一、总结关键点和遇到的问题
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;
}
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);
}
}
}
}
//定时器,自行运动
this.timer = setInterval ((function (context) {
return function () {
Bullet.prototype.move.call (context)
}
}) (this), 30);
8.方法的功能设计,除了功能外,应该包括执行此功能的条件检测,如move,就应该包括什么情况下可以移动,移动到什么地方就不能移动了。此检测不应该放在外部。
9.写代码时不应该去想设计或者优化的问题,先实现功能,再谈优化,或者先设计再实现。思路要清晰,别混乱,着重于一点。
10.javascript中没有sleep的功能,可以创建一个变量作为缓冲,来达到间隔执行的目的
二、代码实现
1.本程序分为Bomb.js,Bullet.js,Draw.js,Tank.js,index.html,img,music,
2.最终效果
3.代码
1.index.html
按下回车键开始游戏
按下1键增加生命,默认是1
剩余生命数 :
/**
* Created by Alane on 14-3-18.
*/
function draw(){
//检测子弹和坦克生死
checkDead();
//清空画布
ctx.clearRect(0,0,500,400);
//画玩家
if(!hero.isdead){
drawTank(hero);
}else{
hero.cutLife();
}
//画敌人坦克
for (var i = 0; i < enemys.length; i++) {
drawTank(enemys[i]);
}
//画敌人子弹
for(var j=0;j8){
ctx.drawImage(im,obj.x,obj.y,50,50);
}else if(obj.life>4){
ctx.drawImage(im2,obj.x,obj.y,50,50);
}else{
ctx.drawImage(im3,obj.x,obj.y,50,50);
}
obj.lifeDown();
if(obj.life<=0){
Bombs.deleteElement(obj);
}
}
function checkDead(){
//检测敌人子弹生死
for(var j=0;j
/**
* Created by Alane on 14-3-18.
*/
function Bomb(x,y){
this.life = 12;
this.x = x;
this.y = y;
}
Bomb.prototype.lifeDown = function(){
this.life--;
}
/**
* Created by Alane on 14-3-7.
*/
/**
* direct 0 上
* 1 右
* 2 下
* 3 左
* @param x
* @param y
* @param direct
* @constructor
*/
//******************************************************************************************/
//坦克父类
function Tank (x, y, direct) {
this.speed = 2;
}
Tank.prototype.moveUp = function () {
//边界检测
if (this.y < 0) {
//换方向
this.changeDirect ();
return;
}
this.y -= this.speed;
this.direct = 0;
}
Tank.prototype.moveDown = function () {
if (this.y > height - 30) {
this.changeDirect ();
return;
}
this.y += this.speed;
this.direct = 2;
}
Tank.prototype.moveLeft = function () {
if (this.x < 0) {
this.changeDirect ();
return;
}
this.x -= this.speed;
this.direct = 3;
}
Tank.prototype.moveRight = function () {
if (this.x > width - 30) {
this.changeDirect ();
return;
}
this.x += this.speed;
this.direct = 1;
}
//变换方向
Tank.prototype.changeDirect = function () {
while (true) {
var temp = Math.round (Math.random () * 3);
if (this.direct != temp) {
this.direct = temp;
break;
}
}
//alert("x="+this.x+" y="+this.y+" direct="+this.direct)
}
//射击子弹
Tank.prototype.shot = function () {
if(this.isdead){
return;
}
if (this.bulletsList.length < this.maxBulletSize) {
//新建子弹
var bullet = null;
switch (this.direct) {
case 0:
bullet = new Bullet (this.x + 10, this.y - 2, 0, this.color);
break;
case 1:
bullet = new Bullet (this.x + 32, this.y + 10, 1, this.color);
break;
case 2:
bullet = new Bullet (this.x + 10, this.y + 32, 2, this.color);
break;
case 3:
bullet = new Bullet (this.x - 2, this.y + 10, 3, this.color);
break;
}
//放入弹夹
this.bulletsList.push (bullet);
}
}
//******************************************************************************************/
//玩家
function Hero (x, y, direct) {
this.lifetimes = 5;
this.isdead = false;
this.color = '#FF0000';
this.x = x;
this.y = y;
this.direct = direct;
this.bulletsList = [];
this.maxBulletSize = 10;
this.newlife = null;
}
Hero.prototype = new Tank (0, 0, 0);
Hero.prototype.constructor = Hero;
Hero.prototype.addLife = function(){
this.lifetimes++;
document.querySelector("#life").innerHTML = hero.lifetimes;
}
Hero.prototype.cutLife = function(){
if(this.lifetimes>=1 && !this.newlife){
this.lifetimes--;
this.newlife = setTimeout("hero.newLife()",2000);
}
}
Hero.prototype.newLife = function(){
this.isdead = false;
clearTimeout(hero.newlife);
hero.newlife = null;
document.querySelector("#life").innerHTML = hero.lifetimes;
}
//******************************************************************************************/
//敌人坦克
function Enemy (x, y, direct) {
this.isdead = false;
this.color = 'blue';
this.x = x;
this.y = y;
this.direct = direct;
this.bulletsList = [];
this.maxBulletSize = 1;
//定时器,自动移动
this.timer1 = setInterval ((function (context) {
return function () {
//移动
Enemy.prototype.move.call (context);
}
}) (this), 30);
//定时器,射击
this.timer2 = setInterval ((function (context) {
return function () {
//射击
Tank.prototype.shot.call (context);
}
}) (this), 2000);
//定时器,变换方向
this.timer3 = setInterval ((function (context) {
return function () {
//射击
Tank.prototype.changeDirect.call (context);
}
}) (this), 3000);
}
Enemy.prototype = new Tank (0, 0, 0);
Enemy.prototype.constructor = Enemy;
Enemy.prototype.move = function () {
switch (this.direct) {
case 0:
this.moveUp ();
break;
case 1:
this.moveRight ();
break;
case 2:
this.moveDown ();
break;
case 3:
this.moveLeft ();
break;
}
}
/**
* Created by Alane on 14-3-11.
*/
function Bullet (x, y, direct, color) {
this.isdead = false;
this.x = x;
this.y = y;
this.direct = direct;
this.speed = 4;
this.color = color;
//定时器,自行运动
this.timer = setInterval ((function (context) {
return function () {
Bullet.prototype.move.call (context)
}
}) (this), 30);
}
Bullet.prototype.move = function () {
switch (this.direct) {
case 0:
this.y -= this.speed;
break;
case 1:
this.x += this.speed;
break;
case 2:
this.y += this.speed;
break;
case 3:
this.x -= this.speed;
break;
}
//边界检测
if (this.y < 0 || this.x > width || this.y > height || this.x < 0) {
clearInterval (this.timer);
this.isdead = true;
}
//碰撞检测 检测敌人坦克
for(var i=0;itemp.x && this.xtemp.y&& this.ytemp.x && this.xtemp.y&& this.y
提取码:ix9t