<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>经典的坦克大战</title>
</head>
<body onkeydown="getCommand();" style="text-align:center" >
<h1>Html5经典的坦克大战</h1>
<!-- 坦克大战的战场 -->
<canvas id="tankMap" width="600px" height="500px" style="background-color:Black"></canvas>
<script src="js/tank.js" type="text/javascript"></script>
<script type="text/javascript">
//得到画布
var canvas = document.getElementById("tankMap");
//得到画笔
var cxt = canvas.getContext("2d");
//我的坦克(坦克的基准点)
//方向 0表示向上,1表示向右,2表示像下,3表示向左
var myTank = new MyTank(300, 400, 0,myTankColor);
//定义子弹数组
var myBullets = new Array();
//定义敌人的坦克
var enemyTanks = new Array();
//定义敌人子弹的数组
var enemyBullets = new Array();
//定义一个炸弹数组(可以存放很多炸弹)
var bombs = new Array();
//先定义三个,后面把敌人坦克的数量,作出变量
//0->上,1->右,2->下,3->左
for (var i = 0; i < 3; i++) {
//创建一个坦克
var enemyTank = new EnemyTank((i + 1) * 50, 3, 2, enemyColor);
//把这个坦克放入数组
enemyTanks[i] = enemyTank;
//启动这个敌人的坦克
window.setInterval("enemyTanks[" + i + "].run()", 50);
//当创建敌人坦克时就会分配子弹,子弹速度为3
var eb = new Bullet(enemyTanks[i].x + 9, enemyTanks[i].y + 30, 2, 3, "enemy", enemyTanks[i]);
enemyBullets[i] = eb;
//启动该子弹
var ettimer = window.setInterval("enemyBullets[" + i + "].run()", 50);
enemyBullets[i].timer = ettimer;
}
//先调用一次
flashTankMap();
//专门写一个函数,用于定时刷新我们的作战区,把要在作战区出现的元素(子弹,坦克,障碍物等绘制出来)
function flashTankMap() {
//把画布清理
cxt.clearRect(0, 0, 600, 500);
//我的坦克
drawTank(MyTank);
//画出自己的子弹
//子弹飞的效果原理是,每隔一段时间setInterval就去刷新工作区
drawMyBullet();
//敌人的坦克
//判断一下敌人的坦克是否被击中
isHitEnemyTank();
drawEnemyBomb();
drawEnemyBullet();
//画出所有敌人的坦克
for(var i=0;i<3;i++) {
drawTank(enemyTanks[i]);
}
}
//绘制坦克
drawTank(myTank);
//判断键盘按键
function getCommand() {
//说明当时按下的是什么键,-->event对象-->事件处理函数
var code = event.keyCode; //对应字母的ascii码
switch (code) {
case 87: //W
myTank.MoveUp();
break;
case 68: //D
myTank.MoveRight();
break;
case 65: //A
myTank.MoveLeft();
break;
case 83: //S
myTank.MoveDown();
break;
case 74:
myTank.shotEnemy();
break;
}
//触发这个函数flashTankMap();
flashTankMap();
//清理画布
// cxt.clearRect(0, 0, 600, 500); //重绘画布
// //清理过后重新绘制
// drawTank(myTank);
window.setInterval("flashTankMap()",100);
}
</script>
</body>
</html>
js:
//定义两个颜色数组
var myTankColor = new Array("#F0C970", "#FCD152");
var enmeyColor = new Array("#00A2B5", "#00FEFE");
//定义一个炸弹类
function Bomb(x, y) {
this.x = x;
this.y = y;
this.isLive = true; //炸弹是否是活的,默认为true;
this.blood = 9; //炸弹生命值
this.bloodDown = function () {
if (this.bood > 0) {
this.blood--;
}
else {
this.isLive = false; //说明炸弹死亡
}
}
}
//子弹类
//type表示区分是别人的子弹,还是自己的子弹
//tank表示对象,说明这可子弹是属于哪个坦克
function Bullet(x, y, direct, speed, type, tank) {
this.x = x;
this.y = y;
this.direct = direct;
this.speed = speed;
this.timer = null;
this.isLive = null;
this.type = type;
this.tank = tank;
this.run = function () {
//先判断字段是否已经碰到边界
//子弹不前进,有两个逻辑,1.碰到边界,2.碰到敌人的坦克
if (this.x <= 0 || this.x >= 600 || this.y <= 0 || this.y >= 500 || this.isLive == false) {
//子弹要停止
window.clearInterval(this.timer);
//子弹死亡
this.isLive = false;
if (this.type == "enemy") {
this.tank.bulletIsLive = false;
}
else {
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;
}
}
document.getElementById("aa").innerText = "子弹x=" + this.x + "子弹y=" + this.y;
}
}
}
//坦克类
function Tank(x, y, direct,color) {
this.x = x;
this.y = y;
this.direct = direct;
this.isLive = true;
this.color = color;//一个坦克需要两种颜色
this.speed = 3; //默认速度为1
//上移
this.MoveUp = function () {
this.y -= this.speed;
this.direct = 0;
}
//下移
this.MoveDown = function () {
this.y += this.speed;
this.direct = 2;
}
//左移
this.MoveLeft = function () {
this.x -= this.speed;
this.direct = 3;
}
//右移
this.MoveRight = function () {
this.x += this.speed;
this.direct = 1;
}
}
//定义我的坦克
function MyTank(x, y, direct, color) {
//下面两句话是通过对象冒充,达到继承的效果
this.tank = Tank;
this.tank(x, y, direct, color);
//增加一个函数,射击敌人的坦克
this.shotEnemy = function () {
//创建子弹,子弹的位置和自己坦克的位置有关系,并且和方向有关
//this.x就是当前坦克的横坐标
switch (this.direct) {
case 0: //上
myBullet = new Bullet(this.x + 15, this.y + 2, this.direct, 1, "hero", this);
break;
case 1: //右
myBullet = new Bullet(this.x + 28, this.y + 15, this.direct, 1, "hero", this);
case 2: //下
myBullet = new Bullet(this.x + 15, this.y + 28, this.direct, 1, "hero", this);
break;
case 3: //左
myBullet = new Bullet(this.x + 2, this.y + 15, this.direct, 1, "hero", this);
}
//把这个子弹对象放入到数组中->push函数
myBullets.push(myBullet);
//调用我们的子弹run
//每个子弹的定时器是独立,如果按原来的方法
//则所有的子弹共享一个定时器
var timer = window.setInterval("myBullets[" + (myBullets.length - 1) + "].run()", 50);
//把这个timer赋给每一个子弹(js对象是引用传递)
myBullets[myBullets.length - 1].timer = timer;
}
}
//定义一个EnemyTank类
function EnemyTank(x,y,direct,color) {
//也通过对象来冒充,来继承Tank
this.tank = Tank;
this.count = 0;
this.bulletIsLive = true;
this.tank(x, y, direct, color);
this.run = function () {
//判断敌人的坦克的前进方向
switch (this.direct) {
case 0:
if (this.y > 0) {
this.y -= this.speed;
}
break;
case 1:
if (this.x + 30 < 500) {
this.x += this.speed;
}
break;
case 2:
if (this.y + 30 < 600) {
this.y += this.speed;
}
break;
case 3:
if (this.x > 0) {
this.x -= this.speed;
}
break;
}
//改变方向,走三十次,在改变方向
if (this.count > 30) {
//math.round返回的是最接近的整数,math.random产生0.1-1.0之间的数
this.direct = Math.round(Math.random() * 3); //随机生成0,1,2,3
this.count = 0;
}
this.count++;
//判断子弹是否已经死亡,如果死亡,则增加新的一颗子弹
if(this.bulletIsLive==false) {
switch(this.direct){
//重新产生子弹的时候需要考虑当前坦克的状态
case 0: //上
etBullet = new Bullet(this.x + 15, this.y + 2, this.direct, 1, "hero", this);
break;
case 1: //右
etBullet = new Bullet(this.x + 28, this.y + 15, this.direct, 1, "hero", this);
break;
case 2: //下
etBullet = new Bullet(this.x + 15, this.y + 28, this.direct, 1, "hero", this);
break;
case 3: //左
etBullet = new Bullet(this.x + 2, this.y + 15, this.direct, 1, "hero", this);
break;
}
//把子弹添加到敌人子弹数组中
enemyBullets.push(etBullet);
//启动新子弹run
var mytimer=window.setInterval("enemyBullets["+(enemyBullets.lendth-1)+"].run()",50);
enemyBullets[enemyBullets.length-1].timer=mytimer;
this.bulletIsLive=true;
}
}
}
//画自己的子弹,要把这个函数封装到myTank类中
function drawMyBullet() {
//现在要画出所有的子弹
for(var i=0;i<myBullets.length;i++)
{
var myBullet=myBullets[i];
if(myBullet!=null&&myBullet.isLive)
{
cx.fillStyle="#FEF26E";
cxt.fillRect(myBullet.x,myBullet.y,2,2);
}
}
}
//画敌人的子弹,当然敌人的子弹和自己的子弹可以合并
function drawEnemyBullet()
{
//现在要画出所有子弹
for(var i=0;i<enemyBullets.length;i++)
{
var etBullet=enemyBullets[i];
if(etBullet.isLive)
{
cxt.fillStyle="#00FEFE";
cxt.fillRect(etBullet.x,etBullet.y,2,2);
}
}
}
//绘制坦克(敌人和自己的坦克)
//把绘制坦克封装成一个函数,将来可以作为成员函数
function drawTank(tank) {
//说明所有的坦克都要isLive这个属性
if(tank.isLive)
{
//考虑方向
switch (tank.direct) {
case 0: //上
case 2: //下
//使用自己的坦克,使用绘图技术
//设置颜色
cxt.fillStyle = tank.color[0];
//坦克
cxt.fillRect(tank.x, tank.y, 5, 30); //左轮
cxt.fillRect(tank.x + 5, tank.y + 7, 16, 16); //坦克身
cxt.fillRect(tank.x + 5 + 16, tank.y, 5, 30); //右轮
//画一个盖子(内圆)
cxt.beginPath();
cxt.fillStyle = tank.color[1];
cxt.arc(tank.x + 5 + 8, tank.y + 7 + 8, 8, 0, 360, true); //(x,y,r,开始角度,结束角度,是否顺时针)
cxt.closePath();
//填充实心的圆形
cxt.fill();
//设置线条的宽度
cxt.lineWidth = 4;
cxt.beginPath();
cxt.moveTo(tank.x + 13, tank.y + 15);
//炮筒
//cxt.fillRect(tank.x + 5 + 6, tank.y + 2, 4, 5);
cxt.strokeStyle = tank.color[1];
if (tank.direct == 0) {
cxt.lineTo(tank.x + 13, tank.y + 2);
} else if (tank.direct == 2) {
cxt.lineTo(tank.x + 13, tank.y + 28);
}
cxt.closePath();
cxt.stroke();
break;
//左和右
case 1:
case 3:
//画出自己的坦克,使用前面的绘图技术
//设置颜色
cxt.fillStyle = tank.color[0];
//韩老师使用 先死--->后活 (初学者最好用这个方法)
//先画出右面的矩形
cxt.fillRect(tank.x, tank.y, 30, 5);
//画出左边的矩形
cxt.fillRect(tank.x, tank.y + 21, 30, 5);
//画出中间矩形
cxt.fillRect(tank.x + 7, tank.y + 5, 16, 16);
//画出坦克的盖子
cxt.fillStyle = tank.color[1];
cxt.arc(tank.x + 15, tank.y + 13, 8, 0, 360, true);
cxt.fill();
//画出炮筒(直线)
cxt.strokeStyle = tank.color[1];
//设置线条的宽度
cxt.lineWidth = 4;
cxt.beginPath();
cxt.moveTo(tank.x + 15, tank.y + 13);
//向右
if (tank.direct == 1) {
cxt.lineTo(tank.x + 28, tank.y + 13);
} else if (tank.direct == 3) { //向左
cxt.lineTo(tank.x + 2, tank.y + 13);
}
cxt.closePath();
cxt.stroke();
break;
}
}
}
//编写一个函数,专门用于判断我的子弹,是否集中某个敌人的坦克
function isHitEnemyTank() {
//取出每一颗子弹
for(var i=0;i<myBullets.length;i++)
{
//取出每一颗子弹
var myBullet=myBullets[i];
if(heroBullet.isLive) //子弹是活的,才去判断
{
//让这颗子弹去和遍历每个敌人坦克判断
for(var j=0;j<enemyTanks.length;j++)
{
var enemyTank=enemyTanks[j];
//子弹集中敌人坦克的条件是什么?
//看这颗子弹是否进入敌人坦克所在的矩形
//根据当时敌人坦克的方向来决定
if(enemyTank.isLive)
{
switch(enemytank.direct)
{
case 0:
case 2:
if(myBullet.x>=enemyTank.x&&myBullet.x<=enemyTank.x+26&&myBullet.y>=enemyTank.y&&myBullet.y<=enemyTank.y+30)
{
//把坦克isLive设置为false,表示死亡
enemyTank.isLive=false;
//该子弹也死亡
myBullet.isLive=false;
//创建一颗炸弹
var bomb=new Bomb(enemyTank.x,enemyTank.y);
//然后把该炸弹放入到booms数组中
bombs.push(bomb);
}
break;
case 1:
case 3://左右方向
if(myBullet.x>=enemyTank.x&&myBullet.x<=enemyTank.x+30&&myBullet.y>=enemyTank.y&&myBullet.y<=enemyTank.y+26)
{
//把坦克isLive设置为false,表示死亡
enemyTank.isLive=false;
//该子弹也死亡
myBullet.isLive=false;
//创建一颗炸弹
var bomb=new Bomb(enemyTank.x,enemyTank.y);
//然后把该炸弹放入到booms数组中
bombs.push(bomb);
}
break;
}
}
}
}
}
}
//画出敌人的炸弹
function drawEnemyBomb() {
for(var i=0;i<bombs.length;i++)
{
//取出一颗炸弹
var bomb=bombs[i];
if(bomb.isLive)
{
//根据当前这个炸弹的生命值,来画出不同的炸弹图片
if(bomb.blood>6)
{
//显示最大炸弹图
var img1=new Image();
img1.src="imgs/bomb_1.gif";
var x=bombs.x;
var y=bombs.y;
img1.onload=function () {
cxt.drawImage(img1,x,y,30,30);
}
}
else if(bomb.blood>3)
{
//显示中等炸弹图
var img3=new Image();
img3.src="imgs/bomb_2.gif";
var x=bombs.x;
var y=bombs.y;
img2.onload=function () {
cxt.drawImage(img1,x,y,30,30);
}
}
else
{
//显示最小炸弹图
var img3=new Image();
img3.src="imgs/bomb_3.gif";
var x=bombs.x;
var y=bombs.y;
img3.onload=function () {
cxt.drawImage(img1,x,y,30,30);
}
}
//减血
bomb.bloodDown();
if(bomb.blood<=0)
{
//把这个炸弹从数组中去掉
bombs.splice(i,1);
}
}
}
}