原文地址: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. debugging openstack with pdb

    在要开始debug的地方导入pdb: class KeypairAPI(base.Base): """Sub-set of the Compute Manager API ...

  2. shrink-to-fit(自适应宽度)

    自适应宽度是指当未明白设定容器的宽度(或外边距设为auto)时,在特定的情况下容器的宽度会依据情况自行设定.而设定的结果往往并非我们想要的. W3C规范中描写叙述了几种shrink-to-fit的情况 ...

  3. 部署全局ajax处理

    $.ajaxSetup({ beforeSend:function(){ $('.loading').show(); }, complete:function(){ $('.loading').fad ...

  4. python虚拟机运行原理

    近期为了面试想要了解下python的运行原理方面的东西,奈何关于python没有找到一本类似于深入理解Java虚拟机方面的书籍,找到了一本<python源码剖析>电子书,但是觉得相对来说最 ...

  5. Arduino开发版学习计划--直流电机

    代码来源:http://www.cnblogs.com/starsnow/p/4579547.html // --------------------------------------------- ...

  6. 在Windows上手动安装php开发环境

    安装MySQL 使用官方提供提供的安装包一键安装即可. 打开 mysql,选择Windows,MSI Installer点击下载.附:最新版mysql5.7.18下载地址 点击installer安装, ...

  7. 文艺青年装B指南

        和大龄文艺青年们去凤凰的时候,很难不注意到狭窄小道旁边的文艺小店.有提供焦糖玛奇朵的咖啡店,有兜售梦露赫本明信片和烟雨 凤凰笔记本的店铺,还有复古式的静吧,常驻唱民谣小众歌曲的流浪歌手.我每看 ...

  8. 160613、MyBatis insert操作返回主键

    在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数:如果业务层需要得到记录的主键时,可以通过配置的方式来完成这个功能,针对Sequence主键而言,在执行 ...

  9. Zabbix低级主动发现之MySQL多实例

    接上篇:Zabbix自动发现与主动注册 在一个agent安装一个maraidb 拷贝一个原始配置文档并且修改配置用于开启多实例 按照配置文件初始化数据库 mysql_install_db --user ...

  10. DEV中gridview常用属性

    1.隐藏最上面的GroupPanel: gridView1.OptionsView.ShowGroupPanel=false; 2.得到当前选定记录某字段的值: sValue=Table.Rows[g ...