前言
前一陣發現一個不錯的網站,都是一些用html5+css+js寫的小游戲,於是打算學習一番,寫下這個系列博客主要是為了加深理解,當然也有一些個人感悟,如果英文好可以直接Click Here.
概述
一般,小游戲都要關注兩個問題:刷新和交互。因為游戲一般是動態的,所以需要不斷刷新。JavaScript是單線程,如果用C語言寫過貪吃蛇之類的小游戲,應該知道,單線程一般是掛起一個時間來達到動態效果。比如C語言的Sleep(),JS的setInterval()等。但是js還有一種更高性能的方法requestAnimationFrame。可以在網上找些資料進行學習,在此不做贅述。另一個就是交互,即用戶需要通過鼠標、鍵盤控制游戲,從編程角度來書就是要添加對應事件的監聽器。
以下,正式開始。
HTML5
先創建一個canvas畫布:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Rembound.com Example</title> 6 <script type="text/javascript" src="script.js"></script> 7 </head> 8 <body> 9 <canvas id="viewport" width="640" height="480"></canvas> 10 </body> 11 </html>
JS
添加以下基本代碼,代碼詳情可以看注釋,最好單步調試加深理解:
//窗口加載完成后調用 window.onload = function() { // 獲取畫布及context(上下文) var canvas = document.getElementById("viewport"); var context = canvas.getContext("2d"); // 記錄時間幀,這個最好通過單步調試來理解 var lastframe = 0; var fpstime = 0; var framecount = 0; var fps = 0; // 初始化游戲,添加鼠標的監聽事件 function init() { canvas.addEventListener("mousemove", onMouseMove); canvas.addEventListener("mousedown", onMouseDown); canvas.addEventListener("mouseup", onMouseUp); canvas.addEventListener("mouseout", onMouseOut); // 進入游戲主循環 main(0); } // 主循環 function main(tframe) { // 結束時繼續調用main函數 window.requestAnimationFrame(main); // 更新游戲 update(tframe); render(); } // 更新游戲狀態,計算已經過去了的時間 function update(tframe) { var dt = (tframe - lastframe) / 1000; lastframe = tframe; //更新幀數計數器 updateFps(dt); } function updateFps(dt) { if (fpstime > 0.25) { //計算幀數 fps = Math.round(framecount / fpstime); //重置時間 fpstime = 0; framecount = 0; } //增加幀時間、幀數 fpstime += dt; framecount++; } // 渲染(更新畫布) function render() { drawFrame(); } // function drawFrame() { // 背景、邊界 context.fillStyle = "#d0d0d0"; context.fillRect(0, 0, canvas.width, canvas.height); context.fillStyle = "#e8eaec"; context.fillRect(1, 1, canvas.width-2, canvas.height-2); // 標題頭 context.fillStyle = "#303030"; context.fillRect(0, 0, canvas.width, 65); // 標題 context.fillStyle = "#ffffff"; context.font = "24px Verdana"; context.fillText("HTML5 Canvas Basic Framework - Rembound.com", 10, 30); // 顯示幀數 context.fillStyle = "#ffffff"; context.font = "12px Verdana"; context.fillText("Fps: " + fps, 13, 50); } //鼠標監聽 function onMouseMove(e) {} function onMouseDown(e) {} function onMouseUp(e) {} function onMouseOut(e) {} // 獲取鼠標位置 function getMousePos(canvas, e) { var rect = canvas.getBoundingClientRect(); return { x: Math.round((e.clientX - rect.left)/(rect.right - rect.left)*canvas.width), y: Math.round((e.clientY - rect.top)/(rect.bottom - rect.top)*canvas.height) }; } // 游戲入口 init(); };
效果:
添加游戲元素
以上就是一個通用的游戲框架了,雖然它在不斷刷新,但是沒什么直觀感受,以下建立一個簡單游戲來感受一下:
...... var framecount = 0; var fps = 0; // 游戲平面 var level = { x: 1, y: 65, width: canvas.width - 2, height: canvas.height - 66 }; // 小方塊 var square = { x: 0, y: 0, width: 0, height: 0, xdir: 0, ydir: 0, speed: 0 } // 分數 var score = 0; // 初始化游戲,添加鼠標的監聽事件 function init() { ....
在init()函數中添加:
.... canvas.addEventListener("mouseout", onMouseOut); // 初始化方塊 square.width = 100; square.height = 100; square.x = level.x + (level.width - square.width) / 2; square.y = level.y + (level.height - square.height) / 2; square.xdir = 1; square.ydir = 1; square.speed = 200; // 初始化分數 score = 0; // 進入游戲主循環 main(0); ....
在update()函數中更新方塊
.... //更新幀數計數器 updateFps(dt); // 基於時間移動方塊 square.x += dt * square.speed * square.xdir; square.y += dt * square.speed * square.ydir; // 處理碰撞 if (square.x <= level.x) { // Left edge square.xdir = 1; square.x = level.x; } else if (square.x + square.width >= level.x + level.width) { // Right edge square.xdir = -1; square.x = level.x + level.width - square.width; } if (square.y <= level.y) { // Top edge square.ydir = 1; square.y = level.y; } else if (square.y + square.height >= level.y + level.height) { // Bottom edge square.ydir = -1; square.y = level.y + level.height - square.height; } ...
render()函數中還要渲染方塊
.... // 繪制方塊 context.fillStyle = "#ff8080"; context.fillRect(square.x, square.y, square.width, square.height); // 繪制內部 context.fillStyle = "#ffffff"; context.font = "38px Verdana"; var textdim = context.measureText(score); context.fillText(score, square.x+(square.width-textdim.width)/2, square.y+65); ...
添加鼠標事件
function onMouseDown(e) { // 獲取鼠標位置 var pos = getMousePos(canvas, e); // 檢查是否碰到了方塊 if (pos.x >= square.x && pos.x < square.x + square.width && pos.y >= square.y && pos.y < square.y + square.height) { // 增加分數 score += 1; // 增加速度 square.speed *= 1.1; // 隨機給一個新的位置 square.x = Math.floor(Math.random()*(level.x+level.width-square.width)); square.y = Math.floor(Math.random()*(level.y+level.height-square.height)); // 隨機方向 square.xdir = Math.floor(Math.random() * 2) * 2 - 1; square.ydir = Math.floor(Math.random() * 2) * 2 - 1; } }
效果
完整源代碼:Click Here
注:這只是眾多小游戲合集中的一個,今后會繼續添加。