【写在前面:本篇文章介绍的是博主在学习前端的JavaScript时跟着教程,稍作改良的一个打砖块的小游戏,这个可能与大家见到的简易版打砖块不大一样,会稍微复杂一点点。写这篇文章有两个目的,一是作为学习记录,二是希望对大家有点帮助,对于不足之处,也希望各路大佬可以不吝赐教。本文为作者原创文章,文中所示的图片、代码皆来自网络或博主自制,仅做学习、记录使用,如果某些东西涉及侵权,请作者大大告知博主,可以对此进行补充说明。如有人私自引入商业使用构成侵权或违法犯罪,则博主概不负责。】
这里写目录标题
- 一、完成情况
- 二、简介
-
- - 板子移动
- - 碰撞模块
- - 砖块的生成
- 三、总结
- 四、完整代码
一、完成情况
二、简介 这个项目主要是为了练习JavaScript中的一些操作方法而设定的练习,但本身用Chrome写这种程序就是在折磨cup,懂得都懂。当时运行久了(敲代码+开Chrome看完成情况),电脑都差点卡死。所以也不敢继续完成下去了。
大体上的思路其实并不复杂,大家在很多地方都可以看到类似的代码。整个游戏是通过div块完成的,中间一个大的div作为中心方框,下面一个div作为打砖块的板子,然后一个div将角消掉作为小球,最后在游戏开始前随机那么60个白色div作为砖块,就可以开始打了。
其中需要实现的基本功能有三个。一是这个板子的移动,他应该可以有两种方式实现控制,键盘和鼠标,在这里我选择了用鼠标点击拖动的方式实现这一功能。第二个就是碰撞,其中包括了板子和小球的碰撞和小球和砖块的碰撞两种。第三是砖块的生成和消除。
由于一开始我是想直接仿照打砖块的小游戏做的(类似下图这种有奖励的,然后满屏都是球的这种,图片截自某信小程序),所以,在这个项目中未能完成的功能有:1)奖励方框的生成和掉落 2)小球分裂 3)胜负手判断(这个只是单纯没做完2333)
文章图片
对于已完成的几个功能来讲:
- 板子移动 这里用到了一个简单的div移动的方法,由于用的是鼠标拖动的方法,所以这里只需要检测mouseup、mousedown、mousemove三个事件,这样一来,通过监测鼠标按下和鼠标抬起的事件来判断是否需要移动滑块,在读出鼠标移动的距离用于对板子移动距离进行计算。而对于板子的移动,则只需要在鼠标点下时计算其左上角的坐标,然后再通过鼠标移动时得到的移动数据,对板子的距左距离进行加减运算即可完成。
- 碰撞模块 这个模块相对来说就比较复杂了,倒不是代码有多难,而是由于在这个项目是在div块的基础上完成的,对于碰撞和反弹的判定可能会出现几个问题:
- 碰撞判定:碰撞判定其实还不算特别复杂,首先我们先来看看目标碰撞体和小球的示意图
文章图片
从图中我们可以看到目标div和小球的div实际上都是一个方块,虽然我们用圆角的方式将小球做成了一个圆形,但其实际碰撞体积还是按方块来计算的,所以我们只需要按方块的体积来计算碰撞,就可以简单实现目标。首先我们得知道,在碰撞计算时,我们实际上是用的offsetLeft
和offsetTop
两种方法去获取div距离左侧和顶部的距离,然后利用数学的方式判断是否碰撞,大致上如下图所示
文章图片
由于在本次设计中小球和所以我们单看关键点,就可以吧整个想象成一个二维坐标系和一堆坐标点,然后就会发现是这样的情况,当小球的关键点坐标落在绿色这个区域时,可以说小球与目标块之间产生了碰撞。这样,碰撞的问题就解决了
- 【前端|【前端】利用JavaScript做打砖块小游戏】反弹问题:解决了碰撞的问题之后,反弹的问题相对来说就简单一点了,由于砖块是正方形,那么我们就可以画出一下几个区域
文章图片
其中当“坐标”落在紫色区域时,我们可以认为小球在砖块的上面或者下面,此时我们反转小球纵向速度的正负值,就可以完成反弹。同理,当小球落在黄色区域时,可以认为小球在砖块的左侧或右侧,此时我们反转小球横向速度的正负值,就可以完成反弹。
createElement
依序创建出足够多的砖块,然后再将生成的div变成浮动的形式,最后固定div的“坐标”。这样我们就可以轻松完成对砖块的创建。三、总结 对这个小练习来说,有以下几个问题:
- 最大的问题还是这样做游戏真不推荐,如果把它做完,相当于直接点开了个@echo off ; start cmd;0%;的bat文件,大概能把cpu都给烧了吧。
- 在砖块的碰撞端上还是有一定的问题,问题主要出在小球的速度上,由于程序中是判断小球关键点“坐标”与我们目标位置的关系,一旦进入目标位置,则相应速度方向反向。那么就会出现两个问题:一是板子与小球碰撞的问题,由于板子并不是正方形的块,没办法写对角线的判别式(由于是像素点判定,所以如果强行写判别式,可能出现被遗漏的像素,从而造成bug),所以板子的碰撞反弹只能反转纵向速度。二是如果小球随机到的速度过快,会出现在第一次检测时,“坐标”在判定区内,速度反向,但是第二次检测时,小球来不及飞出来,还在判定区内,于是在同一方向上继续反向,造成在边界上鬼畜的情况。如果说第一个问题还无伤大雅的话,第二个问题我们除了能控制小球速度之外,我想不出更好的办法去解决这个bug,可能是我才疏学浅了,如果有好的办法,请各位大神不吝赐教。
四、完整代码 编译器:vs code
浏览器:Chrome
闲的蛋疼 - 锐客网
>
//做一些简单的css样式,美化网页
#div1{width: 600px;
height: 600px;
border: 1px solid black;
border-bottom: dashed 1px black;
position: relative ;
margin: 100px auto;
}
#ball1{width: 6px;
height: 6px;
background-color: red;
border-radius: 50%;
position:absolute;
bottom: 30px;
left: 300px;
}
#bat{width: 100px;
height: 20px;
background-color:grey;
opacity: 1;
position:absolute;
bottom: -15px;
left: 250px;
}
#brick div{width: 19px;
height: 19px;
border: 0.5px solid black ;
float: left;
}
body{height: 100%;
width: 100%;
background-image: url('E:/vs code/源代码/html/img_2323.jpg');
background-attachment: fixed;
position: relative;
font-family: Arial;
background-position: center 0;
}
#rewardBrick {position: absolute;
}
#rewardBrick div{width: 14px;
height: 14px;
background-color: orange;
opacity: 1;
position:absolute;
left: 3px;
top: 3px;
}
//
>
window.onload = function(){
var oDiv = document.getElementById('div1');
var oBall = document.getElementById('ball1');
var oBat = document.getElementById('bat');
var oBrick = document.getElementById('brick');
var aBricks = oBrick.getElementsByTagName('div');
var rBrick = document.getElementById('rewardBrick');
var rBrick1 = rBrick.getElementsByTagName('div');
var rBrick2 = document.getElementsByClassName('nb');
dragX(oBat);
creatBrick(360);
//随机生成一个的速度
var speedX = 1 + Math.random()*3;
/* parseInt(Math.random()*3) +10;
*/
var speedY = -1 - Math.random()*3;
//触壁反弹函数
setInterval(function(){
oBall.style.left = oBall.offsetLeft + speedX + 'px';
oBall.style.top = oBall.offsetTop + speedY + 'px';
if(oBall.offsetLeft >= 594 || oBall.offsetLeft <= 0){
speedX *= -1;
}if(oBall.offsetTop >= 594 || oBall.offsetTop <= 0){
speedY *= -1;
}//砖块反弹和板子反弹
if(knock(oBall,oBat)){
speedY *= -1;
}for(var i = 0;
i < aBricks.length;
i++){
if(knock(oBall,aBricks[i])){if(knockPositionJudge_Brick(oBall,aBricks[i]) == 'surface'){
speedY *= -1;
}else if(knockPositionJudge_Brick(oBall,aBricks[i]) == 'side'){
speedX *= -1;
}var left2 = aBricks[i].offsetLeft;
var top2 = aBricks[i].offsetTop;
oBrick.removeChild(aBricks[i]);
// reward(aBricks[i],left2,top2);
return top2;
break;
}
}//奖励模块移动
// var bricks_1 = $(".nb");
// bricks_1.style.backgroundColor = 'blue';
// if(rBrick1.length > 0){
//document.getElementsByClassName('nb');
// }},10);
//10ms检测一次}//拍子拖拽函数
function dragX(node){
node.onmousedown = function(ev){
var e = ev ||window.event;
var offsetX = e.clientX - node.offsetLeft;
document.onmousemove = function(ev){
var e = ev ||window.event;
var l = e.clientX - offsetX;
if(l <= 0){
l = 0;
}
if(l >= 500){
l = 500;
}
node.style.left = l +'px';
}
}document.onmouseup = function(){
document.onmousemove = null;
}
}//创建砖块的函数
function creatBrick(n){
var oBrick = document.getElementById('brick');
for(var i = 0;
i < n;
i++){
var node = document.createElement('div');
node.style.backgroundColor = 'rgba(255,255,255,0.7)';
oBrick.appendChild(node);
}//文档流转换
var aBricks = oBrick.getElementsByTagName('div');
for(var i = 0;
i < aBricks.length;
i++){
aBricks[i].style.left = aBricks[i].offsetLeft +'px';
aBricks[i].style.top = aBricks[i].offsetTop +'px';
}for(var i = 0;
i < aBricks.length;
i++){
aBricks[i].style.position = 'absolute';
}
}//碰撞处理的函数
function knock(node1,node2){
var l1 = node1.offsetLeft;
var r1 = node1.offsetLeft + node1.offsetWidth;
var t1 = node1.offsetTop;
var b1 = node1.offsetTop + node1.offsetHeight;
var l2 = node2.offsetLeft;
var r2 = node2.offsetLeft + node2.offsetWidth;
var t2 = node2.offsetTop ;
var b2 = node2.offsetTop + node2.offsetHeight;
if(t2 >= b1 || b2 <= t1 || l2 >= r1 || r2 <= l1){
return false;
}else{
return true;
}
}function knockPositionJudge_Brick(node1,node2){
var x1 = node1.offsetLeft - node2.offsetLeft;
var y1 = node1.offsetTop - node2.offsetTop;
if(y1 >= -6 && y1 - x1 <= 0 && x1 >= -6 && x1 <= 7|| y1 >= -6 && y1 + x1 <= 14 && x1 >= 7 && x1 <= 20|| y1 + x1 >= 14 && y1 <= 20 && x1 >= -6 && x1 <= 7 || y1 - x1 >= 0 && y1 <= 20 && x1 >= 7 && x1 <= 20 ){
return 'surface';
}else {
return 'side';
}
}//随机掉落奖励箱子的创建
// function reward(aBricks,leftPoint,topPoint){//if(Math.random() <= 1){
//var rBrick = document.getElementById('rewardBrick');
//var newBrick = document.createElement('div');
//newBrick.className = 'nb';
//newBrick.style.left = leftPoint + 3 + 'px';
//newBrick.style.top = topPoint +3 + 'px';
//rBrick.appendChild(newBrick);
//newBrick.style.position = 'absulute';
//newBrick.style.display = 'inline-block';
//topPosition = topPoint + 3;
//return topPosition;
//}
// }//小球分裂函数
function divideBall(){}//小球消失函数
function removeBall(){}//胜负手判断函数
function result(){}
推荐阅读
- 前端|【前端】html+css自制登录页面(无交互)
- js|手把手教你制作一个简单的聊天机器人(图灵api)
- WPS表格|WPS-JS宏开发-基础知识-01-初识
- Vue基础知识|Vue3之Teleport
- java|如果再写for循环,我就锤自己
- 现在大多数人们用的前端框架有哪些大盘点
- React|【React】3_使用react组件化编码流程及案例分享(附源码)
- web前端期末大作业 html+css+javascript 校园主题网页设计(南京大学3页)个人毕设专用
- HTML5期末大作业|个人主页博客网页设计制作HTML5+CSS大作业——清新春暖花开个人博客网站(6页)