Flash游戏开发(11) - 跳跃

跳跃

开始之前,我们先把视角从俯视改成侧视,这样英雄才可以跳跃。就像下面的这个,按左右键英雄移动,按空格键跳跃:


跳跃基础

跳跃意味着上升,上升在Flash中意味着_y属性的减少。所以我们需要计算这样的式子:

新的坐标=现在的坐标-上升速度

如果只计算一次,坐标只改变一次,英雄很快就停止了。因此我们需要持续不断的计算新坐标。而且,我们还应该改变速度的值,否则英雄就在空中下不来了。
下落和上升一样,只不过速度值前面加个负号而已。

为了改变速度,我们定义一个新的变量:重力加速度。重力把英雄拉向地面,学过物理吧?重力加速度并不直接改变坐标,他改变的是速度:

速度=速度+加速度

这就是Flash中的表示方法,=可不是表示左右相等,是把右边计算的结果赋给”速度”变量。这个式子也是需要不停计算的,以便保持连贯的运动。你可以改变重力的值,较小的值意味着在空中的时间更长,较大的值很快就会把英雄“拉”下来。
从另外的角度看,重力也意味着跳跃能力,我们可以给不同的对象赋以不同的“重力”属性,这样他们跳得就不至于一样高。

让我们来看一个例子。比如刚开始的速度是-10,重力是2。
那么开始的时候,英雄将会上移10象素,然后速度降低到8;
接着英雄上移8象素,然后速度又变成了6……
如此往复,直到速度等于0的时候,英雄不再上升了。
接着速度成了2,英雄开始下降2象素;
下一步又下降4象素、6象素、8象素……直到落地。

落地后,跳跃自然也应该结束了。但是要是英雄在跳跃过程中顶到障碍物怎么办?
很简单,我们把速度强行改成0就行了,然后英雄就会落下来。

【注意】在区块游戏开发中,不要让速度值超过方块的高度。过大的速度会导致碰撞检测跳过某个方块,导致英雄“穿过”障碍物。或许有些魔法师可以穿过障碍物,但是在普通的区块游戏中,这是个bug。

跳跃并不影响水平方向的运动,在空中我们还可以用方向键控制英雄的水平运动。我们需要做的是,在左移或右移后,判断英雄脚下是不是还有东西,如果是空的,跳跃就开始了(这时候初始速度是0,英雄直接下落)。

会跳的英雄

我们给英雄再添加一些属性:

char = {xtile:2, ytile:1, speed:4, jumpstart:-18, gravity:2, jump:false};

speed属性是水平移动速度,jumpstart是跳跃的初始速度,
granvity是重力值,jump属性用来表示英雄是不是在跳跃过程中。

下面加一句as到buildMap函数中:

char.y = ((char.ytile 1) * game.tileW) - char.height;

因为我们的视图是侧视的,英雄刚开始的位置可能是“漂”在空中的,我们应该让他站到地面上来。

changeMap函数和getMyCorners函数不需要任何变动。

腾空的感觉

我们先来改造detectKey函数,删除上下键检测,添加空格键检测:

function detectKeys()
{
 var ob = _root.char;
 var keyPressed = false;
 if (Key.isDown(Key.SPACE) and !ob.jump)
 {
  ob.jump = true;
  ob.jumpspeed = ob.jumpstart;
 }
 if (Key.isDown(Key.RIGHT))
 {
  keyPressed = _root.moveChar(ob, 1, 0);
 }
 else if (Key.isDown(Key.LEFT))
 {
  keyPressed = _root.moveChar(ob, -1, 0);
 }
 if (ob.jump)
 {
  keyPressed = _root.jump(ob);
 }
 if (!keyPressed)
 {
  ob.clip.char.gotoAndStop(1);
 }
 else
 {
  ob.clip.char.play();
 }
}

注意看我们怎么避免跳跃过程中空格键触发新的跳跃(听起来很拗口,哈哈),实际上就是当处于跳跃中时,忽略空格键。如果按了空格键,而且英雄没有处于跳跃过程,那就开始跳吧,把jump属性改成true,把jumpspeed改成speedstart属性值。

看一下,在左右方向键的检测语句后面,我们添加了几句。

if (ob.jump)
 {
  keyPressed = _root.jump(ob);
 }

如果jump属性为true(正在跳),那么执行jump函数。只要jump属性为true,jump函数就会不断地被执行,直到jump属性变成了false。这个函数可以在空格键松开后仍然执行,只要jump属性为true。

Jump函数所做的只是改变jumpspeed的值,给他加上重力值。同时做一些处理防止速度值过大,让jumpspeed不会超过方块高度。最后调用moveChar函数移动角色。

function jump (ob)
{
 ob.jumpspeed = ob.jumpspeed ob.gravity;
 if (ob.jumpspeed > game.tileH)
 {
  ob.jumpspeed = game.tileH;
 }
 if (ob.jumpspeed < 0)
 {
  moveChar(ob, 0, -1, -1);
 }
 else if (ob.jumpspeed > 0)
 {
  moveChar(ob, 0, 1, 1);
 }
 return (true);
}

我们还需要改一下moveChar函数,因为加入了跳跃过程,跳跃时的速度jumpspeed和水平移动的速度speed是不同的:

function moveChar(ob, dirx, diry, jump)
{
 if (Math.abs(jump) == 1)
 {
  speed = ob.jumpspeed * jump;
 }
 else
 {
  speed = ob.speed;
 }
 ...

jump参数是从上面的jump函数中传递过来的,它的取值不是1就是-1。如果jump的绝对值(Math.abs)是1,移动的距离就是jumpspeed*jump,否则就是speed属性。

如果这一步移动结束后,角色的顶到了障碍物,就要把jumpspeed值改成0:

ob.y = ob.ytile * game.tileH ob.height;
ob.jumpspeed = 0;

如果这一步移动结束后,角色站到了地面上,跳跃就该结束了:

ob.y = (ob.ytile 1) * game.tileH - ob.height;
ob.jump = false;

在左右移动后,我们还要看看角色是不是还站在平台上,如果不是,就应该落下来:

ob.x = speed * dirx;
fall (ob);

所以,我们还需要一个fall函数:

function fall (ob)
{
 if (!ob.jump)
 {
  getMyCorners (ob.x, ob.y 1, ob);
  if (ob.downleft and ob.downright)
  {
   ob.jumpspeed = 0;
   ob.jump = true;
  }
 }
}

如果角色已经处于跳跃过程中,这个函数就没有必要运行了,它是用来检测“踩空”的情况的,只有当角色站着(!ob.jump)的时候才有用。这时候我们调用getMycorners函数,如果角色下方的两个方块都是可通行的,那就应该落下来了,起始速度是0,然后把jump属性改成true。

Google