原文地址: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 Studio 编写 JNI

    之前一直都不知怎么编写JNI,今天刚好学习一下,感谢梦真的指教,以及提供的文档. 参考链接 http://blog.csdn.net/u011168565/article/details/518781 ...

  2. 图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)

    图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面. 与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉 ...

  3. ThinkPHP项目笔记之函数篇

    说到函数,可能有人会想:框架的C(控制器)通牌都是函数构成的,没有必要讲吧. 当然,我要说的是,公共函数:function.php,该文件就是为了开发一下功能准备的,比方说,某个功能,a地方可用,b地 ...

  4. Python使用pycurl获取http的响应时间

    最近需要对节点到源站自己做个监控,简单的ping可以检测到一些东西,但是http请求的检查也要进行,于是就研究了下pycurlpycurl是个用c语言实现的python 库,虽然据说不是那么pytho ...

  5. 《Programming with Objective-C》第四章 Encapsulating Data

    Designated Initializer 不稳定的传送门 合成属性 Properties don’t always have to be backed by their own instance ...

  6. JavaScript 二、eval 和 with 函数

    /* * ========================================================= * * JavaScript 词法欺骗 * * 1.欺骗词法作用域,会导致 ...

  7. 统计nginx进程占用的物理内存

    #!/usr/bin/env python #-*- coding:utf-8 -*- ''' 统计nginx进程占用的物理内存 ''' import os import sys import sub ...

  8. 第十五篇:使用 FP-growth 算法高效挖掘海量数据中的频繁项集

    前言 对于如何发现一个数据集中的频繁项集,前文讲解的经典 Apriori 算法能够做到. 然而,对于每个潜在的频繁项,它都要检索一遍数据集,这是比较低效的.在实际的大数据应用中,这么做就更不好了. 本 ...

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

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

  10. 7624:山区建小学(划分dp)

    7624:山区建小学 查看 提交 统计 提问 总时间限制: 1000ms 内存限制: 65536kB 描述 政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄 ...