2.公主精灵的控制
在第2阶段,将创建一个公主角色,支持玩家使用键盘上的左、右方向键控制公主角色的左、右移动。在“sdgz”项目目中 ,把 version1.jl复制一份并命名为version2.jl,在第1个版本的基础上编写第2 个版本的代码,具体步骤如下:
(1) 用图像Actor创建一个公主角色,将其定位在窗口底部居中位置。
princess = Actor(princess_img)
princess.pos=(400, 305)
(2) 在窗口的draw()方法中,调用draw()方法将公主精灵的图绘制到窗口中。在游戏处于进行状态才会显示公主精灵,即在 game_state 等于 1 时才绘制公主角色的外观。
elseif game_state == 1 … draw(princess)
提示:“…”号表示省略掉的部分代码,下同。
(3) 控制公主角色左、右移动。这里没有使用键盘事件,而是通过检测键盘按键状态来判断是否按下左 、右方向键。因此需要在窗口的事件循环update()方法中检测左、右方向键的按键状态,并控制公主角色左、右移动。在update()方法中添加如下代码:
function update(g::Game,dt)
princess_control(g,dt)
end
princess_control是公主角色控制函数,update事件中每帧切换会调用这个函数。princess_control()函数的代码如下:
#控制公主左右移动 function princess_control(g::Game,dt) global game_state if game_state != 1 return end if g.keyboard.LEFT princess.x -= 400 * dt if princess.left < 0 princess.left = -princess.left end elseif g.keyboard.RIGHT princess.x += 400 * dt if princess.right > WIDTH princess.right += -(2 * (princess.right - WIDTH)) end end end
对上面代码的说明如下。
①在游戏处于进行状态时才能控制公主精灵移动,即如果 game_state 不等于1,就退出这个函数。
②函数 princess_control ()被调用时,自上次被调用以来经过的时间(单位= S)就会被传递给参数 dt。假设公主精灵的移动速度为400 像素/S,那么它在 princess_control () 函数披调用时的移动速度则为 400*dt。在向左移动时,princess.x 的值将减去400*dt;在向右移动时 ,princess.x 的值将增加 400*dt。
③公主角色在窗口中移动应该显示完整的外形。因此princess.left最小值为0,princess.right最大值是800 。
至此,第 2 个版本的程序编写完成. 运行程序,就可以用键盘上的左、右方向键控制公主角色左右移动了。
3.下落物体角色的控制
在第3个阶段,将实现从天空中随机落下雪花、礼物或剪刀。从面向对象的角度看,雪花、礼物和剪刀都可以归结为一类物体,即“下落物体类”,原书的做法是从Pyglet的Sprite 类中派生一个下落物体类 FallingObject,并运用该类的实例实现雪花、礼物或剪刀的互相切换。
但是Julia不是传统意义上的面向对象语言,Julia里没有class,没有类的继承(inheritance),勉强与class能对应上的是struct,且不能派生和继承,除构造函数外,struct内不能定义其它函数。
1) 创建FallingObject对象
原书中,作者定义了一个名为 FallingObject的类,继承自Sprite 类,在类中添加一个属性 type 和一个用于切换雪花、礼物和剪刀的 change()方法。转换到Julia,可以写成如下结构的代码:
1 mutable struct FallingObject 2 act::Actor 3 type::Int 4 5 function FallingObject() 6 act=Actor(snowflake_img) 7 type=1 8 new(obj,type) 9 end 10 end 11 12 function change(fo::FallingObject) 13 #随机切换掉落物体的造型 14 n = rand(1:10) 15 if 1 <= n <= 5 16 fo.type = 1 17 fo.act.image = snowflake_img 18 elseif 6 <= n <= 8 19 fo.type = 2 20 fo.act.image = gift_img 21 else 22 fo.type = 3 23 fo.act.image = clipper_img 24 end 25 #将物体定位到窗口上方随机位置 26 x=rand(100:700) 27 fo.act.pos =x , -100 28 end
笔者原打算按此思路实现下落物体的控制,但是通过研究GameZero的源码,发现源码作者对Actor增加了赋予其自定义属性的能力。由于下落物体本质上是一个Actor,所以我们可以直接这样定义:
falling_obj =Actor(snowflake_img;pos=(rand(100:700),-100),type=1)
上面代码中参数snowflake_img是雪花的图片,pos是位置,其x轴坐标为100-700间的随机值,第三个参数type就是自定属性。
这样一来,代码将简洁很多。至于Julia的面向对象编程,笔者将新开贴专题论述。
2) 控制 FallingObject对象
将version2.jl录复制一份并命名为version3.jl,在第 2 个版本的基础上编写第 3 个版本的代码。
(1) 在窗口的draw()方法中,绘制出 falling_0bj 对象的外观。与公主精灵一样 ,都是在游戏处于进行状态时才会显示下落物体.
elseif game_state == 1 … draw(falling_obj)
(2) 在窗口的 on_key_down()方法中添加切换下落物体造型的代码。当在游戏重新开始时,就调用 Change()方法切换下落物体的造型。
function on_key_down(g, k) global game_state #println(k) if k ==Keys.RETURN #13 if game_state != 1 game_state = 1 change(falling_obj) end end end
另外,事先将Change()方法稍加修改,添加到version3.jl中:
1 function change(fo::Actor) 2 #随机切换掉落物体的造型 3 n = rand(1:10) 4 if 1 <= n <= 5 5 fo.type = 1 6 fo.image = snowflake_img 7 elseif 6 <= n <= 8 8 fo.type = 2 9 fo.image = gift_img 10 else 11 fo.type = 3 12 fo.image = clipper_img 13 end 14 #将物体定位到窗口上方随机位置 15 x=rand(100:700) 16 fo.pos =x , -100 17 end
上面的代码使用随机数生成掉落物体的造型 ,并将其随机定位在窗口上方。随机生成下落物体的算法在本节的编程思路中已经作过介绍。
(1) 控制下落物体向下移动 。在update()方法中添加如下代码:
function update(g::Game,dt) falling_control(dt) end
函数falling_control()的代码如下:
1 function falling_control(dt) 2 #礼物精灵的控制''' 3 global game_state 4 if game_state != 1 5 return 6 end 7 8 #控制礼物的落下速度和旋转速度 9 falling_obj.angle += 60 * dt 10 falling_obj.y += 200 * dt 11 if falling_obj.y >HEIGHT 12 #println("ddd") 13 change(falling_obj) 14 end 15 end
对上面代码的说明如下。
①在游戏处于进行状态时才能控制下落物体的移动,即如果 game_state 不等于 l,就退出这个函数。
②旋转速度和向下移动速度跟时间有关。下落物体在降落过程中是旋转的,假设每秒旋转 60。,就使用 60 *dt 算出 faning_0bj.angle每次的增加量;假设每秒向下移动200 像素,就使用 200 *dt 算出 fa]ling_Obj.y 每次减少的距离。
③当下落物体移动到窗口底部外面的区域时,就将其重新放到窗口的顶部,并随机切换新的造型,调用 change()方法来实现。
至此,第 3 个版本的程序编写完成。运行程序,就可以看到在游戏时会从天空中随机掉下雪花、礼物或者剪刀。