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快速下降/閃避):

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM