WEEK 06 · JAVASCRIPT
06|讀懂遊戲流程
看懂一小段,動手改一點,再回到遊戲找用途。
畫布座標:往右 x 增加,往下 y 增加
原遊戲畫布寬 360、高 640,左上角是 (0, 0)。我方子彈 vy = -520,表示往上移動;敵方子彈 vy = 230,表示往下移動。
canvasX() 用畫布在頁面上的位置及縮放比例,把滑鼠座標換成畫布座標。觸控的 e.touches[0] 是第一個接觸點;passive: false 允許處理函式取消預設捲動。
const r = canvas.getBoundingClientRect();
return (clientX - r.left) * (W / r.width);時間差 dt:速度乘以時間才是位移
performance.now() 提供毫秒時間。除以 1000 轉成秒,乘上每秒速度得到移動距離。若速度 320、dt 是 0.016 秒,就移動約 5.12 個畫布單位。
原遊戲將 dt 上限設為 0.05 秒,避免停頓後突然跳很遠;這會捨棄超過上限的時間,不是補跑所有落後時間。
const dt = Math.min((now - last) / 1000, 0.05);
last = now;
cannon.x += cannon.speed * dt;基本繪圖指令
| 指令 | 用途 |
|---|---|
| clearRect() | 清除上一張畫面 |
| fillStyle / strokeStyle | 設定填色/線條顏色 |
| fillRect() / strokeRect() | 畫實心/外框矩形 |
| beginPath()、moveTo()、lineTo()、closePath() | 開始路徑、移到起點、畫線、封閉路徑 |
| arc() / ellipse() | 畫圓弧/橢圓路徑 |
| fill() / stroke() | 把路徑填色/描邊 |
| save() / restore() / translate() | 保存/還原繪圖狀態,以及移動座標原點 |
| globalAlpha / fillText() | 透明度/畫文字 |
Math.PI × 2 是一整圈的弧度。Math.sin、Math.cos 在爆炸特效中把方向角度轉成水平、垂直速度,先理解用途即可。
主迴圈:資料與畫面分開
init 先建立資料。requestAnimationFrame 登記下一次畫面更新前要呼叫的函式;瀏覽器會傳入時間 now。每次 loop 都先 update 再 draw,最後再登記下一次,不保證固定每秒 60 次。
function loop(now) {
const dt = Math.min((now - last) / 1000, 0.05);
last = now;
update(dt); // 移動、碰撞、勝負
draw(); // 依照目前資料繪圖
requestAnimationFrame(loop);
}
init();
requestAnimationFrame(loop);操作看看:速度 × 時間
按開始後可調整速度,抵達右側後從左側繼續。
動手修改
讓敵機下降速度從每秒 14 改成每秒 25。
展開參考答案
修改 update 裡的數字,仍乘上 dt。
en.y += 25 * dt;