最近学习了一下html5的canvas技术,做了space bowling的小游戏练手。为cocos2d-html5做点准备。
only备份代码。
index.htm
<!DOCTYPE html> <html> <head> <title>Space Bowing</title> <meta charset="utf-8"> <link href = "game.css" rel = "stylesheet" type = "text/css"> <script type = "text/javascript" src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script> <script type = "text/javascript" src="game.js"></script> </head> <body> <div id = "game"> <div id = "gameUI"> <div id = "gameIntro"> <h1>Space bowing</h1> <p>This is an awesome game.</p> <p><a id="gamePlay" class="button" href="">Play</a></p> </div> <div id = "gameStats"> <p>Asteroids :<span id = "gameRemaining"></span></p> <p>Clicks :<span class = "gameScore"></span></p> <p><a class = "gameReset" href = "">Reset</a></p> </div> <div id = "gameComplete"> <h1>You Win!</h1> <p>Congratulations, you completed the game in <span class = "gameScore"></span> clicks.</p> <p><a class = "gameReset button" href = "">Play again</a></p> </div> </div> <canvas id = "gameCanvas" widrh = "350" height = "600"> <!--> </canvas> </div> </body> </html>
game.css
/* CSS Document */ * {margin: 100; padding: 0;} html, body {height: 100%; width: 100%;} canvas {display: block;} body { background: #000; color: #fff; font-family: Verdana, Arial, sans-serif; font-size: 18px; } h1 { font-size: 30px; } p { margin: 0 20px; } a { color: #fff; text-decoration: none; } a:hover { text-decoration: underline; } a.button { background: #185da8; border-radius: 5px; display: block; font-size: 30px; margin: 40px 0 0 45px; padding: 10px; width: 200px; } a.button: hover { background: #2488f5; color: #fff text-decoration: none; } #game { heigth: 600px; left: 50%; margin: -350px 0 0 -175px; position: relative; top: 50%; width: 350px; } #gameCanvas { background: #001022; } #gameUI { height: 600px; position: absolute; width: 350px; } #gameIntro, #gameComplete { background: rgba(0, 0, 0, 0.5); margin-top: 100px; padding: 40px 0; text-align: center; } #gameStats { font-size: 14px; margin: 20px 0; } #gameStats .gameReset { margin: 20px 60px 0 0; position: absolute; right: 0; top: 0; }
game.js
// JavaScript Document $(document).ready(function() { var canvas = $("#gameCanvas"); var context = canvas.get(0).getContext("2d"); var canvasWidth = canvas.width(); var canvasHeight = canvas.height(); var playGame; var score; var asteroids; var player; var playerOriginalX; var playerOriginalY; var playerSelected; var playerMaxAbsVelocity; var playerVelocityDampener; var powerX; var powerY; var platformX; var platformY; var platformOuterRadius; var platformInnerRadius; var ui = $("#gameUI"); var uiIntro = $("#gameIntro"); var uiStats = $("#gameStats"); var uiComplete = $("#gameComplete"); var uiPlay = $("#gamePlay"); var uiReset = $(".gameReset"); var uiRemaining = $("#gameRemaining"); var uiScore = $(".gameScore"); var Asteroid = function(x, y, radius, mass, friction) { this.x = x; this.y = y; this.radius = radius; this.mass = mass; this.friction = friction; this.vX = 0; this.vY = 0; this.player = false; } function resetPlayer() { player.x = playerOriginalX; player.y = playerOriginalY; player.vX = 0; player.vY = 0; } function startGame() { uiScore.html("0"); uiStats.show(); platGame = false; platformX = canvasWidth/2; platformY = 150; platformOuterRadius = 100; platformInnerRadius = 75; asteroids = new Array(); playerSelected = false; playerMaxAbsVelocity = 30; playerVelocityDampener = 0.3; powerX = -1; powerY = -1; score = 0; var pRadius = 15; var pMass = 10; var pFriction = 0.97; playerOriginalX = canvasWidth/2; playerOriginalY = canvasHeight-150; player = new Asteroid(playerOriginalX, playerOriginalY, pRadius, pMass, pFriction); player.player = true; asteroids.push(player); var outerRing = 8; var ringCount = 3; var ringSpacing = (platformInnerRadius/(ringCount-1)); for(var r=0; r<ringCount; r++) { var currentRing = 0; var angle = 0; var ringRadius = 0; if(r == ringCount-1) { currentRing = 1; } else { currentRing = outerRing - (r*3); angle = 360/currentRing; ringRadius = platformInnerRadius-(ringSpacing*r); }; for(var a=0; a<currentRing; a++) { var x = 0; var y = 0; if(r == ringCount-1) { x = platformX; y = platformY; } else { x = platformX + (ringRadius*Math.cos((angle*a)*(Math.PI/180))); y = platformY + (ringRadius*Math.sin((angle*a)*(Math.PI/180))); var radius = 10; var mass = 5; var friction = 0.95; asteroids.push(new Asteroid(x, y, radius, mass, friction)); }; }; uiRemaining.html(asteroids.length-1); }; $(window).mousedown(function(e) { if(!playerSelected && player.x == playerOriginalX && player.y == playerOriginalY) { var canvasOffset = canvas.offset(); var canvasX = Math.floor(e.pageX - canvasOffset.left); var canvasY = Math.floor(e.pageY - canvasOffset.top); if(!playGame) { playGame = true; animate(); }; var dX = player.x - canvasX; var dY = player.y - canvasY; var distance = Math.sqrt((dX*dX)+(dY*dY)); var padding = 5; if(distance < player.radius+padding) { powerX = player.x; powerY = player.y; playerSelected = true; }; }; }); $(window).mousemove(function(e) { if(playerSelected) { var canvasOffset = canvas.offset(); var canvasX = Math.floor(e.pageX - canvasOffset.left); var canvasY = Math.floor(e.pageY - canvasOffset.top); var dX = canvasX - player.x; var dY = canvasY - player.y; var distance = Math.sqrt((dX*dX)+(dY*dY)); if(distance*playerVelocityDampener < playerMaxAbsVelocity) { powerX = canvasX; powerY = canvasY; } else { var ratio = playerMaxAbsVelocity/(distance*playerVelocityDampener); powerX = player.x + (dX*ratio); powerY = player.y + (dY*ratio); }; }; }); $(window).mouseup(function(e) { if(playerSelected) { var dX = powerX - player.x; var dY = powerY - player.y; player.vX = -(dX * playerVelocityDampener); player.vY = -(dY * playerVelocityDampener); uiScore.html(++score); }; playerSelected = false; powerX = -1; powerY = -1; }); animate(); }; function init() { uiStats.hide(); uiComplete.hide(); uiPlay.click(function(e) { e.preventDefault(); uiIntro.hide(); startGame(); }); uiReset.click(function(e) { e.preventDefault(); uiComplete.hide(); startGame(); }); }; function animate() { context.clearRect(0, 0, canvasWidth, canvasHeight); context.fillStyle = "rgb(100, 100, 100)"; context.beginPath(); context.arc(platformX, platformY, platformOuterRadius, 0, Math.PI*2, true); context.closePath(); context.fill(); if(playerSelected) { context.strokeStyle = "rgb(255, 255, 255)"; context.lineWidth = 3; context.beginPath(); context.moveTo(player.x, player.y); context.lineTo(powerX, powerY); context.closePath(); context.stroke(); } context.fillStyle = "rgb(255, 255, 255)"; var deadAsteroids = new Array(); var asteroidsLength = asteroids.length; for(var i=0; i<asteroidsLength; i++) { var tmpAsteroid = asteroids[i]; for(var j=i+1; j<asteroidsLength; j++) { var tmpAsteroidB = asteroids[j]; var dX = tmpAsteroidB.x - tmpAsteroid.x; var dY = tmpAsteroidB.y - tmpAsteroid.y; var distance = Math.sqrt((dX*dX)+(dY*dY)); if(distance < tmpAsteroidB.radius + tmpAsteroid.radius) { var angle = Math.atan2(dY, dX); var sine = Math.sin(angle); var cosine = Math.cos(angle); var x = 0; var y = 0; var xB = dX*cosine + dY*sine; var yB = dY*cosine - dX*sine; var vX = tmpAsteroid.vX * cosine + tmpAsteroid.vY * sine; var vY = tmpAsteroid.vY * cosine - tmpAsteroid.vX * sine; var vXb = tmpAsteroidB.vX * cosine + tmpAsteroidB.vY * sine; var vYb = tmpAsteroidB.vY * cosine - tmpAsteroidB.vX * sine; var vTotal = vX - vXb; vX = ((tmpAsteroid.mass - tmpAsteroidB.mass) * vX + 2 * tmpAsteroidB.mass * vXb) / (tmpAsteroid.mass + tmpAsteroidB.mass); vXb = vTotal + vX; xB = x + (tmpAsteroid.radius + tmpAsteroidB.radius); tmpAsteroid.x = tmpAsteroid.x + (y * cosine - y * sine); tmpAsteroid.y = tmpAsteroid.y + (y * cosine + x * sine); tmpAsteroidB.x = tmpAsteroid.x + (xB * cosine - yB * sine); tmpAsteroidB.y = tmpAsteroid.y + (yB * cosine + xB * sine); tmpAsteroid.vX = vX * cosine - vY * sine; tmpAsteroid.vY = vY * cosine + vX * sine; tmpAsteroidB.vX = vXb * cosine - vYb * sine; tmpAsteroidB.vY = vYb * cosine + vXb * sine; }; }; tmpAsteroid.x += tmpAsteroid.vX; tmpAsteroid.y += tmpAsteroid.vY; if (Math.abs(tmpAsteroid.vX) > 0.1) { tmpAsteroid.vX *= tmpAsteroid.friction; } else { tmpAsteroid.vX = 0; }; if (Math.abs(tmpAsteroid.vY) > 0.1) { tmpAsteroid.vY *= tmpAsteroid.friction; } else { tmpAsteroid.vY = 0; }; if (!tmpAsteroid.player) { var dXp = tmpAsteroid.x - platformX; var dYp = tmpAsteroid.y - platformY; var distanceP = Math.sqrt((dXp*dXp)+(dYp*dYp)); if (distanceP > platformOuterRadius) { // Kill asteroid if (tmpAsteroid.radius > 0 && tmpAsteroid != player) { tmpAsteroid.radius -= 1; } else { deadAsteroids.push(tmpAsteroid); }; }; }; if (player.x != playerOriginalX && player.y != playerOriginalY) { if (player.vX == 0 && player.vY == 0) { resetPlayer(); } else if (player.x+player.radius < 0) { resetPlayer(); } else if (player.x-player.radius > canvasWidth) { resetPlayer(); } else if (player.y+player.radius < 0) { resetPlayer(); } else if (player.y-player.radius > canvasHeight) { resetPlayer(); }; }; context.beginPath(); context.arc(tmpAsteroid.x, tmpAsteroid.y, tmpAsteroid.radius, 0, Math.PI*2, true); context.closePath(); context.fill(); }; var deadAsteroidsLength = deadAsteroids.length; if (deadAsteroidsLength > 0) { for (var di = 0; di < deadAsteroidsLength; di++) { var tmpDeadAsteroid = deadAsteroids[di]; asteroids.splice(asteroids.indexOf(tmpDeadAsteroid), 1); }; var remaining = asteroids.length-1; // Remove player from asteroid count uiRemaining.html(remaining); if (remaining == 0) { // Winner! playGame = false; uiStats.hide(); uiComplete.show(); // Reset event handlers $(window).unbind("mousedown"); $(window).unbind("mouseup"); $(window).unbind("mousemove"); }; }; if(playGame) { setTimeout(animate, 33); }; }; init(); });
这里有别人发布的这个demo的展示,还提供了源码。