原文地址: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. android system.img 解压和打包

    system.img重新编译的时间太长,添加和更改的文件系统内容,往往通过对system.img加压再打包的方式. 参考链接 http://blog.csdn.net/whu_zhangmin/art ...

  2. 第二百七十四节,同源策略和跨域Ajax

    同源策略和跨域Ajax 什么是同源策略  尽管浏览器的安全措施多种多样,但是要想黑掉一个Web应用,只要在浏览器的多种安全措施中找到某种措施的一个漏洞或者绕过一种安全措施的方法即可.浏览器的各种保安措 ...

  3. IIS故障问题(Connections_Refused)分析及处理【转】

    这篇文章其实已经写好很久,只是后来一直没有重现当时的问题,或者因为业务的重要性.投诉的压力也就临时处理了.这几天某地市Web服务器连续多次出现这个问题,正好借这个案例来做个收尾. 前几个月有台重要的W ...

  4. 【BZOJ】1005: [HNOI2008]明明的烦恼(prufer编码+特殊的技巧)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1005 这里讲得挺清楚的:http://www.cnblogs.com/zhj5chengfeng/p ...

  5. python3----scrapy(笔记)

    import scrapy import sys # import io # sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb ...

  6. jquery后加Dom绑定事件

    $('#musicCategoryListContainer').on('click', '.musicCategoryItem', function () { $(this).siblings(). ...

  7. 编程之美 set 7 求数组中的最长递增子序列

    解法 1. 假设在目标数组 array[] 的前 i 个元素中, 最长递增子序列的长度为 LIS[i] 那么状态转移方程为 LIS[i] = max(1, LIS[k]+1) array[i+1] & ...

  8. Spring学习笔记--自动检测

    要使用自动检测,我们需要用到<context:annotation-scan>标签.<context:annotation-scan>元素除了完成与<context:an ...

  9. JZOJ.5315【NOIP2017模拟8.19】小串串

    Description

  10. Django学习笔记第二篇--关于请求获取

    #细节都在代码段里面讲解 零.绪论: HTTP协议是一种请求响应的协议,一次请求一次响应.所以这部分的讲解将分为三个部分:请求获取,分析处理.返回响应. 一.获取请求数据: 1.POST和GET类型 ...