鍵盤是一種經常使用的輸入設備,靈活熟練地使用鍵盤進行輸入是計算機用戶需掌握的一門基本功。下面咱們編寫一個簡單的鍵盤練習遊戲。html
在編寫簡單的鍵盤練習遊戲以前,先設計一個簡單地刺破氣泡交互式小動畫。canvas
在面板底部逐個上升一些氣泡,用鼠標在某個氣泡上單擊,該氣泡被刺破,刺破後的小氣泡逐漸消散在面板中。交互式效果如圖1所示。數組
圖1 刺破氣泡交互式動畫dom
一個氣泡可分爲兩個狀態:(1)氣泡從面板底部上升;(2)氣泡被鼠標單擊刺破成小氣泡或氣泡上升越過了面板頂部消散了。ide
爲此抽象出兩個對象類:Bubbles和miniBubbles。其中,Bubbles用於表示一個未被刺破的氣泡,miniBubbles用於表示一個氣泡刺破後獲得的逐漸消散的小氣泡。函數
Bubbles對象類定義6個屬性:表示氣泡圓心的座標(x,y)、氣泡的半徑radius、上升時垂直方向的位移改變量ySpeed、氣泡上升加速度gravity和睦泡顏色color。動畫
座標屬性值y的初始值取畫布的高度,表示氣泡從遊戲面板底部開始上升,其他各屬性的初始值採用隨機數肯定或直接指定。具體定義以下:this
function Bubbles()spa
{prototype
this.x = rand(30,canvas.width - 30);
this.y = canvas.height;
this.radius = rand(15, 30);
this.color ='rgba(255, 255, 255, 0.75)';
this.ySpeed= Math.random() * 2;
this.gravity = 0.01;
}
Bubbles對象類定義2個方法:繪製氣泡的方法draw()、氣泡上升時座標改變方法update()。
miniBubbles對象類定義8個屬性:表示小氣泡圓心的座標(x,y)、小氣泡半徑radius、散開時水平和垂直方向的位移改變量xSpeed和ySpeed、小氣泡的填充color、小氣泡的減速度gravity、小氣泡的存活時間timeToLive。具體定義以下:
function miniBubbles(x,y,radius)
{
this.x = x;
this.y = y;
this.radius = radius;
this.color = 'rgba(255, 255, 255, 0.5)';
this.xSpeed=(Math.random() - 0.5) * 0.6;
this.ySpeed=(Math.random() - 1) * 0.5;
this.gravity = -0.03;
this.timeToLive = 100;
}
miniBubbles對象類定義2個方法:繪製小氣泡的方法draw()、小氣泡位置改變改變方法update()。小氣泡每次改變位置後,timeToLive減1,當timeToLive值等於0時,從小氣泡數組中刪除該小氣泡,表示該小氣泡已消亡。
定義兩個數組var bubbles = [];和 var minibubbles = [];分別存儲未刺破的大氣泡對象和大氣泡刺破後散開的小氣泡。
爲畫布添加鼠標按下事件監控canvas.addEventListener('mousedown', function(){ });,在事件處理函數中查找鼠標單擊的氣泡,而後將該氣泡從bubbles數組中刪除,向minibubbles數組中添加若干個散開的小氣泡。
完整的HTML代碼以下。
<html> <head> <title>刺破氣泡小遊戲</title> </head> <body> <canvas id="myCanvas"></canvas> <script> var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); canvas.height = innerHeight; canvas.width = innerWidth; function rand(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } function Bubbles() { this.x = rand(30,canvas.width - 30); this.y = canvas.height; this.radius = rand(15, 30); this.color ='rgba(255, 255, 255, 0.75)'; this.ySpeed= Math.random() * 2; this.gravity = 0.01; } Bubbles.prototype.draw = function () { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); ctx.fillStyle = this.color; ctx.fill(); ctx.closePath(); } Bubbles.prototype.update = function () { this.y -= this.ySpeed; if (this.y - this.radius > 0) this.ySpeed += this.gravity; this.draw(); } function miniBubbles(x,y,radius) { this.x = x; this.y = y; this.radius = radius; this.color = 'rgba(255, 255, 255, 0.5)'; this.xSpeed=(Math.random() - 0.5) * 0.6; this.ySpeed=(Math.random() - 1) * 0.5; this.gravity = -0.03; this.timeToLive = 100; } miniBubbles.prototype.draw = function () { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); ctx.fillStyle = this.color; ctx.fill(); ctx.closePath(); } miniBubbles.prototype.update = function () { if (this.y - this.radius > 0) this.ySpeed += this.gravity; this.x += this.xSpeed; this.y += this.ySpeed; this.timeToLive --; this.draw(); } var backgroundGradient = ctx.createLinearGradient(0, 0, 0, canvas.height); backgroundGradient.addColorStop(0, '#009cff') backgroundGradient.addColorStop(1, '#007bff') var bubbles = []; var minibubbles = []; var timer = 0; var spawnRate = 70; function animate() { requestAnimationFrame(animate); ctx.fillStyle = backgroundGradient; ctx.fillRect(0, 0, canvas.width, canvas.height); for (var i=bubbles.length-1;i>=0;i--) { bubbles[i].update(); if (bubbles[i].y<0) { bubbles.splice(i, 1); } } for (var i=minibubbles.length-1;i>=0;i--) { minibubbles[i].update(); if (minibubbles[i].timeToLive == 0) { minibubbles.splice(i, 1); } } timer++; if (timer==spawnRate) { bubbles.push(new Bubbles()); timer=0; spawnRate = rand(50, 100); } } canvas.addEventListener('mousedown', function(){ var x = event.pageX - canvas.getBoundingClientRect().left; var y = event.pageY - canvas.getBoundingClientRect().top; // 查找被單擊的氣泡 for (var i=bubbles.length-1; i>=0; i--) { var bubble = bubbles[i]; var dist = Math.sqrt(Math.pow(bubble.x-x,2)+ Math.pow(bubble.y- y,2)); if (dist<= bubble.radius) { var mx = bubble.x; var my = bubble.y; var mr = rand(2,5); bubbles.splice(i, 1) for (var k = 0; k < bubble.radius/mr; k++) { minibubbles.push(new miniBubbles(mx,my, mr)); } return; } } }); animate(); </script> </body> </html>
有了上面的基礎,咱們能夠編寫一個簡單的鍵盤練習小遊戲,大小寫字母出如今遊戲面板中,按鍵盤某個字母鍵後,對應的字母消失。遊戲過程如圖2所示。
圖2 鍵盤練習小遊戲
在Bubbles對象類中增長一個屬性letter,表示氣泡中顯示的字母。
爲Windows添加鍵盤按下keypress事件監聽,處理鍵盤按鍵。
完整的HTML代碼以下。
<html> <head> <title>簡單鍵盤練習</title> </head> <body> <canvas id="myCanvas"></canvas> <script> var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); canvas.height = innerHeight; canvas.width = innerWidth; var str="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; var cnt1=0; var cnt2=0; var cnt3=0; function rand(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } function Bubbles() { this.x = rand(30,canvas.width - 30); this.y = canvas.height; this.radius = 20; this.color ='rgba(255, 255, 255, 0.75)'; this.ySpeed= Math.random() * 2; this.gravity = 0.01; this.letter=str.charAt(rand(0,str.length-1)); } Bubbles.prototype.draw = function () { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); ctx.fillStyle = this.color; ctx.fill(); ctx.closePath(); ctx.font = "Bold 20px Georgia"; ctx.fillStyle = "Black"; ctx.textAlign = 'center'; ctx.baseline = 'middle'; ctx.fillText(this.letter,this.x, this.y); } Bubbles.prototype.update = function () { this.y -= this.ySpeed; if (this.y - this.radius > 0) this.ySpeed += this.gravity; this.draw(); } function miniBubbles(x,y,radius) { this.x = x; this.y = y; this.radius = radius; this.color = 'rgba(255, 255, 255, 0.5)'; this.xSpeed=(Math.random() - 0.5) * 0.6; this.ySpeed=(Math.random() - 1) * 0.5; this.gravity = -0.03; this.timeToLive = 100; } miniBubbles.prototype.draw = function () { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); ctx.fillStyle = this.color; ctx.fill(); ctx.closePath(); } miniBubbles.prototype.update = function () { if (this.y - this.radius > 0) this.ySpeed += this.gravity; this.x += this.xSpeed; this.y += this.ySpeed; this.timeToLive --; this.draw(); } var backgroundGradient = ctx.createLinearGradient(0, 0, 0, canvas.height); backgroundGradient.addColorStop(0, '#009cff') backgroundGradient.addColorStop(1, '#007bff') var bubbles = []; var minibubbles = []; var timer = 0; var spawnRate = 70; function animate() { requestAnimationFrame(animate); ctx.fillStyle = backgroundGradient; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.font = "Bold 30px Georgia"; ctx.fillStyle = "Black"; ctx.textAlign = 'center'; ctx.baseline = 'middle'; var mess="正確按鍵次數:"+cnt1+" 無效按鍵次數:"+cnt2+" 丟失字母個數:"+cnt3; ctx.fillText(mess,canvas.width/2,35); for (var i=bubbles.length-1;i>=0;i--) { bubbles[i].update(); if (bubbles[i].y<30) { cnt3++; bubbles.splice(i, 1); } } for (var i=minibubbles.length-1;i>=0;i--) { minibubbles[i].update(); if (minibubbles[i].timeToLive == 0) { minibubbles.splice(i, 1); } } timer++; if (timer==spawnRate) { bubbles.push(new Bubbles()); timer=0; spawnRate = rand(50, 100); } } window.addEventListener('keypress', function(e){ var keyID = e.keyCode ? e.keyCode :e.which; for (var i=0;i<bubbles.length-1;i++) { var bubble = bubbles[i]; if (keyID== bubble.letter.charCodeAt(0)) { var mx = bubble.x; var my = bubble.y; var mr = rand(2,5); bubbles.splice(i, 1) cnt1++; for (var k = 0; k < bubble.radius/mr; k++) { minibubbles.push(new miniBubbles(mx,my, mr)); } return; } } cnt2++; },true); animate(); </script> </body> </html>