JavaScript 坦克大战
界面预览
在线体验
需求分析
- 双人游戏,两套按键分别控制两辆坦克
- 坦克四个方向移动,并且调整坦克朝向
- 边缘检测,坦克只能在地图里面移动
- 发射子弹,四个方向都能发射子弹
- 子弹边缘检测
- 子弹碰撞检测,子弹碰到地形,子弹与地形消失
- 子弹碰到敌方坦克游戏结束
- 生成随机地形,并且限制坦克移动
页面结构与布局
<div class="wrap">
<div class="tan red">
<img src="./image/坦克.jpg" alt="">
</div>
<div class="tan blue">
<img src="./image/坦克.jpg" alt="">
</div>
</div>
* {
margin: 0;
padding: 0;
}
.wrap {
width: 640px;
height: 640px;
border: 1px #ccc solid;
margin: auto;
position: relative;
}
.tan {
width: 40px;
height: 40px;
position: absolute;
box-sizing: border-box;
}
.tan img {
display: block;
width: 40px;
height: 40px;
}
.red {
bottom: 0px;
right: 0px;
border: 1px red solid;
}
.blue {
top: 0px;
left: 0px;
border: 1px blue solid;
}
span {
width: 10px;
height: 10px;
border-radius: 50%;
position: absolute;
background-color: brown;
}
.wall {
position: absolute;
background-color: brown;
width: 40px;
height: 40px;
}
li {
top: 0;
left: 80px;
position: absolute;
list-style: none;
}
地形类
class Wall {
constructor() {
this.init()
}
init() {
this.col = [];
this.row = [];
for (var i = 1, n = 15; i < n; i++) {
this.col.push(i);
this.row.push(i);
};
for (var i = 0; i < 14; i++) {
let rowIndex = randomInt(0, this.row.length - 1)
let colIndex = randomInt(0, this.col.length - 1)
$(`<div class="wall" style="top:${this.row[rowIndex]*40}px; left:${this.col[colIndex]*40}px"></div>`)
.appendTo('.wrap');
this.row.splice(rowIndex, 1);
this.col.splice(colIndex, 1);
};
}
}
子弹类
在定义子弹类之前需要实例化地形,
let wall = new Wall()
let wallArr = [...$('.wall')]
class Bullet {
constructor(x, y, direction, target) {
this.init(x, y, direction, target);
}
init(x, y, direction, target) {
this.x = x;
this.y = y;
this.direction = direction;
this.ele = $('<span></span>')
this.initBullet();
this.wrap = $('.wrap');
this.target = target
}
initBullet() { //初始化子弹坐标
if (tag) {
return
}
this.ele.css('left', this.x + 'px');
this.ele.css('top', this.y + 'px');
$('.wrap').append(this.ele);
this.move();
}
move() { //子弹移动
if (tag) {
return
}
this.timer = setInterval(() => {
switch (this.direction) {
case 'top':
this.y -= 6;
break;
case 'left':
this.x -= 6;
break;
case 'right':
this.x += 6;
break;
case 'bottom':
this.y += 6;
break;
}
if (tag) {
clearInterval(this.timer);
return
}
this.collision()
this.edge();
this.ele.css('left', this.x + 'px');
this.ele.css('top', this.y + 'px');
}, 20)
}
edge() { //边缘检测
if (this.x <= 0 || this.y <= 0 || (this.x >= this.wrap.width() - 10) || (this.y >= this.wrap
.height() - 10)) {
this.ele.remove();
clearInterval(this.timer);
return;
}
}
collision() { //碰撞检测
//
wallArr.forEach(item => {
if (parseInt(this.x / 40) == parseInt(item.offsetLeft / 40) && parseInt(this.y / 40) ==
parseInt(item.offsetTop / 40)) {
this.ele.remove();
$(item).remove()
clearInterval(this.timer);
}
})
if (!((this.x < this.target.offsetLeft) || (this.x > this.target.offsetLeft + 40) || this.y < this
.target.offsetTop || (this.y > this.target.offsetTop + 40))) {
this.ele.remove();
$(this.target).remove();
clearInterval(this.timer);
alert('游戏结束')
$('span').remove();
tag = true;
return;
}
}
}
坦克类
class Tank {
constructor(ele, myKeyCode) {
this.tank = ele;
this.init(myKeyCode);
}
init(myKeyCode) { //初始化坦克
this.keyDown(myKeyCode);
this.x = this.tank[0].offsetLeft;
this.y = this.tank[0].offsetTop;
this.wrap = $('.wrap');
this.direction = 'top';
this.fire(myKeyCode);
this.target = this.tank.siblings('.tan')[0];
}
keyDown(myKeyCode) { //绑定移动事件,控制方向
var that = this
$(document).keyup(function (e) {
switch (e.keyCode) {
case myKeyCode.top:
that.direction = 'top';
break;
case myKeyCode.right:
that.direction = 'right';
break;
case myKeyCode.bottom:
that.direction = 'bottom';
break;
case myKeyCode.left:
that.direction = 'left';
break;
default:
return;
}
that.move()
})
}
move() { //根据方向移动坦克,调整坦克方向
if(this.check()){
return
}
switch (this.direction) {
case 'top':
this.y -= 40;
this.y = this.check()?this.y+40:this.y
this.tank.css('transform', 'rotateZ(0deg)')
break;
case 'left':
this.x -= 40;
this.x = this.check()?this.x+40:this.x
this.tank.css('transform', 'rotateZ(-90deg)')
break;
case 'right':
this.x += 40;
this.x = this.check()?this.x-40:this.x
this.tank.css('transform', 'rotateZ(90deg)')
break;
case 'bottom':
this.y += 40;
this.y = this.check()?this.y-40:this.y
this.tank.css('transform', 'rotateZ(180deg)')
break;
}
this.edge();
this.check();
this.tank.css('left', this.x + 'px');
this.tank.css('top', this.y + 'px');
}
check() {
return wallArr.some(item => (Math.ceil(this.x / 40) === Math.ceil(item.offsetLeft / 40) && Math.ceil(this.y / 40) ===
Math.ceil(item.offsetTop / 40))
)
}
edge() { //边缘检测
if (this.x <= 0) {
this.x = 0;
}
if (this.x >= this.wrap.width() - 40) {
this.x = this.wrap.width() - 40;
}
if (this.y <= 0) {
this.y = 0;
}
if (this.y >= this.wrap.height() - 40) {
this.y = this.wrap.height() - 40;
}
}
fire(myKeyCode) { //开火
var that = this
$(document).keyup(function (e) {
if (e.keyCode === myKeyCode.send) {
switch (that.direction) {
case 'top':
new Bullet((that.x + 15), that.y, that.direction, that.target)
break;
case 'left':
new Bullet(that.x, (that.y + 15), that.direction, that.target)
break;
case 'right':
new Bullet((that.x + 40), (that.y + 15), that.direction, that.target)
break;
case 'bottom':
new Bullet((that.x + 15), (that.y + 40), that.direction, that.target)
break;
}
}
return
})
}
}
初始化游戏
$(document).on('mousemove', function (e) {
e.preventDefault()
})
new Tank($('.blue'), {
top: 87,
right: 68,
bottom: 83,
left: 65,
send: 69
})
new Tank($('.red'), {
top: 38,
right: 39,
bottom: 40,
left: 37,
send: 96
})
alert(`蓝色方:W,D,S,A分别对应上右下左,E发射子弹
红色方:方向键控制方向,数字小键盘0发射子弹`)