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

今天我们将继续使用canvas来进行HTML5游戏开发系列的文章。这次我准备了一个新游戏,是基于第4篇的游戏,但是增加了火球,敌人和碰撞检测。故,我们的龙可以发射火球来杀死敌人,并且记录分数。这样该游戏就有更多的交互性。

之前的翻译文章可以点击这里:http://www.cnblogs.com/pigzhu/p/3234255.html

第一步:HTML

首先是我们基础的html代码:

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

第二步:CSS

接着这里是CSS样式。

css/main.css

这次依然不打算显示出CSS文件的内容了,因为仅仅只是些页面布局样式。你可以在源代码包里找到该文件。

第三步:JS

js/script.js

 // 内部变量
var canvas, ctx;
var backgroundImage;
var iBgShiftX = 100; var dragon, enemy = null; // 游戏中两个主要实体对象
var balls = [];
var enemies = []; var dragonW = 75; // 龙的宽度
var dragonH = 70; // 龙的高度
var iSprPos = 0; // 初始帧的位置
var iSprDir = 0; // 初始龙的朝向
var iEnemyW = 128; // 敌人的宽度
var iEnemyH = 128; // 敌人的高度
var iBallSpeed = 10; // 火球的速度
var iEnemySpeed = 2; // 敌人的速度 var dragonSound; // 龙的声音
var wingsSound; // 翅膀的声音
var explodeSound, explodeSound2; // 爆炸声音
var laughtSound; // 敌人从左边逃出,嘲笑的声音 var bMouseDown = false; // 鼠标是否按下
var iLastMouseX = 0;
var iLastMouseY = 0;
var iScore = 0;
// ------------------------------------------------------------- // 龙
function Dragon(x, y, w, h, image) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.image = image;
this.bDrag = false;
}
// 球
function Ball(x, y, w, h, speed, image) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.speed = speed;
this.image = image;
}
// 敌人
function Enemy(x, y, w, h, speed, image) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.speed = speed;
this.image = image;
}
// -------------------------------------------------------------
// 获得位于x和y之间的随机数。
function getRand(x, y) {
return Math.floor(Math.random() * y) + x;
} // draw functions :
function drawScene() { // main drawScene function
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // 清除这个画布 // 画背景
iBgShiftX += 4;
if (iBgShiftX >= 1045) {
iBgShiftX = 0;
}
ctx.drawImage(backgroundImage, 0 + iBgShiftX, 0, 1000, 940, 0, 0, 1000, 600); // 更新帧的位置
iSprPos++;
if (iSprPos >= 9) {
iSprPos = 0;
} // 当鼠标被按下,龙朝着鼠标移动
if (bMouseDown) {
if (iLastMouseX > dragon.x) {
dragon.x += 5;
}
if (iLastMouseY > dragon.y) {
dragon.y += 5;
}
if (iLastMouseX < dragon.x) {
dragon.x -= 5;
}
if (iLastMouseY < dragon.y) {
dragon.y -= 5;
}
} // 绘制龙
ctx.drawImage(dragon.image, iSprPos * dragon.w, iSprDir * dragon.h, dragon.w, dragon.h,
dragon.x - dragon.w / 2, dragon.y - dragon.h / 2, dragon.w, dragon.h); // 如果有火球则绘制
if (balls.length > 0) {
for (var key in balls) {
if (balls[key] != undefined) {
ctx.drawImage(balls[key].image, balls[key].x, balls[key].y);
balls[key].x += balls[key].speed; if (balls[key].x > canvas.width) { //超出屏幕,移除
delete balls[key];
}
}
}
} // 如果有敌人则绘制
if (enemies.length > 0) {
for (var ekey in enemies) {
if (enemies[ekey] != undefined) {
ctx.drawImage(enemies[ekey].image, enemies[ekey].x, enemies[ekey].y);
enemies[ekey].x += enemies[ekey].speed; if (enemies[ekey].x < - iEnemyW) { //敌人没有被击中,从左边消失,并发出嘲笑声音
delete enemies[ekey]; laughtSound.currentTime = 0;
laughtSound.play();
}
}
}
} // 检测是否击中敌人
if (balls.length > 0) {
for (var key in balls) {
if (balls[key] != undefined) { if (enemies.length > 0) {
for (var ekey in enemies) {
if (enemies[ekey] != undefined && balls[key] != undefined) {
if (balls[key].x + balls[key].w > enemies[ekey].x && balls[key].y + balls[key].h > enemies[ekey].y
&& balls[key].y < enemies[ekey].y + enemies[ekey].h) {
delete enemies[ekey];
delete balls[key];
iScore++; explodeSound2.currentTime = 0;
explodeSound2.play();
}
}
}
}
}
}
} // 绘制分数
ctx.font = '16px Verdana';
ctx.fillStyle = '#fff';
ctx.fillText('Score: ' + iScore * 10, 900, 580);
ctx.fillText('Plese click "1" to cast fireball', 100, 580); } // ------------------------------------------------------------- // 初始化
$(function(){
canvas = document.getElementById('scene');
ctx = canvas.getContext('2d'); var width = canvas.width;
var height = canvas.height; // 加载背景图片
backgroundImage = new Image();
backgroundImage.src = 'images/hell.jpg';
backgroundImage.onload = function() {
}
backgroundImage.onerror = function() {
console.log('Error loading the background image.');
} //初始化各种声音
dragonSound = new Audio('media/dragon.wav');
dragonSound.volume = 0.9; laughtSound = new Audio('media/laught.wav');
laughtSound.volume = 0.9; explodeSound = new Audio('media/explode1.wav');
explodeSound.volume = 0.9;
explodeSound2 = new Audio('media/explosion.wav');
explodeSound2.volume = 0.9; wingsSound = new Audio('media/wings.wav');
wingsSound.volume = 0.9;
wingsSound.addEventListener('ended', function() { // loop wings sound
this.currentTime = 0;
this.play();
}, false);
wingsSound.play(); // 加载各种图片
var oBallImage = new Image();
oBallImage.src = 'images/fireball.png';
oBallImage.onload = function() { } var oEnemyImage = new Image();
oEnemyImage.src = 'images/enemy.png';
oEnemyImage.onload = function() { } var oDragonImage = new Image();
oDragonImage.src = 'images/dragon.gif';
oDragonImage.onload = function() {
dragon = new Dragon(400, 300, dragonW, dragonH, oDragonImage);
} $('#scene').mousedown(function(e) { // 处理鼠标按下
var mouseX = e.layerX || 0;
var mouseY = e.layerY || 0;
if(e.originalEvent.layerX) { // jquery 1.7之后用下面这种方式
mouseX = e.originalEvent.layerX;
mouseY = e.originalEvent.layerY;
} bMouseDown = true; if (mouseX > dragon.x- dragon.w/2 && mouseX < dragon.x- dragon.w/2 +dragon.w &&
mouseY > dragon.y- dragon.h/2 && mouseY < dragon.y-dragon.h/2 +dragon.h) { dragon.bDrag = true;
dragon.x = mouseX;
dragon.y = mouseY;
}
}); $('#scene').mousemove(function(e) { // 处理鼠标移动
var mouseX = e.layerX || 0;
var mouseY = e.layerY || 0;
if(e.originalEvent.layerX) {
mouseX = e.originalEvent.layerX;
mouseY = e.originalEvent.layerY;
} // 保存上次鼠标的位置
iLastMouseX = mouseX;
iLastMouseY = mouseY; // 执行龙的拖动
if (dragon.bDrag) {
dragon.x = mouseX;
dragon.y = mouseY;
} // 根据鼠标的位置,改变龙的方向
if (mouseX > dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) {
iSprDir = 0;
} else if (mouseX < dragon.x && Math.abs(mouseY-dragon.y) < dragon.w/2) {
iSprDir = 4;
} else if (mouseY > dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) {
iSprDir = 2;
} else if (mouseY < dragon.y && Math.abs(mouseX-dragon.x) < dragon.h/2) {
iSprDir = 6;
} else if (mouseY < dragon.y && mouseX < dragon.x) {
iSprDir = 5;
} else if (mouseY < dragon.y && mouseX > dragon.x) {
iSprDir = 7;
} else if (mouseY > dragon.y && mouseX < dragon.x) {
iSprDir = 3;
} else if (mouseY > dragon.y && mouseX > dragon.x) {
iSprDir = 1;
}
}); $('#scene').mouseup(function(e) { // 处理鼠标释放事件
dragon.bDrag = false;
bMouseDown = false; // play dragon sound
dragonSound.currentTime = 0;
dragonSound.play();
}); $(window).keydown(function(event){ // 按键1,开火
switch (event.keyCode) {
case 49: // '1' key
balls.push(new Ball(dragon.x, dragon.y, 32, 32, iBallSpeed, oBallImage)); // play explode sound #1
explodeSound.currentTime = 0;
explodeSound.play();
break;
}
}); setInterval(drawScene, 30); // loop drawScene // 随机生产出敌人
var enTimer = null;
function addEnemy() {
clearInterval(enTimer); var randY = getRand(0, canvas.height - iEnemyH);
enemies.push(new Enemy(canvas.width, randY, iEnemyW, iEnemyH, - iEnemySpeed, oEnemyImage)); var interval = getRand(5000, 10000);
enTimer = setInterval(addEnemy, interval); // loop drawScene
}
addEnemy();
});

在上面代码的开始处,我增加了两个新对象,球和敌人。每个对象都有他们自己的属性集(比如位置,大小,图片,速度),然后通过‘drawScene’方法来绘制他们,在该方法底部,你可以看到处理球和敌人的碰撞检测代码:

 // 检测是否击中敌人
if (balls.length > 0) {
for (var key in balls) {
if (balls[key] != undefined) { if (enemies.length > 0) {
for (var ekey in enemies) {
if (enemies[ekey] != undefined && balls[key] != undefined) {
if (balls[key].x + balls[key].w > enemies[ekey].x && balls[key].y + balls[key].h > enemies[ekey].y
&& balls[key].y < enemies[ekey].y + enemies[ekey].h) {
delete enemies[ekey];
delete balls[key];
iScore++; explodeSound2.currentTime = 0;
explodeSound2.play();
}
}
}
}
}
}
}

最后,我们通过下面的代码不定时间的增加敌人:

 // 随机生产出敌人
var enTimer = null;
function addEnemy() {
clearInterval(enTimer); var randY = getRand(0, canvas.height - iEnemyH);
enemies.push(new Enemy(canvas.width, randY, iEnemyW, iEnemyH, - iEnemySpeed, oEnemyImage)); var interval = getRand(5000, 10000);
enTimer = setInterval(addEnemy, interval); // loop drawScene
}
addEnemy();

第四步:Custom files

  • images/dragon.gif, images/enemy.png, images/fireball.png, images/hell.jpg

  • media/dragon.wav, media/explode1.wav, media/explosion.wav, media/laught.wav, media/wings.wav

上面所有的文件都在源码包里。

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

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

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-7/ 今天我们将完成我们第一个完整的游戏--打砖块.这次教程中,将 ...

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

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

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

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

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

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

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

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

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

    原文地址:http://www.script-tutorials.com/html5-game-development-lesson-10/ 最后我们将继续使用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. NHibernate初学二之简单执行SQL及HQL、Linq

    上篇文章简单介绍NHibernate之简单增删改查,本文将会简单介绍有关执行NHibernate的SQL.HQL及存储过程: 一:执行SQL语句实例,运用CreateSQLQuery方法 public ...

  2. Windows之Xmanager连接linux打开Oracle视图操作

    前提:安装Xmanager 能够百度Xmanager下载其破解版或者带注冊机的版本号,也能够官网下载.只是须要秘钥(建议下载企业版) 官网下载地址:http://www.netsarang.com/d ...

  3. day01<计算机基础知识&Java语言基础>

    计算机基础知识(计算机概述) 计算机基础知识(软件开发和计算机语言概述) 计算机基础知识(人机交互) 计算机基础知识(键盘功能键和快捷键) 计算机基础知识(如何打开DOS控制台) 计算机基础知识(常见 ...

  4. swift - 将表格滚动条移动到底部

    类似聊天那种效果,最新出现消息后,会自动滚动到表的底部,具体代码实现如下: 1,使用scrollToRow方法: let mySec = 1//最后一个分组的索引(0开始,如果没有分组则为0 let ...

  5. 【RF库Collections测试】Copy Dictionary

    Name: Copy DictionarySource:Collections <test library>Arguments:[ dictionary ]Returns a copy o ...

  6. osgEarth2.8添加模型

    #include <osgEarthDrivers/model_simple/SimpleModelOptions> SimpleModelOptions modelOptions; mo ...

  7. osgEarth2.8加载矢量数据描边效果

    通过修改osgearth自带的agglite插件,实现矢量描边效果,可以自定义描边的颜色和宽度(单位像素) 测试文件osgearth_features.cpp #include <osg/Not ...

  8. ubuntu安装TexturePicker

    TexturePacker网页:https://www.codeandweb.com/texturepackerTexturePacker下载页面:https://www.codeandweb.com ...

  9. WIN10 X64下通过TLS实现反调试

    目录(?)[-] TLS技术简介 1 TLS回调函数 2 TLS的数据结构 具体实现及原理 1 VS2015 X64 release下的demo 2 回调函数的具体实现 21 使用IsDebugger ...

  10. Androidの共享登录之方案研究

    由于最近公司提到了一个需求是,一个应用登录成功了,另一个自动登录. 绞尽脑汁想了好几天,看起来很容易但是想深点就漏洞百出,有的时候代码都写完了测试都成功了突然发现给一个假设就完全失效. 先前几个同事之 ...