PuTsangTo-单撸游戏开发03 碰撞与跳跃瑕疵版
继续上一部分,游戏的定位是横版平台动作类游戏,所以得有跳跃动作,首先想到的就是物理引擎,不过在2D游戏里,仅为了角色的跳跃而引入物理引擎,目前想来有些不至于,仅使用cocos默认带有的碰撞系统也足够了,所以,至少目前色测试场景下,角色的纵向运动就使用简单的算法来模拟。
思路是这样的:
1. 定义一个恒定的纵向速度,角色一直都拥有此速度,并在脚本的update回调中每次都更新角色位置,效果就是角色会匀速下降。
2. 引入碰撞,给角色分组到Actor,给地面或平台分组到Platform(给节点分组后只保留Actor与Platform之间的碰撞,这样就够了)
3. 配置碰撞回调,碰撞事件发生后角色应该停留在平台上不会继续“掉落”。
4. 增加跳跃动作,做法是给一个纵向的跳跃速度值,在更新角色的纵向位置同时考虑前边提到的恒定速度以及这里的跳跃速度,并在开始跳跃后将跳跃速度逐渐减小至0,就能实现角色的从上升到下落过程了。
5. 平衡角色已有几种动作的搭配与冲突(左右跳跃连续跳跃以及跳跃方向更改限制等)
本次需要做的是纯代码工作,来完善前面的move.js。
1. 添加重力
首先是定义恒定的纵向速度,这里就大言不惭的命名为gravity,并在update的每次回调中更改角色的纵向位置模拟掉落:
this.node.y -= this.gravity * dt;
运行效果就是我们的英雄小白会在屏幕上一直掉落,同时可以左右行动,但也只能决定往左边或是右边掉落,下一步就是让它能稳稳的落在地面上。
2. 停留到地面
现在要先给英雄小白加上碰撞体组件:
给地面也加上碰撞体组件:
然后多复制几个地面来进行跳跃测试,搭好的鬼畜场景像这样:
3. 碰撞事件回调
有了碰撞体后,就能在脚本中配置碰撞事件的回调了,这里只操作碰撞发生事件(onCollisionEnter),此外其实还有碰撞停留事件以及离开事件。
代码如下:
1 onCollisionEnter: function (other, self) { 2 var otherTop = other.world.aabb.y + other.world.aabb.height; 3 var selfBottom = self.world.aabb.y; 4 // 自身底部与目标顶部的偏移 5 var out = otherTop - selfBottom; 6 // 偏移 7 if(Math.abs(out) < 10) { 8 this.stay = true; 9 this.direction = this.afterJump; 10 this.afterJump = 0; 11 this.node.y += out; 12 } 13 }
要实现的效果并不是超级玛丽那样,可以从下往上撞砖头,而是像冒险岛那样,可以一层一层向上跳跃,下降时才会落在平台上,所以只需要在碰撞进入时计算自身的底部与目标顶部的偏移,在一定值以下则判定为碰撞完成了,需要将角色准确的降落在目标顶部上(这里要设置一个偏差值而不是准确的0是因为碰撞检测系统本身就会有延迟,但是也需要将位置调整准确,即更新node.y的值)。
4. 增加跳跃动作
现在,横向左、右移动以及“自由落体”三个动作已经有了,要轮到最复杂的一个动作——跳跃了。
跳跃的思路是暂时打破“重力规则”,让角色上升一定位置然后进行自由落体落至平台。
目前的实现即是通过更改jumpSpeed来做到暂时上升,并在update回调中主键恢复jumpSpeed的值,使得重力重新主导纵向运动。
case cc.KEY.alt: if(this.stay){ this.stay = false; this.jumpSpeed = this.jump; this.afterJump = this.direction; } break;
其中的afterJump用来决定本次跳跃完成后一瞬间的动作,这个下一部分来讲。
if(!this.stay) { this.node.y -= (this.gravity - this.jumpSpeed * this.jumpCoefficient) * dt; if(this.jumpSpeed > 0){ this.jumpSpeed --; }else if(this.jumpSpeed < 0){ this.jumpSpeed ++; } }
通过stay变量来判断是否处于跳跃状态,这样能减少update回调的性能(stay为true时说明没有跳跃,不必考虑纵向运动)。
其中的jumpCoefficient是个跳跃系数,用于放大跳跃的数值。
5. 平衡现有动作的搭配与冲突
下一步得考虑动作之间的冲突了,比如横向左右移动肯定不能同时生效,跳跃前的左右移动将决定本次跳跃的方向,而跳跃过程中由于惯性角色不应该能控制跳跃后自身的移动,在《冒险岛》中还有一个下跳动作,可以支持角色下蹲时跳跃则会降落到下方平台,这个目前暂不实现。实际上本文的跳跃以致整个角色控制的逻辑都还存在瑕疵,有待整改。
首先是横向移动的冲突,最终效果应该是以最后按下的按键为准,也就是左移过程中按右移键则改为右移,左移键不再生效。
纵向的起跳很容易,只要保持当前方向即可,但下落后的移动却需要控制得当。比如,跳跃过程中角色不能再改变移动位置,却可以改变自身的朝向以及决定下落到平台后立即开始的移动方向。这里用一个afterJump变量来预定下落后的位置。
if(Math.abs(out) < 10) { this.stay = true; this.direction = this.afterJump; this.afterJump = 0; this.node.y += out; }
下落动作一定也会触发碰撞体的onCollisionEnter回调,只需在此将预定好的afterJump赋值给direction然后重置afterJump即可。
6. 存在的问题
现在的游戏世界还存在很多缺陷,比如:
只要角色不跳跃,就可以在横向任意移动,悬空也可以,比如移动到这个位置:
还有就是cocos的键盘事件的一个机制,或许也是所有键盘输入的机制,也就是按下一个按键不放,按键回调会立即触发一次,然后等待半秒还是更多才会一直保持快速的触发按键回调,这个在输入框打字时感觉是一样的,这就会导致某些时候跳跃结束角色刚落回平台时会迟疑这么个半秒才进行其预定的移动动作(如果落霞后不松开原方向键的话)。
总结是角色的动作控制要考虑完美对于笔者这个不务正业的web从业人员来说还是有些路要走的,不过讲理这个移动控制是个一劳永逸的过程,且对于我们这个横版平台动作游戏来说,引入物理引擎这么庞大的东西或许有其必要或许小题大做,毕竟需要考虑跳跃的就只有角色自己,顶多来一部分特殊怪物拥有角色的移动控制,这也是通用的。再加把劲吧。