实现效果如图所示:
1、布局
在html中,声明 div1 作为作为带有边框的父物体,一切行为都要在 div1 中进行。创建小球ball、左右可滑动的板子bat,以及存放要销毁的砖块的父物体 brick。
div1:父物体
ball:小球
bat:板子
brick:承载砖块的父容器
<body>
<div class="div1">
<div class="ball"></div>
<div class="bat"></div>
<div class="brick">
</div>
</div>
</body>
2、样式
div1:设置大小,边框,线对定位,以及左右居中。
ball:设成圆形,相对div1居中,设置大小,绝对定位
bat:设置大小,绝对定位,位置在div1的左下方
brick::预设一个div样式,并设置浮动,以及边框的大小。目的是为了让砖块可以自动生成
<style>
.div1 {
600px;
height: 600px;
border: 1px solid black;
margin: 100px auto;
position: relative;
}
.ball {
position: absolute;
20px;
height: 20px;
background: red;
border-radius: 50%;
left: 300px;
top: 300px;
}
.bat {
100px;
height: 20px;
background: blue;
position: absolute;
left: 0;
bottom: 0;
}
.brick div {
height: 8px;
98px;
float: left;
background-color: yellow;
border: 1px solid black;
}
</style>
3、行为
① 拿到所有定义的标签对象
const oDiv = document.querySelector('.div1');
const oBrick = oDiv.querySelector('.brick');
const oBall = oDiv.querySelector('.ball');
const oBatt = oDiv.querySelector('.bat');
var aBricks = oBrick.getElementsByTagName("div");
② 生成指定个数砖块,每个砖块随机生成颜色,并添加到父物体 brick下。为了以后销毁做准备,将每个砖块添加 top left属性,以及absolute绝对定位(解决在销毁时,由于浮动原因,带来销毁后其他砖块左移动的影响)。
creatStone(60);
//生成砖块
function creatStone(num) {
for (var i = 0; i < num; i++) {
var div = document.createElement('div');
div.style.background = setColors();
oBrick.appendChild(div);
div.style.left = div.offsetLeft + 'px';
div.style.top = div.offsetTop + 'px';
}
for (var j = 0; j < num; j++) {
aBricks[j].style.position = 'absolute';
}
}
随机颜色
//设置砖块随机颜色
function setColors() {
let r = parseInt(Math.random() * 256);
let g = parseInt(Math.random() * 256);
let b = parseInt(Math.random() * 256);
return `rgb(${r},${g},${b})`;
}
③ 设置滑块的移动
oBatt.onmousedown = function(e) {
e = e || window.event;
let x = e.clientX - oBatt.offsetLeft;
document.onmousemove = function(ev) {
ev = ev || window.event;
let l = ev.clientX - x;
if (l <= 0) {
l = 0;
}
if (l >= oDiv.clientWidth - oBatt.offsetWidth) {
l = oDiv.clientWidth - oBatt.offsetWidth;
}
oBatt.style.left = l + 'px';
}
}
document.onmouseup = function() {
document.onmousemove = null;
}
}
④ 设置小球随机滚动,这里定义了x y两个方向的随机速度,当ball碰到边框是,将速度设为负值,进行反方向运动。运动时间间隔为40ms。运动形式是通过改变小球的left top值来实现的。这里做了一个校验,当碰到底边时会弹窗,告诉玩家重新开始。knock()为自定义的碰撞函数,接下来会为大家介绍。
var speedx = parseInt(Math.random() * 4) + 3;
var speedy = parseInt(Math.random() * 3) + 4;
setInterval(function() {
oBall.style.left = oBall.offsetLeft + speedx + 'px';
oBall.style.top = oBall.offsetTop + speedy + 'px';
if (oBall.offsetLeft <= 0 || oBall.offsetLeft > oDiv.clientWidth - oBall.offsetWidth) {
speedx *= -1;
}
if (oBall.offsetTop <= 0 || oBall.offsetTop > oDiv.clientHeight - oBall.offsetHeight) {
speedy *= -1;
}
if (oBall.offsetTop == oDiv.clientHeight - oBall.offsetHeight) {
window.alert('重新开始')
window.location.reload();
}
if (knock(oBall, oBatt)) {
speedy *= -1;
}
for (var i = 0; i < aBricks.length; i++) {
if (knock(oBall, aBricks[i])) {
speedy *= -1;
oBrick.removeChild(aBricks[i]);
}
}
}, 40);
⑤ 碰撞函数的介绍:两个参数node1,node2,获取两个对象的每条边相对于父物体的坐标值。通过比较是否发生重叠的原理,判断是否发生了碰撞。
function knock(node1, node2) {
let l1 = node1.offsetLeft;
let r1 = node1.offsetLeft + node1.offsetWidth;
let t1 = node1.offsetTop;
let b1 = node1.offsetTop + node1.offsetHeight;
let l2 = node2.offsetLeft;
let r2 = node2.offsetLeft + node2.offsetWidth;
let t2 = node2.offsetTop;
let b2 = node2.offsetTop + node2.offsetHeight;
if (l2 >= r1 || r2 <= l1 || t2 >= b1 || b2 <= t1) {
return false;
} else {
return true;
}
}
4、详细js代码如下
<script>
window.onload = function() {
const oDiv = document.querySelector('.div1');
const oBrick = oDiv.querySelector('.brick');
const oBall = oDiv.querySelector('.ball');
const oBatt = oDiv.querySelector('.bat');
var aBricks = oBrick.getElementsByTagName("div");
creatStone(60);
//生成砖块
function creatStone(num) {
for (var i = 0; i < num; i++) {
var div = document.createElement('div');
div.style.background = setColors();
oBrick.appendChild(div);
div.style.left = div.offsetLeft + 'px';
div.style.top = div.offsetTop + 'px';
}
for (var j = 0; j < num; j++) {
aBricks[j].style.position = 'absolute';
}
}
//设置砖块随机颜色
function setColors() {
let r = parseInt(Math.random() * 256);
let g = parseInt(Math.random() * 256);
let b = parseInt(Math.random() * 256);
return `rgb(${r},${g},${b})`;
}
//设置小球随机滚动
var speedx = parseInt(Math.random() * 4) + 3;
var speedy = parseInt(Math.random() * 3) + 4;
setInterval(function() {
oBall.style.left = oBall.offsetLeft + speedx + 'px';
oBall.style.top = oBall.offsetTop + speedy + 'px';
if (oBall.offsetLeft <= 0 || oBall.offsetLeft > oDiv.clientWidth - oBall.offsetWidth) {
speedx *= -1;
}
if (oBall.offsetTop <= 0 || oBall.offsetTop > oDiv.clientHeight - oBall.offsetHeight) {
speedy *= -1;
}
if (oBall.offsetTop == oDiv.clientHeight - oBall.offsetHeight) {
window.alert('重新开始')
window.location.reload();
}
if (knock(oBall, oBatt)) {
speedy *= -1;
}
for (var i = 0; i < aBricks.length; i++) {
if (knock(oBall, aBricks[i])) {
speedy *= -1;
oBrick.removeChild(aBricks[i]);
}
}
}, 40);
//设置滑块的移动
oBatt.onmousedown = function(e) {
e = e || window.event;
let x = e.clientX - oBatt.offsetLeft;
document.onmousemove = function(ev) {
ev = ev || window.event;
let l = ev.clientX - x;
if (l <= 0) {
l = 0;
}
if (l >= oDiv.clientWidth - oBatt.offsetWidth) {
l = oDiv.clientWidth - oBatt.offsetWidth;
}
oBatt.style.left = l + 'px';
}
}
document.onmouseup = function() {
document.onmousemove = null;
}
}
function knock(node1, node2) {
let l1 = node1.offsetLeft;
let r1 = node1.offsetLeft + node1.offsetWidth;
let t1 = node1.offsetTop;
let b1 = node1.offsetTop + node1.offsetHeight;
let l2 = node2.offsetLeft;
let r2 = node2.offsetLeft + node2.offsetWidth;
let t2 = node2.offsetTop;
let b2 = node2.offsetTop + node2.offsetHeight;
if (l2 >= r1 || r2 <= l1 || t2 >= b1 || b2 <= t1) {
return false;
} else {
return true;
}
}
</script>