原文地址: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的本地存储。我非常乐意看见你的谢意和评论。好运!

HTML5游戏开发系列教程7(译)的更多相关文章

  1. HTML5游戏开发系列教程6(译)

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-6/ 这是我们最新一篇HTML5游戏开发系列文章.我们将继续使用c ...

  2. HTML5游戏开发系列教程5(译)

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-5/ 最终我决定准备下一篇游戏开发系列的文章,我们将继续使用can ...

  3. HTML5游戏开发系列教程4(译)

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-4/ 这篇文章是我们继续使用canvas来进行HTML5游戏开发系 ...

  4. HTML5游戏开发系列教程8(译)

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-8/ 这是我们最新一篇HTML5游戏开发系列文章.我们将继续使用c ...

  5. HTML5游戏开发系列教程10(译)

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-10/ 最后我们将继续使用canvas来进行HTML5游戏开发系列 ...

  6. HTML5游戏开发系列教程9(译)

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-9/ 今天我们将继续使用canvas来进行HTML5游戏开发系列的 ...

  7. cocos2d-x游戏开发系列教程-前言

    cocos2d-x游戏开发前景: 最近企业对于Cocos2D-X开发人才的用人需求很大,而且所提供的薪资相当可观. 为满足广大向往游戏开发行业同学的需求,特推出适合新手的Cocos2D-X手游开发教程 ...

  8. cocos2d-x游戏开发系列教程-超级玛丽07-CMGameMap

    背景 在上一篇博客中,我们提到CMGameScene,但是CMGameScene只是个框架,实际担任游戏逻辑的是CMGameMap类,这个博文就来了解下CMGameMap 头文件 class CMGa ...

  9. cocos2d-x游戏开发系列教程-超级玛丽06-CMGameScene

    背景 在CMMenuScene中,当用户点击开始游戏时,导演让场景进入到CMGameScene 头文件 class CMGameScene : public cocos2d::CCLayer,publ ...

随机推荐

  1. 小结:线段树 & 主席树 & 树状数组

    概要: 就是用来维护区间信息,然后各种秀智商游戏. 技巧及注意: 一定要注意标记的下放的顺序及影响!考虑是否有叠加或相互影响的可能! 和平衡树相同,在操作每一个节点时,必须保证祖先的tag已经完全下放 ...

  2. centos7安装avahi

    sudo yum install avahi sudo yum install avahi-tools 转自: http://unix.stackexchange.com/questions/1829 ...

  3. 修改CFileDialog的标题

    CFileDialog   f(TRUE);   f.m_ofn.lpstrTitle   =   "我的标题";   f.DoModal(); 设置标题! CFileDialog ...

  4. 过滤一个Collection最好的方法

    private static List<Integer> filter(List<Integer> list){ Iterator<Integer> it = li ...

  5. 83、android的消息处理机制(图+源码分析)——Looper,Handler,Message

    转载:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html https://my.oschina.net/u/139 ...

  6. Cognos组织架构介绍

    Cognos只是一个工具,说到Cognos相信大部分人都知道BI(商业智能,Business Intelligence). Cognos也是属于SOA架构,面向服务的体系结构,是一个组件模型,它将应用 ...

  7. python反序列化研究学习

    零.补充: 补充于2018-02-08,之前研究时候有一个疑惑,python的序列化成二进制,打web服务怎么传这个二进制对象呢,今天请教了身边大神(传说的九零后黑客代表),可以使用base64传输. ...

  8. [黑金原创教程] FPGA那些事儿《设计篇 I》- 图像处理前夕

    简介 一本为入门图像处理的入门书,另外还教你徒手搭建平台(片上系统),内容请看目录. 注意 为了达到最好的实验的结果,请准备以下硬件. AX301开发板, OV7670摄像模块, VGA接口显示器, ...

  9. 移动端1px细线解决方案--利用transform缩放方式

    移动端1px会显示为2px; 解决方式很多,这里介绍比较常用的一种方式--css的transform属性缩放 1. 上边框 相当于 border-top <div class="bor ...

  10. 在 Java 应用程序中绑定 Bean 和数据

    本指南介绍了 NetBeans IDE 对 Java 应用程序中 Bean 绑定和数据绑定的支持. 要学完本教程,您需要具备以下软件和资源. 软件或资源 要求的版本 NetBeans IDE 版本 7 ...