punya代码分析和学习笔记
punya(DXプニャリン競争)是用DxRuby实现的一个小游戏。
see also:?
http://www20.atpages.jp/papihime/
http://www20.atpages.jp/papihime/ruby/index.htm
下面是我的学习笔记。
?
一、场景模块(DXRuby的场景框架):
?
1. 类
(1) Scene::Exit
退出场景类,空类,表示场景为空(见Scene.main_loop)
(2) Scene::Base
抽象类,Scene.main_loop的第一参数
?
2. 方法
(1) Scene::Base#initialize
构造函数。清空下一场景;帧数设为0;调用init。
(2) Scene::Base#__update
帧数加一,调用update。
(3) Scene::Base#init
抽象方法。初始化事件。
(4) Scene::Base#quit
抽象方法。退出场景并且将要进入下一个场景时的事件。
(5) Scene::Base#update
抽象方法。逻辑更新或场景切换事件。
(6) Scene::Base#render
抽象方法。界面渲染事件,发生在update后。
(7) Scene.main_loop(scene_class, fps = 60, step = 1)
静态方法。
* scene_class是Scene的子类,这里的作用相当于模板参数(实际是传入类构造器);
* fps是窗口最初的指定帧率。
* step是默认fps倍数(在运行期间可按PGUP和PGDN键调节),表示在一个循环内执行多少次渲染和逻辑更新。当它放大时窗口的fps随之缩小,使每秒执行的次数保持相同。
作用:
1) 构造出最开始的scene
2) 按PGUP和PGDN键调节更新内循环数。
3) 调用Scene.Base的回调方法
4) 判断scene.next_scene,如果非空的话构造新的scene读写。
5) 按ESCAPE键退出窗口循环
3. 属性:
(1) Scene::Base#next_scene
可读写。Scene.Base类的子类的类构造器。等于Scene.Exit的话退出。
(2) Scene::Base#frame_counter
只读。从最开始到目前为止的update次数,在update前加一。用于实现场景的透明度和闪烁动画。
4. 出现过的DxRuby API
* Window.loop
窗口循环
* Window.fps
设置窗口帧率
* Input.keyPush?
键盘当前是否按下状态?
?
二、dx_punya模块(游戏实现)
1. 类
(1) LogoStart
logo,Scene::Base的子类
(2) TitleScene
标题,Scene::Base的子类
(3) MenuScene
菜单,Scene::Base的子类
(4) CharactersScene
帮助与说明,Scene::Base的子类
(5) Punya
每个角色实例的设置
(6) PunyaRaceScene
游戏主界面。
?
2. 主入口
Scene.main_loop LogoStart
从LogoStart场景开始进入Scene框架主循环
?
3. 各个类的方法和字段
* LogoStart#FADE_IN_TIME:动画总时间
* LogoStart#init
* LogoStart#go_next_scene
* LogoStart#update
* LogoStart#render
1) 把frame_counter作为定时器参照修改images/logo2.png的显示透明度(渐现后渐隐)
2) 到达FADE_IN_TIME时间后转至下一个场景TitleScene
* TitleScene#init
* TitleScene#go_next_scene
* TitleScene#update
* TitleScene#render
1) 把frame_counter作为定时器参照修改背景图images/bg_title.png的显示透明度(渐现)
2) 提示文字images/press_any_key.png闪烁显示(某些时候不显示)
* MenuScene#init
* MenuScene#go_next_scene
* MenuScene#update
* MenuScene#hit_img?(img):鼠标当前位置是否落在某个菜单图片上。
* MenuScene#render
1) 背景由30个images/menu_tile.png砖块数组组成
2) 标题文字为images/menu_title.png
3) 菜单图片(选择)为images/menu#{i}.png,共三个
4) 菜单图片(未选择)为images/menu#{i}_back.png,共三个
5) 菜单(选择,未选择)信息数组有三个条目:
选择数组(img[])条目为[x坐标, y坐标, 菜单图片,是否当前选择]
未选择数组(img_back[])条目为[x坐标, y坐标, 菜单图片]
6) 按空格或鼠标左键时跳转场景。
根据@cursol_id的值选择跳转到:
PunyaRaceScene,CharactersScene,TitleScene
7) 根据鼠标当前所在位置判断选择哪个菜单
是否落在菜单数组条目,
根据img[0],img[1],image[2].width,image[2].height来判断。
8) 分别绘画
@bg_tiles:循环平铺,根据frame_counter进行偏移(不超过e.width)
形成倾斜方向的运动动画。
@back_menus:循环3次绘画。
@menus:如果@menus[i][3]为1时才绘画。
@title:绘画标题。
* CharactersScene#init
* CharactersScene#go_next_scene
* CharactersScene#update
* CharactersScene#render
1) 渐现背景图images/bg_characters.png(alpha随frame_counter而增加)
2) 空格或鼠标左键跳转到下一个场景MenuScene
* Punya#initialize(idx)
* Punya#update(frame_counter):由PunyaRaceScene场景类的update方法调用
* Punya#goal?:此精灵角色是否到达终点
* Punya#render:由PunyaRaceScene场景类的render方法调用
1) 构造函数传入角色编号idx
加载images/punya#{idx}.png的6张子图片(3*2)(动画精灵图片)。
根据idx算出@x, @y
@move为0,指示@image数组的下标(动画精灵的当前帧数)
2) 根据@x和@y绘画图片@image[@move]
3) 根据frame_counter,在合适的时候增加@i。
4) 根据@i切换精灵的帧图片:
到达终点:@move修改为3->4->5->4->...
未到达终点:@move修改为0->1->2->0->...
5) 根据@i移动精灵
到达终点:不动
未到达终点:@x += rand(4)
6) 精灵的@x超过560时认为到达终点
* PunyaRaceScene#init
* PunyaRaceScene#go_next_scene
* PunyaRaceScene#update
* PunyaRaceScene#render
1) 绘画背景图images/bg_race.png
2) 创建6个Punya精灵
3) 调用精灵的update和render方法
4) 空格或左键跳转到下一个场景MenuScene
?
4. 出现过的DxRuby API
* Image.load
加载图片
* Input.keyPush?
判断键盘是否按下
* Input.mousePush?
判断鼠标是否按下
* Window.drawAlpha
绘画图片到指定坐标,改变其透明度实现渐隐和渐现。
* Window.draw
绘画图片到指定坐标,可以实现闪烁(显示或不显示)
* Input.mousePosX
鼠标当前所在的X坐标
* Input.mousePosY
鼠标当前所在的Y坐标
* Image.loadToArray
加载一张图片并分割成m * n个对象后返回
?
三、总结和值得借鉴的内容
1. MenuScene和Punya的实现比较复杂,需要重点分析。
2. 学习如何用滴答数实现透明度动画、闪烁动画、砖块平移动画以及精灵动画。
3. 学习如何实现菜单按钮(选择和未选择)。