一、总结关键点和遇到的问题
1.javascript中的继承,最好父类只提供方法共享,属性写到各自子类中,避免父类和子类的构造函数混杂。
2.prototype模拟继承的代码,应写在所有方法定义之前,否则原型对象被改变,方法就变成了未定义,如:
复制代码 代码如下:
Hero.prototype = new Tank (0, 0, 0);
Hero.prototype.constructor = Hero;
Hero.prototype.addLife = function(){
this.lifetimes++;
document.querySelector("#life").innerHTML = hero.lifetimes;
}
3.canvas画图形时,除了画矩形,其他的都要加上 ctx.beginPath();、ctx.closePath();,否则会出现意想不到的错误。
4.concat函数可以合并数组,或者是元素返回一个新的数组
5.Image的src属性赋值后就会加载图片,但如果没有加载完毕就画图片,会导致失效,所以使用onload事件处理
6.扩展Array功能,删除指定元素
复制代码 代码如下:
//扩展 删除指定元素
Array.prototype.deleteElement = function (obj) {
if (obj) {
for (var i = 0; i < this.length; i++) {
if (this[i] === obj) {
this.splice (i, 1);
}
}
}
}
7.定时器设置,setInterval(“fun”,1000)方法的第一个参数,可以是字符串,如"hero.say()",类似eval会去执行这串代码,所以它可以给函数带上参数,并且也指定了这个函数的运行上下文。但如果传入是函数的句柄,则不能带参数,并且不能指定上下文,除了第一种方式解决外,我用了闭包来解决这个问题
复制代码 代码如下:
//定时器,自行运动
this.timer = setInterval ((function (context) {
return function () {
Bullet.prototype.move.call (context)
}
}) (this), 30);
我保存了当前的执行环境,并调用call方法手动执行。
8.方法的功能设计,除了功能外,应该包括执行此功能的条件检测,如move,就应该包括什么情况下可以移动,移动到什么地方就不能移动了。此检测不应该放在外部。
9.写代码时不应该去想设计或者优化的问题,先实现功能,再谈优化,或者先设计再实现。思路要清晰,别混乱,着重于一点。
10.javascript中没有sleep的功能,可以创建一个变量作为缓冲,来达到间隔执行的目的
二、代码实现
1.本程序分为Bomb.js,Bullet.js,Draw.js,Tank.js,index.html,img,music,
2.最终效果
3.代码
1.index.html
复制代码 代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
<style type="text/css">
body {
font: 14px "sans-serif"
}
#Map {
background-color: #000000;
}
.show {
float: left
}
#guide {
float: left;
width: 200px;
height: 390px;
margin-left: 5px;
background: #CCCCCC;
padding: 5px;
}
</style>
<script type="text/javascript" src="https://www.jb51.net/Tank.js"></script>
<script type="text/javascript" src="https://www.jb51.net/Bullet.js"></script>
<script type="text/javascript" src="https://www.jb51.net/Bomb.js"></script>
<script type="text/javascript" src="https://www.jb51.net/Draw.js"></script>
<script type="text/javascript">
window.onload = function () {
//画布信息
width = document.getElementById ('Map').width;
height = document.getElementById ('Map').height;
ctx = document.getElementById ('Map').getContext ('2d');
//初始页面
var starImg = new Image ();
starImg.src = "img/star.jpg";
starImg.onload = function () {
ctx.drawImage (starImg, 0, 0, width, height);
}
//键盘监听 回车开始游戏
document.body.onkeydown = function () {
var keycode = event.keyCode;
switch (keycode) {
case 13:
//初始化参数
init ()
//刷新页面
setInterval (draw, 30);
document.body.onkeydown = gameControl;
break;
}
}
}
function init () {
//玩家和电脑
hero = new Hero (100, 300, 0);
enemys = [];
for (var i = 0; i < 3; i++) {
enemys.push (new Enemy (100 + i * 50, 0, 2));
}
//合并数组
allTank = enemys.concat (hero);
//炸弹
Bombs = [];
im = new Image ();
im2 = new Image ();
im3 = new Image ();
im.src = "img/bomb_3.gif";
im2.src = "img/bomb_2.gif";
im3.src = "img/bomb_1.gif";
}
function gameControl () {
var keycode = event.keyCode;
switch (keycode) {
case 65:
hero.moveLeft ();
break;//左
case 83:
hero.moveDown ();
break;//下
case 87:
hero.moveUp ();
break;//上
case 68:
hero.moveRight ();
break;//右
case 74:
hero.shot ();
break;
case 49:
hero.addLife ()
break;
}
}
//扩展 删除指定元素
Array.prototype.deleteElement = function (obj) {
if (obj) {
for (var i = 0; i < this.length; i++) {
if (this[i] === obj) {
this.splice (i, 1);
}
}
}
}
</script>
</head>
<body>
<div>
<canvas>
</canvas>
<audio autoplay="autoplay">
<source src="https://www.jb51.net/music/111.wav">
</audio>
</div>
<div>
<p>按下回车键开始游戏</p>
<p>按下1键增加生命,默认是1</p>
<p>剩余生命数 :<label>1</label></p>
<div>
</div>
</div>
</body>
</html>
2.Draw.js
复制代码 代码如下: