HTML5游戏开发系列教程7(译)

时间:2023-03-08 17:12:18
HTML5游戏开发系列教程7(译)

原文地址:http://www.script-tutorials.com/html5-game-development-lesson-7/

今天我们将完成我们第一个完整的游戏--打砖块。这次教程中,将展示怎样进行基本的碰撞检测和使用HTML5的本地存储。你可以使用鼠标和键盘来操作挡板,上一次游戏的持续时间和分数将会保存。

前一篇的的介绍在HTML5游戏开发系列教程6(译)。

第一步:HTML

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML5 Game Development - Lesson 7 | Script Tutorials</title>
<link href="css/main.css" rel="stylesheet" type="text/css" />
<script src="js/jquery-2.0.0.min.js"></script>
<script src="js/script.js"></script>
</head>
<body>
<header>
<h2>HTML5 Game Development - Lesson 7</h2>
<a href="http://www.script-tutorials.com/html5-game-development-lesson-7/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
</header>
<div class="container">
<canvas id="scene" width="800" height="600"></canvas>
</div>
</body>
</html>

第二步:CSS

下面是css样式文件

css/main.css

 /* page layout styles */
*{
margin:;
padding:;
}
body {
background-color:#eee;
color:#fff;
font:14px/1.3 Arial,sans-serif;
}
header {
background-color:#212121;
box-shadow: 0 -1px 2px #111111;
display:block;
height:70px;
position:relative;
width:100%;
z-index:;
}
header h2{
font-size:22px;
font-weight:normal;
left:50%;
margin-left:-400px;
padding:22px 0;
position:absolute;
width:540px;
}
header a.stuts,a.stuts:visited{
border:none;
text-decoration:none;
color:#fcfcfc;
font-size:14px;
left:50%;
line-height:31px;
margin:23px 0 0 110px;
position:absolute;
top:;
}
header .stuts span {
font-size:22px;
font-weight:bold;
margin-left:5px;
}
.container {
margin: 20px auto;
overflow: hidden;
position: relative;
width: 800px;
}

第三步:JS

js/jquery-2.0.0.min.js  (原文使用的是jquery-1.5.2.min.js)

js/script.js

 //内部变量
var canvas, ctx; var iStart = 0;
var bRightBut = false;
var bLeftBut = false;
var oBall, oPadd, oBricks;
var aSounds = [];
var iPoints = 0;
var iGameTimer;
var iElapsed = iMin = iSec = 0;
var sLastTime, sLastPoints; /**
* @brief 球体对象
*
* @param x 横坐标
* @param y 纵坐标
* @param dx 横坐标将要移动的距离
* @param dy 纵坐标将要移动的距离
* @param r 半径
*
* @return
*/
function Ball(x, y, dx, dy, r) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.r = r;
} /**
* @brief 挡板对象
*
* @param x 横坐标--纵坐标固定的
* @param w 宽端
* @param h 高度
* @param img 图片
*
* @return
*/
function Padd(x, w, h, img) {
this.x = x;
this.w = w;
this.h = h;
this.img = img;
} /**
* @brief 砖块对象
*
* @param w 宽度
* @param h 高度
* @param r row 第几排
* @param c column 第几列
* @param p 砖块之间的间隙
*
* @return
*/
function Bricks(w, h, r, c, p) {
this.w = w;
this.h = h;
this.r = r;
this.c = c;
this.p = p;
this.objs;
this.colors = ['#9d9d9d', '#f80207', '#feff01', '#0072ff', '#fc01fc', '#03fe03'];
} function clear() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.fillStyle = '#111';
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
} function drawScene() {
clear(); //绘制球
ctx.fillStyle = '#f66';
ctx.beginPath();
ctx.arc(oBall.x, oBall.y, oBall.r, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill(); //padd左右移动
if (bRightBut) {
oPadd.x += 5;
} else if (bLeftBut) {
oPadd.x -= 5;
} ctx.drawImage(oPadd.img, oPadd.x, ctx.canvas.height - oPadd.h); //绘制砖块
for (i = 0; i < oBricks.r; i++) {
ctx.fillStyle = oBricks.colors[i];
for (j = 0; j < oBricks.c; j++) {
if (oBricks.objs[i][j] == 1) {
ctx.beginPath();
ctx.rect((j * (oBricks.w + oBricks.p)) + oBricks.p, (i * (oBricks.h + oBricks.p)) + oBricks.p, oBricks.w, oBricks.h);
ctx.closePath();
ctx.fill();
}
}
} //处理碰撞检测
iRowH = oBricks.h + oBricks.p;
iRow = Math.floor(oBall.y / iRowH);
iCol = Math.floor(oBall.x / (oBricks.w + oBricks.p)); if (oBall.y < oBricks.r * iRowH && iRow >= 0 && iCol >= 0 && oBricks.objs[iRow][iCol] == 1) { //处理球碰到砖块
oBricks.objs[iRow][iCol] = 0;
oBall.dy = -oBall.dy;
iPoints++; aSounds[0].play();
} if (oBall.x + oBall.dx + oBall.r > ctx.canvas.width || oBall.x + oBall.dx - oBall.r < 0) { //处理左右边界
oBall.dx = -oBall.dx;
} if (oBall.y + oBall.dy - oBall.r < 0) { //处理上边界
oBall.dy = -oBall.dy;
} else if (oBall.y + oBall.dy + oBall.r > ctx.canvas.height - oPadd.h) { //处理下边界
if (oBall.x > oPadd.x && oBall.x < oPadd.x + oPadd.w) { //球碰到挡板反弹
oBall.dx = 10 * ((oBall.x - (oPadd.x + oPadd.w / 2)) / oPadd.w);
oBall.dy = -oBall.dy; aSounds[2].play();
} else if (oBall.y + oBall.dy + oBall.r > ctx.canvas.height) { //失败
clearInterval(iStart);
clearInterval(iGameTimer); //在Local Storage中存持续时间和分数
localStorage.setItem('last-time', iMin + ':' + iSec);
localStorage.setItem('last-points', iPoints); aSounds[1].play();
}
} oBall.x += oBall.dx;
oBall.y += oBall.dy; //显示分数和时间
ctx.font = '16px Verdana';
ctx.fillStyle = '#fff';
iMin = Math.floor(iElapsed / 60);
iSec = iElapsed % 60;
if (iMin < 10) {
iMin = "0" + iMin;
}
if (iSec < 10) {
iSec = "0" + iSec;
}
ctx.fillText('Time: ' + iMin + ':' + iSec, 600, 520);
ctx.fillText('Points: ' + iPoints, 600, 550); if (sLastTime != null && sLastPoints != null) {
ctx.fillText('Last Time: ' + sLastTime, 600, 400);
ctx.fillText('Last Points: ' + sLastPoints, 600, 490);
}
} //初始化
$(function() {
canvas = document.getElementById('scene');
ctx = canvas.getContext('2d'); var width = canvas.width;
var height = canvas.height; var padImg = new Image();
padImg.src = 'images/padd.png';
padImg.onload = function() {}; oBall = new Ball(width / 2, 550, 0.5, -5, 10);
oPadd = new Padd(width / 2, 120, 20, padImg);
oBricks = new Bricks((width / 8) - 1, 20, 6, 8, 2); oBricks.objs = new Array(oBricks.r); //oBricks.objs 是个二维数组
for (i = 0; i <oBricks.r; i++) {
oBricks.objs[i] = new Array(oBricks.c);
for (j = 0; j < oBricks.c; j++) {
oBricks.objs[i][j] = 1;
}
} //声音
aSounds[0] = new Audio('media/snd1.wav');
aSounds[0].volume = 0.9;
aSounds[1] = new Audio('media/snd2.wav');
aSounds[1].volume = 0.9;
aSounds[2] = new Audio('media/snd3.wav');
aSounds[2].volume = 0.9; iStart = setInterval(drawScene, 10); //重绘
iGameTimer = setInterval(countTimer, 1000); //计数器 sLastTime = localStorage.getItem('last-time');
sLastPoints = localStorage.getItem('last-points'); $(window).keydown(function(event) {
switch (event.keyCode) {
case 37:
bLeftBut = true;
break;
case 39:
bRightBut = true;
break;
}
});
$(window).keyup(function(event) {
switch (event.keyCode) {
case 37:
bLeftBut = false;
break;
case 39:
bRightBut = false;
break;
}
}); //处理挡板跟随鼠标移动
var iCanvX1 = $(canvas).offset().left;
var iCanvX2 = iCanvX1 + width;
$('#scene').mousemove(function(e) {
if (e.pageX > iCanvX1 && e.pageX < iCanvX2) {
oPadd.x = Math.max(e.pageX - iCanvX1 - (oPadd.w / 2), 0);
oPadd.x = Math.min(ctx.canvas.width - oPadd.w, oPadd.x);
}
});
}); function countTimer() {
iElapsed++;
}

我在很多地方添加了注释,希望这些代码很容易理解。注意localStorage对象,并理解它在HTML5本地存储中是如果使用的(使用setItem方法来存储数据,使用getItem来取出数据)。同样,理解怎样处理球和砖块之间的碰撞检测将会很有趣。

结论:

这次我们编写了我们的第一个打砖块游戏。最重要的功能已经呈现了,并且学习了碰撞检测和HTML5的本地存储。我非常乐意看见你的谢意和评论。好运!