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

最后我们将继续使用canvas来进行HTML5游戏开发系列的文章。今天我准备了一个新游戏--SkyWalker。这游戏基本上算是一个射击模拟类型的游戏(有飞机和敌人)。我们的目标是到达终点线。该游戏有几个关键的特征:使用了精灵来处理飞机和爆炸,可以按下多个按键(比如你可以移动飞机的同时发射子弹),a certain level length,增强的碰撞检测(敌人可以撞击飞机),飞机的生命值和获得的分数。

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

第一步:HTML

和往常一样,我们有个基本的html文件:

 <!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="utf-8" />
<title>HTML5 Game Development - Lesson 10 (SkyWalker) | 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 tabindex="0">
<h2>HTML5 Game Development - Lesson 10</h2>
<a href="http://www.script-tutorials.com/html5-game-development-lesson-10/" class="stuts">Back to original tutorial on <span>Script Tutorials</span></a>
</header> <div class="container">
<canvas id="scene" width="700" height="700" tabindex="1"></canvas>
</div>
</body>
</html>

第二步:JS

现在,请在文件夹js中创建一个空文件:“script.js”,并把下面的这些代码粘贴到里面去。我将解释主要的功能。

 //内部变量
var canvas, ctx; //各种图片
var backgroundImage;
var oRocketImage;
var oExplosionImage;
var introImage;
var oEnemyImage; var iBgShiftY = 9300;
var bPause = true; //游戏是否暂停
var plane = null; //飞机
var rockets = []; //子弹对象的数组
var enemies = []; //敌人对象的数组
var explosions = []; //爆炸对象的数组
var planeW = 200; //飞机的宽度
var planeH = 110; //飞机的高度
var iSprPos = 2; //飞机初始帧的位置
var iMoveDir = 0; //移动的方向
var iEnemyW = 128; //敌人的宽度
var iEnemyH = 128; //敌人的高度
var iRocketSpeed =10; //子弹的速度
var iEnemySpeed = 5; //敌人的速度
var pressedKeys = []; //按键的序列
var iScore = 0; //总得分
var iLife = 100; //生命值
var iDamage = 10; //每次敌人碰到飞机的损耗值
var enTimer = null; //产生敌人的定时器 function Plane(x, y, w, h, image) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.image = image;
this.bDrag = false;
} function Rocket(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;
} function Explosion(x, y, w, h, sprite, image) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.sprite = sprite;
this.image = image;
} //得到位于x和y之间的随机数
function getRand(x, y) {
return Math.floor(Math.random() * y) + x;
} //显示游戏介绍界面
function displayIntro() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.drawImage(introImage, 0, 0, 700, 700);
} //绘制主要的场景
function drawScene() {
if (! bPause) {
iBgShiftY -= 2; //主背景向下移动
if (iBgShiftY < 5) {
bPause = true; //绘制分数
ctx.font = '40px Verdana';
ctx.fillStyle = '#fff';
ctx.fillText('Finish, your score: ' + iSore * 10 + ' points', 50, 200);
return;
} //处理按下的建
processPressedKeys(); //清除整个画布
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); //通过剪切图片绘制背景
ctx.drawImage(backgroundImage, 0, 0 + iBgShiftY, 700, 700, 0, 0, 700, 700); //绘制飞机
ctx.drawImage(plane.image, iSprPos * plane.w, 0, plane.w, plane.h,
plane.x - plane.w / 2, plane.y - plane.h / 2, plane.w, plane.h); //绘制子弹
if (rockets.length > 0) {
for (var key in rockets) {
if (rockets[key] != undefined) {
ctx.drawImage(rockets[key].image, rockets[key].x, rockets[key].y);
rockets[key].y -= rockets[key].speed; if (rockets[key].y < 0) { //如果子弹飞出界面,删除掉
delete rockets[key];
}
}
}
} //绘制爆炸
if (explosions.length > 0) {
for (var key in explosions) {
ctx.drawImage(explosions[key].image, explosions[key].sprite * explosions[key].w, 0, explosions[key].w, explosions[key].h,
explosions[key].x - explosions[key].w / 2, explosions[key].y - explosions[key].h / 2,
explosions[key].w, explosions[key].h);
explosions[key].sprite++; if (explosions[key].sprite > 10) { //如果爆炸播放完,则删除掉
delete explosions[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].y -= enemies[ekey].speed;
} if (enemies[ekey].y > canvas.height) { //如果敌人飞出界面,则删除掉
delete enemies;
}
}
} //处理各种碰撞
if (enemies.length > 0) {
for (var ekey in enemies) {
if (enemies[ekey] != undefined) { //子弹打中敌人
if (rockets.length > 0) {
for (var key in rockets) {
if (rockets[key] != undefined && enemies[ekey] != undefined) {
if (rockets[key].y < enemies[ekey].y + enemies[ekey].h / 2
&& rockets[key].x > enemies[ekey].x
&& rockets[key].x + rockets[key].w < enemies[ekey].x + enemies[ekey].w) {
explosions.push(new Explosion(enemies[ekey].x + enemies[ekey].w / 2, enemies[ekey].y + enemies[ekey].h / 2,
120, 120, 0, oExplosionImage)); delete enemies[ekey];
delete rockets[key];
iScore++;
}
}
}
} //敌人打中飞机
if (enemies[ekey] != undefined) {
if (plane.y - plane.h / 2 < enemies[ekey].y + enemies[ekey].h / 2
&& plane.x - plane.w / 2 < enemies[ekey].x + enemies[ekey].w
&& plane.x + plane.w / 2 > enemies[ekey].x) {
explosions.push(new Explosion(enemies[ekey].x + enemies[ekey].w / 2, enemies[ekey].y + enemies[ekey].h / 2,
120, 120, 0, oExplosionImage)); delete enemies[ekey];
iLife -= iDamage; if (iLife <= 0) { //游戏结束
bPause = true; ctx.font = '38px Verdana';
ctx.fillStyle = '#fff';
ctx.fillText('Game voer, your socre: ' + iScore * 10 + ' points', 25, 200);
return;
}
}
} }
}
} //即时显示分数和生命值
ctx.font = '14px Verdana';
ctx.fillStyle = '#fff';
ctx.fillText('life: ' + iLife + ' / 100', 50, 660);
ctx.fillText('Score: ' + iScore * 10, 50, 680);
}
} //处理各种按键事件
function processPressedKeys() {
if (pressedKeys[37] != undefined) {
if (iSprPos > 0) {
iSprPos--;
iMoveDir = -7;
}
if (plane.x - plane.w / 2 > 10) {
plane.x += iMoveDir;
}
} else if (pressedKeys[39] != undefined) {
if (iSprPos < 4) {
iSprPos++;
iMoveDir = 7;
}
if (plane.x + plane.w / 2 < canvas.width - 10) {
plane.x += iMoveDir;
}
}
} //不定时间的增加敌人
function addEnemy() {
clearInterval(enTimer);
var randX = getRand(0, canvas.height - iEnemyH);
enemies.push(new Enemy(randX, 0, iEnemyW, iEnemyH, -iEnemySpeed, oEnemyImage)); var interval = getRand(1000, 4000);
enTimer = setInterval(addEnemy, interval);
} // 主初始化
$(function() {
canvas = document.getElementById('scene');
ctx = canvas.getContext('2d'); //加载背景图片
backgroundImage = new Image();
backgroundImage.src = 'images/levelmap.jpg';
backgroundImage.onload = function() {}
backgroundImage.onerror = function() {
console.log('Error loading the background image.');
} //初始化介绍图片
introImage = new Image();
introImage.src = 'images/intro.jpg'; oRocketImage = new Image();
oRocketImage.src = 'images/rocket.png';
oRocketImage.onload = function(){} oExplosionImage = new Image();
oExplosionImage.src = 'images/explosion.png';
oExplosionImage.onload = function() {} oEnemyImage = new Image();
oEnemyImage.src = 'images/enemy.png';
oEnemyImage.onload = function() {} var oPlaneImage = new Image();
oPlaneImage.src = 'images/plane.png';
oPlaneImage.onload = function() {
plane = new Plane(canvas.width / 2, canvas.height - 100, planeW, planeH, oPlaneImage);
} $(window).keydown(function(evt) { //按下事件处理
var pk = pressedKeys[evt.keyCode];
if (!pk) {
pressedKeys[evt.keyCode] = 1;
} if (bPause && evt.keyCode == 13) { //enter键 开始游戏
bPause = false;
setInterval(drawScene , 30);
addEnemy();
}
}); $(window).keyup(function(evt) { //键释放事件处理
var pk = pressedKeys[evt.keyCode];
if (pk) {
delete pressedKeys[evt.keyCode];
}
if (evt.keyCode == 65) { //'A'键发射子弹
rockets.push(new Rocket(plane.x - 16, plane.y - plane.h, 32, 32, iRocketSpeed, oRocketImage));
}
if (evt.keyCode ==37 || evt.keyCode == 39) {
//左右移动 37 左 39 右 但移动完之后,飞机恢复正常状态
if (iSprPos > 2) {
for (var i = iSprPos; i >= 2; i--) {
iSprPos = i;
iMoveDir = 0;
}
} else {
for (var i = iSprPos; i <= 2; i++) {
iSprPos = i;
iMoveDir = 0;
}
}
}
}); introImage.onload = function() {
displayIntro();
}
});

在主初始化代码中,加载了所有必需的图片资源(level map, 介绍图片,子弹,爆炸,敌人和飞机)。然后,我们使用了数组来处理多个按键事件(在我们渲染主场景的时候,将会使用这个数组来操作我们的飞机),最后,介绍页被加载--显示界面图片。下面是一个重要的代码片段--怎样处理多个按键,请看下面代码:

 var pressedKeys = []; //按键的序列

 $(window).keydown(function (evt){ //鼠标按下事件处理
var pk = pressedKeys[evt.keyCode];
if (! pk) {
pressedKeys[evt.keyCode] = 1; // 把按下的键添加的按键序列中
}
}); $(window).keyup(function (evt) { // 鼠标释放事件处理
var pk = pressedKeys[evt.keyCode];
if (pk) {
delete pressedKeys[evt.keyCode]; // 从按键序列中删除
}
});

这个技术允许我们操作多个按键,在渲染我们主场景时,我们绘制的对象有:背景,飞机,子弹,敌人和爆炸。一旦我们击中敌人,将会在敌人的位置处绘制出爆炸。最后我们的对手是有攻击力的,当他们碰到飞机时,他们会爆炸,同时对飞机造成损伤。如果我们飞机的生命值小于0,则游戏结束。为了实现碰撞和爆炸,我使用了下面的代码:

 if (plane.y - plane.h/2 < enemies[ekey].y + enemies[ekey].h/2 && plane.x - plane.w/2 < enemies[ekey].x + enemies[ekey].w && plane.x + plane.w/2 > enemies[ekey].x) {
explosions.push(new Explosion(enemies[ekey].x + enemies[ekey].w / 2, enemies[ekey].y + enemies[ekey].h / 2, 120, 120, 0, oExplosionImage)); // 删除敌人,并计算损伤
delete enemies[ekey];
iLife -= iDamage; if (iLife <= 0) { // 游戏结束
bPause = true; // 绘制分数
ctx.font = '38px Verdana';
ctx.fillStyle = '#fff';
ctx.fillText('Game over, your score: ' + iScore * 10 + ' points', 25, 200);
return;
}
}

第三步:Custom graphics

enemy.png, explosion.png, intro.jpg, levelmap.jpg, plane.png, rocket.png

上面所有的图片都在源码包里。

结论

你喜欢我们的新SkyWalker游戏吗? 我非常乐意看见你的谢意和评论。好运!

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

  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游戏开发系列教程9(译)

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

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

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

  8. unity3D实际的原始视频游戏开发系列讲座10它《战斗:外来入侵》在第一季度游戏开发

    解说文件夹 <保卫战:异形入侵>游戏开发 第一讲   游戏演示和资源的介绍 第二讲  "异形"怪物的实现 第三讲  "异形"怪物生命值的体现 第四讲 ...

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

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

随机推荐

  1. Linux 远程同步:rsync

    rsync 简介: (1) rsync 是一个远程数据同步工具,可通过 LAN/WAN 快速同步多台主机间的文件(2) rsync 使用所谓的“rsync算法”来使本地和远程两个主机之间的文件达到同步 ...

  2. JavaScript作用域原理——预编译

    JavaScript是一种脚本语言, 它的执行过程, 是一种翻译执行的过程.并且JavaScript是有预编译过程的,在执行每一段脚本代码之前, 都会首先处理var关键字和function定义式(函数 ...

  3. idea & datagrip 注册码

    CNEKJPQZEX-eyJsaWNlbnNlSWQiOiJDTkVLSlBRWkVYIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  4. php学习十四:抽象,接口和多态

    多态为面向对象编程的精华所在,js等面向过程的语言虽然可以模拟面向对象,但是毕竟模仿的永远比不上真的,所以了解而且会使用面向对象的多态是必不可少的 在了解多态之前,我们必须要了解接口,但是接口又是在抽 ...

  5. 使用JS播放声音——SoundManager 2

    <!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>SoundDemo& ...

  6. win8.1rtm专业版无法安装net3.5还有iis

    win8.1rtm专业版无法安装net3.5还有iis错误代码:0x800F0906 已解决:dism.exe /online /enable-feature /featurename:NetFX3 ...

  7. Hibernate(1)——数据访问层的架构模式<转>

    数据库的概念.逻辑.数据模型概念 应用程序的分层体系结构发展 MVC设计模式与四层结构的对应关系 持久层的设计目标 数据映射器架构模式 JDBC的缺点 Hibernate简介 迅速使用Hibernat ...

  8. nohop以及后台运行的相关集合

    本文参考:https://blog.csdn.net/u011095110/article/details/78666833 1. 后台运行一个命令: & tar -czvf /mnt/aa. ...

  9. 【BZOJ2118】墨墨的等式 最短路

    [BZOJ2118]墨墨的等式 Description 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+…+anxn=B存在非负整数解的条件,他要求你编写一个程序,给定N.{an}.以及B的取值 ...

  10. 【BZOJ2007】[Noi2010]海拔 对偶图最短路

    [BZOJ2007][Noi2010]海拔 Description YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作 一个正方形,每一个区域也可看 ...