Chrome自带恐龙小游戏的源码研究(六)

  在上一篇《Chrome自带恐龙小游戏的源码研究(五)》中实现了眨眼睛的恐龙,这一篇主要研究恐龙的跳跃。

恐龙的跳跃

  游戏通过敲击键盘的Spacebar或者Up来实现恐龙的跳跃。先用一张图来表示整个跳跃的过程:

  1. 首先规定向下为正方向,即重力加速度(g)为正,起跳的速度(v)为负,恐龙距离画布上方的距离为yPos
  2. 每一帧动画中,速度都会与重力加速度相加得到新的速度,再用新的速度与yPos相加得到新的yPos,改变恐龙的位置为新的yPos,表现出来为yPos不断减小;
  3. 当恐龙升至最高点,此时速度为0,并且仍具有向下的重力加速度。
  4. 速度仍与重力加速度相加得到新的速度,此时速度方向向下,为正值,表现为yPos逐渐增加;
  5. 落地,并使yPos不超过地面的高度,将速度重置为0,更新状态jumping为false。

  下面通过代码来实现。首先注册键盘事件:

1 document.addEventListener('keydown',onKeyDown);
2 document.addEventListener('keyup',onKeyUp);
1         function onKeyDown(e) {
2             if(keycode.JUMP[e.keyCode]) {
3                 if(!trex.jumping) {
4                     trex.startJump(6);
5                 }
6             }
7         }

按下跳跃键后,执行startJump方法:

 1 startJump: function(speed) {
 2     if (!this.jumping) {
 3         //切换到jump状态
 4         this.update(0, Trex.status.JUMPING);
 5         //设置跳跃速度
 6         this.jumpVelocity = this.config.INIITAL_JUMP_VELOCITY - (speed / 10);
 7         this.jumping = true;
 8         this.reachedMinHeight = false;
 9     }
10 }
View Code

之后在每次GameLoop中更新状态:

1 if (trex.jumping) {
2     ctx.clearRect(0, 0, 600, 150);
3     trex.updateJump(deltaTime);
4 }
View Code
 1 updateJump: function(deltaTime) {
 2     //帧切换速率
 3     var msPerFrame = Trex.animFrames[this.status].msPerFrame;
 4     //经过的帧数
 5     var framesElapsed = deltaTime / msPerFrame;
 6     //更新y轴坐标
 7     this.yPos += Math.round(this.jumpVelocity * framesElapsed);
 8     //由于速度受重力影响,需要对速度进行修正
 9     this.jumpVelocity += this.config.GRAVITY * framesElapsed;
10 
11     //达到最小跳跃高度
12     if (this.yPos < this.minJumpHeight) {
13         this.reachedMinHeight = true;
14     }
15     //达到最大高度后停止跳跃
16     if (this.yPos < this.config.MAX_JUMP_HEIGHT) {
17         this.endJump();
18     }
19     if (this.yPos > this.groundYPos) {
20         this.reset();
21         this.jumpCount++;
22     }
23     this.update(deltaTime);
24 },
25 
26 update: function(deltaTime, opt_status) {
27     this.timer += deltaTime;
28 
29     if (opt_status) {
30         this.status = opt_status;
31         this.currentFrame = 0;
32         //得到对应状态的帧率 e.g. WAITING 1000ms / 3fps = 333ms/fps
33         this.msPerFrame = Trex.animFrames[opt_status].msPerFrame;
34         //对应状态的动画帧 e.g. WAITING [44,0]
35         this.currentAnimFrames = Trex.animFrames[opt_status].frames;
36 
37         if (opt_status === Trex.status.WAITING) {
38             //开始计时
39             this.animStartTime = getTimeStamp();
40             //设置延时
41             this.setBlinkDelay();
42         }
43     }
44 
45     //计时器超过一帧的运行时间,切换到下一帧
46     if (this.timer >= this.msPerFrame) {
47         this.currentFrame = this.currentFrame === this.currentAnimFrames.length - 1 ? 0 : this.currentFrame + 1;
48         this.timer = 0;
49     }
50 
51     //待机状态
52     if (this.status === Trex.status.WAITING) {
53         //执行眨眼动作
54         this.blink(getTimeStamp());
55     } else {
56         this.draw(this.currentAnimFrames[this.currentFrame], 0);
57     }
58 }
View Code

 这样就实现了跳跃的过程。

 

轻跳

  如果持续按住Spacebar或者Up不放,跳跃总是能达到最大高度的,但很多情况下我们只是轻轻敲击一下键盘然后就放手了,这时的游戏表现为恐龙只跳起一个很低的高度,然后开始下落,一般称之为“轻跳”、“小跳”。这看起来是根据按键时长来决定跳跃高度,实现起来有一定的难度,但实际情况却比较简单,只监听键盘的onkeyup事件即可。

function onKeyUp(e) {
    if (keycode.JUMP[e.keyCode]) {
        trex.endJump();
    }
}

当键盘抬起时,执行endJump方法,而endJump方法也十分简单:

endJump: function() {
    if (this.reachedMinHeight && this.jumpVelocity < this.config.DROP_VELOCITY) {
        this.jumpVelocity = this.config.DROP_VELOCITY;
    }
}

首先要判断是否达到了最小跳跃高度,this.reachedMinHeight这个变量非常有用,它避免了游戏角色只跳起数像素然后落地这样的无意义跳跃。此时如果向上的速度仍比较大的话,则强制减小为this.config.DROP_VELOCITY以便能够更快地下落。

下图分别是“大跳”和“小跳”的区别:

          

 

快速落地

  在跳跃过程中如果按下了Down键,恐龙会加速下降。

1 function onKeyDown(e) {
2     //......
3     if(keycode.DUCK[e.keyCode]) {//Down
4         if(trex.jumping) {
5             trex.setSpeedDrop();   //加速下降
6         }
7     }
8 }

松开键位时取消加速:

1 function onKeyUp(e) {
2     //......
3     if (keycode.DUCK[e.keyCode]) {
4         trex.speedDrop = false;
5     }
6 }

在构造函数中添加setSpeedDrop方法:

1 setSpeedDrop: function() {
2     this.speedDrop = true;
3     this.jumpVelocity = 1;    //将速度设置为1,正方向(向下为正方向)
4 }

还需要对updateJump方法做一些更新:

 1 updateJump:function (deltaTime) {
 2     //......
 3     
 4     //更新y轴坐标
 5     if (this.speedDrop) {
 6         //SPEED_DROP_COEFFICIENT为加速倍数,初始设定为3
 7     this.yPos += Math.round(this.jumpVelocity *       this.config.SPEED_DROP_COEFFICIENT * framesElapsed);
 8     } else {
 9     this.yPos += Math.round(this.jumpVelocity * framesElapsed);
10     }  
11 
12 
13     //达到最小跳跃高度
14     //speedDrop也能触发reachedMinHeight
15     if (this.yPos < this.minJumpHeight || this.speedDrop) {
16     this.reachedMinHeight = true;
17     }
18 
19     //达到最大高度后停止跳跃
20     //speedDrop也能触发endJump
21     if (this.yPos < this.config.MAX_JUMP_HEIGHT || this.speedDrop)         {
22     this.endJump();
23     }
24 //......
25 
26 }
View Code

效果如下图所示,在跳跃过程中按住Down,可以发现下落速度比平时快:

闪避

  在地面上按住Down键,恐龙会进入闪避状态。首先还是从keydown方法入手:

1 if (keycode.DUCK[e.keyCode]) {
2     e.preventDefault();
3     if (trex.jumping) {
4         trex.setSpeedDrop();
5     } else if (!trex.jumping && !trex.ducking) {
6         trex.setDuck(true);    //闪避
7     }
8 }

keyup方法取消闪避:

1 function onKeyUp(e) {
2     if (keycode.JUMP[e.keyCode]) {
3         trex.endJump();
4     }
5     if (keycode.DUCK[e.keyCode]) {
6         trex.speedDrop = false;
7         trex.setDuck(false);   //取消闪避
8     }
9 }

setDuck方法:

1 setDuck: function(isDucking) {
2     if (isDucking && this.status !== Trex.status.DUCKING) {
3         this.update(0, Trex.status.DUCKING);
4         this.ducking = true;
5     } else if (this.status === Trex.status.DUCKING) {
6         this.update(0, Trex.status.RUNNING);
7         this.ducking = false;
8     }
9 }

最终效果如下(SpacebarUp跳跃;Down快速下降/闪避):

 

posted @ 2016-12-08 00:12  逐影  阅读(...)  评论(...编辑  收藏