一、创作缘由
在很早以前,我曾经使用微软的C#+Silverlight2+Farseer物理引擎编写过一个投篮小游戏,而如今正使用Scratch开发游戏教学软件,那么能否也使用少儿编程工具重新实现一款投篮小游戏呢?因为Scratch本身并没有提供物理引擎,所以有了两个想法。想法之一是使用Scratch现有功能,借助于物理规律与有关数学计算使用模拟方式并主要通过经验数据实现游戏;想法之二是,能否寻找一个扩展物理引擎来助力Scratch物理类游戏的开发?
其中,第一个想法已经实现,算是第一个版本吧(本文后面简称“前一个版本”或者“第一个版本”),就是我的图文文章Scratch3.6开发小游戏《梦幻灌篮高手》。
在为了实现第二种想法,在网络上展开了广泛搜索,我得到的最终结论是:国外(包括MIT官方)目前没有实现2D或3D扩展物理引擎支持Scratch。但是,在分析几个国内少儿编程老大(编程猫、小码王、核桃编程、西瓜创客、慧编程)所用工具后,发现只有编程猫提供了内置2D物理引擎支持。但是,先不必高兴,在使用当前最新的编程猫Kitten版本3.4.24的物理引擎过程中我也发现很多问题,细节自不必细说,只有一个结论:它只是一个非常初级的2D引擎,用于实现2D游戏中的一些简单的物理规律问题不大,但是很难用于复杂的物理规律游戏开发,而且非常缺乏技术开发文档,更不用说系统性的实例了。
算是题外话吧。本人曾经在开源与非开源的工具集中走了一小圈,一个刚性结论是:开发帮助文档的及时性、友好性严重影响一款软件的用户体验。为此,建议这些看似“不重要的”文档由开发人员自己并联合公司体验员共同编写。另外,热情并及时地广开门路吸收广大用户的意见与建议(甚至结合重大奖励)也是极端重要的举措。只有把产品内功做扎实了,再加上科学的营销与管理,公司发展才能前途无量啊!
本文适合于具有初中二年级及以上物理、数学基础的朋友学习,因为其中涉及到物理力学中的许多概念及有关数学计算。
二、编程猫Kitten物理引擎简介
2D物理游戏(更歪提3D产品了)一直以来代表游戏的一个重要类别,不容忽视。既然如此,很有必要探讨一下编程猫Kitten源码编辑器(当前最新的正式发行版本是3.4.24,据我不完全试验,在最新测试版本的4.0中物理引擎未见大的改进)中内置的物理引擎模块。
经网络搜索,有关这个物理引擎的帮助资料仅见于随同软件的“源码图鉴”(非常简单的目录式帮助文档)中。现在,结合我一天多来的试验摸索,总结一下这个引擎模块的使用思路及注意事项。
在Kitten3.4.24版本中物理类积木共计引入了17块(下图)。注意:物理类积木无法应用于背景角色,仅能在普通角色中使用。
编程猫Kitten工具的四大类17块物理积木(一)物体分类
业界知名的BOX2D刚体物理引擎(针对不同语言,有好多对应版本)中把物理世界中的物体分为三类:
静态(static)物体:质量为0(好似有无穷大的质量),速度为0。在Box2D世界中,静态物体不与其他静态物体和运动学(kinematic)物体相互碰撞。动态(dinamic)物体:完全模拟运动物体,通常是受力的作用而运动的。动态物体可以与其他任何类型(在此列举的共计三种类型)的物体相互碰撞。动态物体的质量总是有限大的(非零),有可碰撞的几何形状与密度。运动学(kinematic)物体:质量为0(好似有无穷大的质量),速度可以设置为一定大小。在Box2D世界中,运动学物体也不与其他静态物体和运动学(kinematic)物体相互碰撞。在编程猫Kitten3.4.24版本中物理类积木中,根据我的试验,可以把场景中的角色当作是包装了一层特殊外衣的物理物体,而且也分为三类:
参与碰撞的运动物体:类似于BOX2D引擎中的动态(dinamic)物体,物理规律也相似。参与碰撞的静态物体:据我的粗略测试,包含类似于上面BOX2D引擎中的静态(static)物体和运动学(kinematic)物体两种类型。不参与碰撞的物体:好像Kitten的物理世界中不存在它们一样。要达到这样的效果,需要开启物理引擎支持,但是还要使用积木。编程猫官方“源码图鉴”中提到的,就是指上面的。当然,起始状态也有可能是静止的,即速度为0。试验确定:在开启物理引擎之前,任何都没用——也就是说,成为上面的!但是,一旦开启物理引擎支持,这个物体变成变成了运动类型的物体,即拥有了重力、质量、摩擦力等物理属性,如果受到一定程度的外力作用,就可能发生相应形式的运动。
因此,在用Kitten编写的物理游戏中,如果想让某些角色保持静止不动,但参与碰撞及摩擦等运动学活动,不需要对这类精灵施加任何物理积木作用!
另外,由上面的四大类共17块积木名称可见,Kitten物理引擎功能还有待扩展与提升,目前远不如Box2D那样能够支持复杂的物理动力学模拟。
(二)使用Kitten物理引擎的一些基本结论与约定
关闭了物理引擎(即先后施加积木和)后,角色会瞬间失去质量,不受任何力的作用,不再出现自由落体等物理效果。此时,完全等价于没有开启物理引擎功能一样。若角色不参与物理碰撞(即先后施加积木和),则其他角色碰到该角色时候不会产生物理碰撞效果。此时,对该角色皆不产生作用,即不受引力影响,无质量,不反弹等等。也即是相当于该角色被设置为“隐藏”状态——处于隐藏状态的角色是不参与物理碰撞的。引力加速度(相当Box2D中的重力加速度)取值范围:-~,大小默认值为10。引力加速度越大,自由落体的速度越快。方向默认值为-90(即垂直向下——与Scratch中方向不一样!)。在Kitten2D物理世界中,密度=质量÷面积。其中,密度大小取值范围:0~,默认值为1。质量取值范围:0~,默认为10。力主要用于改变物体瞬间的加速度,当然力产生的最终效果还和物体的质量相关。由物理知识可知,设置物体的运动速度与设置物体受力大小,虽然效果很相似,但是他们的物理意义是不同的。三、快照快览
如以前的文章一样,先让我们来看一下本文版本实现的投篮小游戏短视频:
01:32下面仅给出一个典型的静态快照:
金蟾抛球后等待的瞬间截图这里给出的是金蟾抛球后等待投篮结果(是不是投中?)的瞬间截图,其中左上角的计数器使用的是Kitten内置的奖杯计数器方式——每进一球加一分。
四、设计方案
这里,我们主要介绍一下较之于前一个版本在角色方面的改进设计。
由上面截图可知,在本版本的投篮游戏中,除了舞台外,也共有五个角色:
小金蟾:同前一版本(根据左右键盘按键方向,相应地修改小金蟾的水平x坐标值,并根据音效开关确定是否播放小金蟾的叫声,用向上按键控制起跳),但设计为类型,为的是模仿人的自然弹跳投球而后受重力影响落地效果。篮球:同前一版本,但设计为类型;篮球从小金蟾额头前上方抛出。篮球抛出后会在舞台矩形范围内的另外专门指定的有效范围内根据物理规律作抛物线运动并与屏幕边缘(静态物体)发生物理弹性碰撞作用。篮筐:同前一版本,还是在特定范围内随机移动;但设计为类型。移动时,位置一般会高于小金蟾头顶——但是受物理碰撞作用,也有可能会出现比小金蟾低甚至是被小金蟾与边缘夹住的情况(本文中我们没有刻意解决这些问题)。音效开关按钮:同前一版本。地面:为了模拟篮球落到地上后的物理效果,被设计为类型,即不施加任何物理引擎效果(不使用任何物理类积木编程)。篮球落到地上后会发生物理弹性作用。显然,在本版本中,没有了前一版本中引入的虚拟盒角色,因为篮球和篮筐都被设计成类型;所以,利用它们的物理规律再加适当的逻辑判断即可检测篮筐与抛出的篮球碰撞结果(是否投中)。
无论是Scratch编程还是Kitten编程,角色中心点这个概念在许多积木中都会使用到,例如、、等积木。其中,地面角色的中心点设计为上边缘中点位置;由于篮球从小金蟾额头前上方抛出,所以,小金蟾角色的中心点大致位置也需要在额头前上方(参考下面的设计时快照)。
小金蟾中心点定在额头前上方有关Kitten物理引擎,非常值得称赞的一点是:它能够自动识别角色的不同几何形状,特别是对于最流行的png格式的角色图形设计中的透明度有很好支持。例如,上面的小金蟾,其帽子与后背间有一处三角形区域,这个地方是透明的。细心的朋友可能会注意到视频中篮球如果恰巧由于物理运动落在小金蟾后背处,则很可能篮球就被卡在这个三角区,游戏中这种情况只好让小金蟾往前走几步,使球落到地上,从而使游戏继续正常往下进行。这一优点利用的另外一个例子是应用于不规则精灵碰撞体验中,例如弯弯的香蕉被刀子切割时碰撞检测等。
五、角色关键部分编程
由于有了上一版本,所以我们在此仅介绍最为关键的物理编程代码部分。
(一)小金蟾角色编程
小金蟾角色代码一、二小金蟾角色代码三在上面最短小的第一部分代码中,把小金蟾角色最初造型设计为下蹲时造型,然后开启物理引擎支持。这是使小金蟾角色成为Kitten物理引擎世界中一个物理角色的第一步。在第二部分代码中,在玩家按下键盘上的向上箭头键时为了使小金蟾产生向上跃起的效果并符合物理规律,这里使用了反复试验出的数据设置角色的受力大小及方向(90度为垂直向上,与Scratch不同)、重力加速度大小及方向以及初始跃起的速度与方向。因为Kitten帮助信息十分有限,所以这里的数据需要自己不断修改试验,并结合物理规律调整。最后,切换造型,呈现小金蟾先下蹲后跃起的姿态。
最后,注意一下上面第三部分代码,这与以前的版本中代码完全一致,用于控制角色的左右移动。
(二)篮球角色编程
篮球角色代码一二篮球角色代码二在我们的游戏设计中,游戏开始时,篮球是隐藏的,在代码一中进行必要的物理参数初始化设置,大致遵循:篮球质量比较小,篮球在空中时一般是滚动的,而且有参与运动的物理边缘,其密度、摩擦系数及反弹系数等根据前面Kitten物理引擎的基本介绍进行设置。一般来说,这些参数不好一下设置到位,需要重复多次进行测试调整才最终确定。
在代码二中,即当玩家按下键盘上的空格键时,完成两个任务:发球;发球后的是否投中判断。
发球之初有一个力度与速度大小及方向的确定问题。其中,变量“命中”等价于以前版本的游戏中的私有变量_shot,用于辅助判断篮球是否投中。
接下来,注意“移动球员”这块积木——球员小金蟾的中心点位置确定在此显得非常重要!
再往下,为了使情况尽可能遵循现实物理规律又简化编程,使用了一个循环三次的条件循环。注意其中条件积木中的条件表达,与前一个版本的编程不同,这里的办法是必须满足4个条件才确定投中:
(1)变量“命中”为0,即“未投”,而不是“未投中”;
(2)篮球的纵坐标要高于篮筐的纵坐标,使不至于出现篮球在篮筐底部而出现误判断为投中的情形;
(3)篮球大致在篮筐内部(篮筐宽度大约为97左右)——使用篮球中心点横坐标与篮筐中心点横坐标差的绝对值确定;
(4)篮球碰到篮筐。
当条件满足时,加分,变量“命中”设置为1,播放投中的消息,并退出循环(模块是Kitten中特有的)。
最后,无论是否投中,篮球都要隐藏起来。问题:是不是立即隐藏呢?请继续往下阅读。
(三)地面角色编程
地面角色编程乍看起来,这个有点怪的地面角色作用有点“怪”,其实并不怪。我们的设计方案是,当篮球投中时,让它立即消失(隐藏起来);当不中时,让其按照物理规律,掉到地上,并发生可能的反弹效果,当接触地面三次后,隐藏起来,以便于下一次再发球。
其他几个角色,篮筐角色代码基本同以前版本,只是移动的X和Y区间值由于屏幕尺寸不同(Kitty支持横版16:9、横版4:3和竖屏三种类型)有所修改,在此省略介绍;背景角色代码同以前版本,省略介绍;音效开关按钮角色代码同以前版本,在此也省略介绍。
六、小结
本文中,我们使用编程猫Kitten编辑器中的物理引擎开发了小游戏《梦幻灌篮高手》的另一个版本。当然,与上一个Scratch版本相比,各有利弊——不敢说,使用代码少了多少,至少是更真实了一些。
另一方面,在引入Kitten物理引擎简化了物理碰撞及相应判断的同时,也带来另外一些新问题,例如小金蟾角色设置为类型后与篮球发生物理碰撞的复杂性,对于篮筐设置为类型后也存在类似问题。球掉落到地上后要反弹,反弹多少次为最佳,本次投球后在命中与不中时如何准备下一次的投篮,等等。总之,要想使开发出的游戏尽可能逼真,是相当费力和费时的事情——既需要掌握扎实的基础数学与物理知识,还需要结合游戏的趣味性与可玩性的基于经验性数据的再修正。
最后,本文仅对编程猫Kitten编辑器中的物理引擎的应用作了初步试验性探索;若有不当处,还欢迎朋友们多多批评指正!