<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.box {
width: 940px;
height: 500px;
border: 1px solid #000;
margin: 50px auto;
position: relative;
/* cursor: none; */
}
.block {
position: absolute;
top: 0;
left: 0;
width: 94px;
height: 36px;
background: url(img/block.png);
}
.ball {
position: absolute;
width: 27px;
height: 27px;
background: url(img/ball.png);
}
.racket {
position: absolute;
width: 179px;
height: 37px;
background: url(img/racket.png);
top: 450px;
left: 10px;
}
</style>
</head>
<body>
<div class="box" id="box">
<div class="ball" id="ball"></div>
<div class="racket" id="racket"></div>
</div>
</body>
<script>
// 获取dom对象
var box = document.getElementById('box');
var ball = document.getElementById('ball');
var racket = document.getElementById('racket');
// 面向对象的思维挡板,小球,地图,碰撞块,大盒子都可以是一个类
// 创建碰撞块类
function Block(left, top, color) {
this.top = top;
this.left = left;
this.width = 94;
this.height = 36;
this.color = color;
this.alive = true;
this.init();
}
// 块类有一个初始化方法
Block.prototype.init = function() {
this.dom = document.createElement('div');
this.dom.className = 'block';
box.appendChild(this.dom);
this.render();
}
// 块类有一个渲染方法
Block.prototype.render = function() {
this.dom.style.top = this.top + 'px';
this.dom.style.left = this.left + 'px';
this.dom.style.backgroundPosition = -this.color * this.width + 'px 0';
};
// 我们的block也要有碰撞检测,当被小球撞到时消失,并且反弹小球
Block.prototype.check = function() {
// 上边界检测
if (b.top >= this.top - b.d && b.top <= this.top && b.left >= this.left - b.d && b.left <= this.left + this.width) {
b.deltaY *= -1;
this.hide();
return true;
// 下边界检测
} else if (b.top <= this.top + this.height && b.top >= this.top && b.left >= this.left - b.d && b.left <= this.left + this.width) {
b.deltaY *= -1;
this.hide();
return true;
// 左边界检测
} else if (b.left >= this.left - b.d && b.left <= this.left && b.top >= this.top && b.top <= this.top + this.height) {
b.deltaX *= -1;
this.hide();
return true;
// 右边界检测
} else if (b.left <= this.left + this.width && b.left >= this.left && b.top >= this.top && b.top <= this.top + this.height) {
b.deltaX *= -1;
this.hide();
return true;
}
};
Block.prototype.hide = function() {
this.alive = false;
container.dom.removeChild(this.dom);
};
// 创建地图类
function Map() {
// 地图类需要有一个二维数组来表示box内的block数量
this.data = [
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
];
this.allBlockArr = [];
this.render();
}
// Map也有一个render方法
Map.prototype.render = function() {
// 遍历二维数组
for (var row = 0; row < this.data.length; row++) {
for (var col = 0; col < this.data[row].length; col++) {
this.allBlockArr.push(new Block(col * 94, row * 30, this.data[row][col]))
}
}
};
// 检测所有block是否被小球碰撞
Map.prototype.checkAll = function() {
for (var i = 0; i < this.allBlockArr.length; i++) {
if (this.allBlockArr[i].alive) {
var result = this.allBlockArr[i].check()
}
if (result) {
break;
}
}
}
// 创建小球类
function Ball() {
this.left = 480;
this.top = 400;
this.d = 27;
// 小球运动速度,运动角度
this.speed = 5;
this.angle = 50;
// 小球的运动方向
// 计算机采用的是弧度制,并不是角度制
// 这里我们将圆球运动看作三角模型那么它斜向运动的speed就是斜线
// 我们可以根据角度计算出sin 也就是对边 / 斜边 的值
// 然后让其 * 斜边speed得到对边也就是Y轴的移动速度
this.deltaY = Math.sin(angleChangeToRadian(this.angle)) * this.speed;
// 三角函数中余弦就是邻边比斜边
this.deltaX = Math.cos(angleChangeToRadian(this.angle)) * this.speed;
this.dom = ball;
this.fly();
}
// 小球有一个运动方法
Ball.prototype.fly = function() {
var self = this;
var timer = setInterval(function() {
self.left += self.deltaX;
self.top += self.deltaY;
self.dom.style.left = self.left + 'px';
self.dom.style.top = self.top + 'px';
// 每十秒让container检测是否被小球碰到
container.check();
map.checkAll();
oRacket.check();
}, 10)
}
// 创建一个大盒子的类
function Box() {
this.dom = box;
this.width = 940;
this.height = 500;
}
// 大盒子需要一个碰撞检测,当检测到小球碰撞到盒子时反弹
Box.prototype.check = function() {
// 左右边界检测
// 反弹的原理是当我们的小球以X轴5 / s,Y轴 8 / s的速度下降,那么它反弹后
// X轴的速度不变,Y轴向相反方向运动
if (b.left >= this.width - b.d || b.left <= 0) {
b.deltaX *= -1;
}
if (b.top >= this.height - b.d || b.top <= 0) {
b.deltaY *= -1;
}
}
// 创建挡板类
function Racket() {
this.width = 179;
this.height = 37;
this.top = 450;
this.left = 10;
this.dom = racket;
this.move()
}
// 挡板移动
Racket.prototype.move = function() {
var self = this;
container.dom.onmousemove = function(event) {
event = event || window.event;
self.left = event.clientX - container.dom.offsetLeft - self.width / 2;
self.dom.style.left = self.left + 'px';
}
};
// 挡板碰撞检测
Racket.prototype.check = function() {
// 上边界检测
if (b.top >= this.top - b.d && b.top <= this.top && b.left >= this.left - b.d && b.left <= this.left + this.width) {
b.deltaY *= -1;
// 下边界检测
} else if (b.top <= this.top + this.height && b.top >= this.top && b.left >= this.left - b.d && b.left <= this.left + this.width) {
b.deltaY *= -1;
// 左边界检测
} else if (b.left >= this.left - b.d && b.left <= this.left && b.top >= this.top && b.top <= this.top + this.height) {
b.deltaX *= -1;
// 右边界检测
} else if (b.left <= this.left + this.width && b.left >= this.left && b.top >= this.top && b.top <= this.top + this.height) {
b.deltaX *= -1;
}
}
var b = new Ball();
var map = new Map();
var container = new Box();
var oRacket = new Racket()
// 定义角度转弧度的函数
function angleChangeToRadian(angle) {
return angle * Math.PI / 180;
}
</script>
</html>