Nape模拟《割绳子》里的泡泡
想必大家都玩过《Cut The Rope》(割绳子)这个物理游戏吧。玩家需要通过剪断绳索,让绑着的糖果掉入怪兽嘴里,难度在于必须计划好让糖果掉落的过程中吃到各种星星。更多内容可以点击这里查看,我就不多说了。
今天我们要学习的是游戏中糖果碰到泡泡后向上飘的效果,如下图所示:
实际上,这个效果的原理很简单,大致有3个步骤
- 添加糖果和泡泡的碰撞事件侦听,在事件处理函数中给糖果添加是一个向上的力
- 在泡泡上升的过程中,因为一直受第一步里外力的牵引,所以会一直加速运动,这不符合漂浮的运动轨迹。所以添加一个maxSpeed变量,限制泡泡运动的最大速度,不会咣当掉到天花板上。
Body类里有一个Vec2类型的force属性,表示刚体上综合作用力,但是并不进行物理模拟计算,简单的讲,就是刚体的坐标、角度等属性计算都不收这个force属性的影响,所以理论上设置这个属性对刚体是没有什么影响的,而且每次运行Space.step()之后,force属性都会重置为(0,0)。这一点和Box2D里的ApplyForce()方法不同,要注意。
没关系,Body类还有一个applyImpulse()方法,可以在刚体上添加一个作用力,它的结构如下:
function applyImpulse( impulse : Vec2, pos : Vec2, sleepable : Boolean ):Body
每个参数说明如下:
- impulse:添加到刚体上的冲量,也是一个作用力,但是为N。
- pos:impulse在作用在刚体上的位置,这是一个全局坐标,默认值是调用applyImpulse方法的刚体坐标,即body.position。
- sleepable:表示当刚体处于静止状态时,是否停止应用冲量,默认值是false。
冲量只是一时的,它也是一个作用力,就像我们小时候弹玻璃球一样,弹出去之后玻璃球就不收我们的控制了。所以我们要一直给泡泡添加一个冲量,它才能克服重力,持续的向上运动。
说到克服重力,拉登大叔有要多少两句了。怎么判断impulse是否克服了重力呢?我们知道 力=质量*加速度。刚体的质量可以通过body.mass属性获取,用a表示加速度,那么impulse = body.mass * a。那么重力怎么表示呢?同样的 重力=质量*重力加速度,即 G = body.mass * gravity。要让impulse大于G,只要a大于gravity就可以了。看下面的代码应该更清楚些:
impulse = body.mass * a; G = body.mass * gravity; 若 impulse > G ; 则 body.mass * a > body.mass * gravity; 即 a > gravity;
还有一点要注意的,我们在创建Nape世界时设置的gravity是600,它的单位是 600 px/秒,而impulse里的加速度a的单位是 px/帧,因为示例中的帧频都是60,所以将gravity的单位转换为px/帧应该是 600/60 = 10。
综上所述,要让泡泡可以向上运动,a要大于 10;
明白了原理,代码写起来就简单多了。在碰撞事件处理函数onCollistion中设置向上的作用力,如果你对碰撞检测不熟悉,请参考这篇文章:
private function onCollistion(cb : InteractionCallback) : void { //碰撞后设置force在y轴的分量为负数,让小球向上移动,记得要大于gravity=10哦! force.y= - 40 * paopao.mass; paopao.userData.graphic.alpha = 0.5; }
然后在loop函数中,持续给泡泡施加这个向上的作用力:
override protected function loop(event : Event) : void { super.loop(event); //持续给泡泡施加向上的作用力 paopao.applyImpulse(force,null, true); //限制泡泡上升的速度 if(paopao.velocity.y < maxSpeed){ paopao.velocity.y = maxSpeed; } }
当然,也可以添加一些其他的效果,比如当按下空格键时,清楚作用力,泡泡就会做自由落体运动了:
override protected function keyBoardEventHanlder(event : KeyboardEvent) : void { super.keyBoardEventHanlder(event); if(event.keyCode == Keyboard.SPACE && event.type == KeyboardEvent.KEY_DOWN){ //按下空格键后,清除向上的力 force.y = 0; paopao.userData.graphic.alpha = 1; } }
我做的效果如下,当黑色的小球碰到下面的圆圈时,会改变方向向上移动,按下空格键,小球又重新恢复自由落体运动!
[swfobject]867[/swfobject]
主要的代码上面我都介绍过了,下面就不贴源代码了。大家直接下载源文件看吧!
联系作者
好东西啊、有时间研究一下,等我学好了box2d、
拉登老师,假如我的一个刚体被很多刚体压着。我怎么获取这个刚体受了多少力呢?
我看API有几个类似的,但搞不懂区别。totalImpulse、totalContactsImpulse、totalFluidImpulse
回头我研究一下哈,研究好了,写教程给你解释!谢谢你的关注!
谢谢拉登老师~~~期待教程啊
可是,你要模拟什么效果呢
我想模拟的一个效果是,假如1个刚体被压在最底,那它爆炸后产生一个力把其他刚体炸开。那这个力很难定义。假如被10万个刚体压住,那这个力不能炸开其他刚体;假如只被10个刚体压住,那旁边10个的刚体又会给炸得好远。
我想一个刚体无论是受多少力,爆炸开的力使其他刚体弹得不会太远也不要太近。
Enjoy your blog )
my blog