这是一个游戏,这不仅仅是一个游戏,我们的目标不是为了开发游戏,而是为了掌握常见函数和基本开发思路 (多练多练)
实现代码之前 先有思路 实现具体的功能 和进行不断的调式
以下是本人在培训时期老师写的代码 思路图为老师所画
场景为css 和 html 组成
直接上代码
代码如下
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
background-color: aliceblue;
}
h2 {
text-align: center;
margin: 20px auto;
}
#box {
background-color: white;
width: 1000px;
height: 500px;
box-shadow: 0 0 3px darkcyan;
margin: 20px auto;
position: relative;
}
P {
display: block;
width: 100px;
/* 砖块样式 */
height: 40px;
position: absolute;
box-shadow: -2px -3px -6px black;
}
#baffle {
position: absolute;
width: 200px;
height: 16px;
border-radius: 8px;
background-color: brown;
left: 454px;
top: 484px;
}
#ball {
z-index: 99;
width: 30px;
height: 30px;
background: rgb(117, 85, 74);
box-shadow: #888 2px 2px 3px;
position: absolute;
top: 454px;
left: 534px;
border-radius: 50%;
}
</style>
</head>
<body>
<h2>打砖块</h2>
<div id="box">
<!-- 小球 -->
<div id="ball"></div>
<!-- 挡板 -->
<div id="baffle"></div>
</div>
// 让js代码在网页加载后执行
window.onload = function () {
//获取场景对象
var _box = document.querySelector("#box");
// ----------------------- 砖块处理部分
//定义行数
var rows = 3;
//计算一行放多少砖块
var cols = Math.floor(_box.offsetWidth / 100);
//声明一个保存砖数的数组
var brickArrs = []
//循环 创建砖块
for (var i = 0; i < rows; i++) {
//循环创建多行
for (var j = 0; j < cols; j++) {
//循环创建一行中的多个砖块
//创建砖块 p 标签
var _p = document.createElement("p");
_p.style.backgroundColor =
"#" + Math.random().toString(16).substr(2, 6);
//p 标签定位;位置
_p.style.left = j * 100 + "px";
_p.style.top = i * 40 + "px";
//将砖块添加到场景中
_box.appendChild(_p);
//将砖块保存到数组中
brickArrs.push(_p)
}
}
代码详情在第一段里
//-----------挡板运动
var _baffle = document.querySelector("#baffle")
var _speed = 20
document.onkeydown = function(e) {
//获取事件对象
var e = e || window.event
//判断用户按下的按键
var keyCode = e.keyCode
//用户按下,控制挡板运动
switch(keyCode) {
case 37:
console.log("向左移动")
_baffle.style.left = _baffle.offsetLeft - _speed + "px"
break
case 39:
console.log("向右移动")
_baffle.style.left = _baffle.offsetLeft + _speed + "px"
break
}
左右不超出场景边缘
代码实现:
//挡板边界判断,挡板不能超出边界
if(_baffle.offsetLeft < 0) {
_baffle.style.left = 0
}else if(_baffle.offsetLeft >= (_box.offsetWidth - _baffle.offsetWidth)){
_baffle.style.left = (_box.offsetWidth - _baffle.offsetWidth) + "px"
}
}
需求:小球在游戏区域可以运动起来,碰撞墙壁的时候需要反弹
//----------小球运动
var _ball = document.querySelector("#ball")
var speedX = 3 //垂直速度
var speedY = -5 //水平速度
// ballInterval 全部间隔
//setInterval 设置间隔
var ballInterval = setInterval(function () {
//小球运动起来
_ball.style.left = _ball.offsetLeft + speedX + "px"
_ball.style.top = _ball.offsetTop + speedY + "px"
需求:小球不能碰撞下边界,一旦碰撞到下边界游戏结束;下边界上必须让小球碰撞到挡板进行反弹
//边界判断
if(_ball.offsetLeft < 0 ) {//左边界
speedX = 3
}else if(_ball.offsetLeft > (_box.offsetWidth - _ball.offsetWidth)) {
speedX = -3
}
if(_ball.offsetTop < 0 ) { //上边界
speedY = 5
} else if(
( _ball.offsetLeft >= (_baffle.offsetLeft - _ball.offsetWidth/2))
&&
(_ball.offsetLeft <= (_baffle.offsetLeft + _baffle.offsetWidth - _ball.offsetWidth/2))
&&
(_ball.offsetTop >= (_baffle.offsetTop -_ball.offsetHeight))
) { // 碰到挡板
speedY = -5
}else if(_ball.offsetTop > (_box.offsetHeight - _ball.offsetHeight)){
clearInterval(ballInterval)// clearInterval 清除间隔
alert("你漏球了,结束") //弹窗 阻止代码执行 计时器仍然执行
location.reload()//重新加载当前位置 刷新网页
}
小球和砖块之间的碰撞检测,小球碰到砖块,砖块消失/小球反弹,
具体操作如图
如果碰撞过程中,按照每一个碰撞面去检测,很容易存在 BUG
代码中通过上下碰撞面、左右碰撞面进行同时检测,检测小球坐标一旦进入砖块
内部就算碰撞成功,让砖块消失/代码中通过 DOM removeChild() 函数移除标签,小球的运动反弹 左右碰撞面-水平速度取反、上下碰撞面-垂直速度取反
代码实现:
//判断小球是否和砖块发生碰撞
for(var x = 0; x < brickArrs.length; x++) {
//获取一个砖块
var brick = brickArrs[x]
//碰撞检测
collide(brick, _ball)
}
}, 20)
//--------------------- 碰撞检测:小球、砖块
// brick :砖块
// ball:小球
function collide(brick, ball) {
console.log("--------------------------------------")
// console.log(brick.offsetLeft, brick.offsetTop, brick.offsetWidth, brick.offsetHeight, "砖块")
// console.log(ball.offsetLeft, ball.offsetTop, ball.offsetWidth, ball.offsetHeight, "小球")
console.log("--------------------------------------")
// 底部碰撞、左侧碰撞、顶部碰撞、右侧碰撞
if(
//offset 抵消
(ball.offsetLeft > (brick.offsetLeft - ball.offsetWidth/2))
&&
(ball.offsetLeft < (brick.offsetLeft + brick.offsetWidth - ball.offsetWidth/2))
&&
(ball.offsetTop < (brick.offsetTop + brick.offsetHeight))
&&
(ball.offsetTop > (brick.offsetTop - brick.offsetHeight))
) { // 底部碰撞 或者 顶部碰撞
// 碰撞发生,砖块:消失,小球:反弹
console.log("碰撞发生,砖块消失,小球反弹.....")
speedY = -speedY // 垂直速度取反
_box.removeChild(brick)
} else if(
//offset 抵消
(ball.offsetTop > (brick.offsetTop - ball.offsetHeight/2))
&&
(ball.offsetTop < (brick.offsetTop + brick.offsetHeight - ball.offsetHeight/2))
&&
(ball.offsetLeft > (brick.offsetLeft - ball.offsetWidth))
&&
(ball.offsetLeft < (brick.offsetLeft + brick.offsetWidth))
) {
// 左侧碰撞 或者 右侧碰撞
speedX = -speedX
_box.removeChild(brick)
boom()
}
}
当小球和砖块发生碰撞时
创建 audio 标签
设置 src 属性,添加音效文件
不设置 autoplay=true 自动播放
碰撞时调用 audio.play() 播放音效即可
代码如下:
// 音效处理
var _audio = document.createElement("audio")
_audio.src = "./img/y993.wav"
// _audio.autoplay = true
document.appendChild(_audio)
function boom() {
_audio.play()
}
整体代码如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
background-color: aliceblue;
}
h2 {
text-align: center;
margin: 20px auto;
}
#box {
background-color: white;
width: 1000px;
height: 500px;
box-shadow: 0 0 3px darkcyan;
margin: 20px auto;
position: relative;
}
P {
display: block;
width: 100px;
/* 砖块样式 */
height: 40px;
position: absolute;
box-shadow: -2px -3px -6px black;
}
#baffle {
position: absolute;
width: 200px;
height: 16px;
border-radius: 8px;
background-color: brown;
left: 454px;
top: 484px;
}
#ball {
z-index: 99;
width: 30px;
height: 30px;
background: rgb(117, 85, 74);
box-shadow: #888 2px 2px 3px;
position: absolute;
top: 454px;
left: 534px;
border-radius: 50%;
}
</style>
</head>
<body>
<h2>打砖块</h2>
<div id="box">
<!-- 小球 -->
<div id="ball"></div>
<!-- 挡板 -->
<div id="baffle"></div>
</div>
<script>
// 让js代码在网页加载后执行
window.onload = function () {
//获取场景对象
var _box = document.querySelector("#box");
// ----------------------- 砖块处理部分
//定义行数
var rows = 3;
//计算一行放多少砖块
var cols = Math.floor(_box.offsetWidth / 100);
//声明一个保存砖数的数组
var brickArrs = []
//循环 创建砖块
for (var i = 0; i < rows; i++) {
//循环创建多行
for (var j = 0; j < cols; j++) {
//循环创建一行中的多个砖块
//创建砖块 p 标签
var _p = document.createElement("p");
_p.style.backgroundColor =
"#" + Math.random().toString(16).substr(2, 6);
//p 标签定位;位置
_p.style.left = j * 100 + "px";
_p.style.top = i * 40 + "px";
//将砖块添加到场景中
_box.appendChild(_p);
//将砖块保存到数组中
brickArrs.push(_p)
}
}
//-----------挡板运动
var _baffle = document.querySelector("#baffle")
var _speed = 20
document.onkeydown = function(e) {
//获取事件对象
var e = e || window.event
//判断用户按下的按键
var keyCode = e.keyCode
//用户按下,控制挡板运动
switch(keyCode) {
case 37:
console.log("向左移动")
_baffle.style.left = _baffle.offsetLeft - _speed + "px"
break
case 39:
console.log("向右移动")
_baffle.style.left = _baffle.offsetLeft + _speed + "px"
break
}
//挡板边界判断,挡板不能超出边界
if(_baffle.offsetLeft < 0) {
_baffle.style.left = 0
}else if(_baffle.offsetLeft >= (_box.offsetWidth - _baffle.offsetWidth)){
_baffle.style.left = (_box.offsetWidth - _baffle.offsetWidth) + "px"
}
}
//----------小球运动
var _ball = document.querySelector("#ball")
var speedX = 3 //垂直速度
var speedY = -5 //水平速度
// ballInterval 全部间隔
//setInterval 设置间隔
var ballInterval = setInterval(function () {
//小球运动起来
_ball.style.left = _ball.offsetLeft + speedX + "px"
_ball.style.top = _ball.offsetTop + speedY + "px"
//边界判断
if(_ball.offsetLeft < 0 ) {//左边界
speedX = 3
}else if(_ball.offsetLeft > (_box.offsetWidth - _ball.offsetWidth)) {
speedX = -3
}
if(_ball.offsetTop < 0 ) { //上边界
speedY = 5
} else if(
( _ball.offsetLeft >= (_baffle.offsetLeft - _ball.offsetWidth/2))
&&
(_ball.offsetLeft <= (_baffle.offsetLeft + _baffle.offsetWidth - _ball.offsetWidth/2))
&&
(_ball.offsetTop >= (_baffle.offsetTop -_ball.offsetHeight))
) { // 碰到挡板
speedY = -5
}else if(_ball.offsetTop > (_box.offsetHeight - _ball.offsetHeight)){
clearInterval(ballInterval)// clearInterval 清除间隔
alert("你漏球了,结束") //弹窗 阻止代码执行 计时器仍然执行
location.reload()//重新加载当前位置 刷新网页
}
//判断小球是否和砖块发生碰撞
for(var x = 0; x < brickArrs.length; x++) {
//获取一个砖块
var brick = brickArrs[x]
//碰撞检测
collide(brick, _ball)
}
}, 20)
//--------------------- 碰撞检测:小球、砖块
// brick :砖块
// ball:小球
function collide(brick, ball) {
console.log("--------------------------------------")
// console.log(brick.offsetLeft, brick.offsetTop, brick.offsetWidth, brick.offsetHeight, "砖块")
// console.log(ball.offsetLeft, ball.offsetTop, ball.offsetWidth, ball.offsetHeight, "小球")
console.log("--------------------------------------")
// 底部碰撞、左侧碰撞、顶部碰撞、右侧碰撞
if(
//offset 抵消
(ball.offsetLeft > (brick.offsetLeft - ball.offsetWidth/2))
&&
(ball.offsetLeft < (brick.offsetLeft + brick.offsetWidth - ball.offsetWidth/2))
&&
(ball.offsetTop < (brick.offsetTop + brick.offsetHeight))
&&
(ball.offsetTop > (brick.offsetTop - brick.offsetHeight))
) { // 底部碰撞 或者 顶部碰撞
// 碰撞发生,砖块:消失,小球:反弹
console.log("碰撞发生,砖块消失,小球反弹.....")
speedY = -speedY // 垂直速度取反
_box.removeChild(brick)
} else if(
//offset 抵消
(ball.offsetTop > (brick.offsetTop - ball.offsetHeight/2))
&&
(ball.offsetTop < (brick.offsetTop + brick.offsetHeight - ball.offsetHeight/2))
&&
(ball.offsetLeft > (brick.offsetLeft - ball.offsetWidth))
&&
(ball.offsetLeft < (brick.offsetLeft + brick.offsetWidth))
) {
// 左侧碰撞 或者 右侧碰撞
speedX = -speedX
_box.removeChild(brick)
boom()
}
}
// 音效处理
var _audio = document.createElement("audio")
_audio.src = "./img/y993.wav"
// _audio.autoplay = true
document.appendChild(_audio)
function boom() {
_audio.play()
}
};
</script>
</body>
</html>