贪吃蛇是前端人入门且必须的技能。今天闲下来整理介绍一下~~~
首先,先要确定贪吃蛇小游戏的需求:
- 背景墙 确定行列
- 创建蛇头
- 蛇头移动
- 蛇头变相
- 创建实物
- 碰撞检测
- 增加身体
- 食物消失 随机创建新的
- 身体蛇头一起移动
我们首先通过创建一些div元素来生成网格轨道背景:
然后创建蛇头(我们让蛇头位置是固定的,食物是随机产生的)
接下来是蛇头的自动移动(我们设置一个定时器来实现蛇头的自动移动):
蛇头的变向操作(使用到了键盘事件 我们使用上下左右键来移动 判断keycode值来改变蛇头位置)
接下来创建随机食物:
食物和蛇头的碰撞检测:
注意食物不能成成在身体上,所以我们需要添加条件判断:
吃掉食物后产生身体块
身体块随着头移动
把创建头 食物 身体 封装到一起(共有的地方)
让几个函数需要的参数是一致的,不一样的在内部实现
接下来还要优化以下~判断蛇头是否碰撞了边界和自己的身体,也要不让蛇可以回退移动;随机产生不同分值的食物,获得一定分值后的速度也要变快
以下是具体代码实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>贪吃蛇</title>
<style>
.out{
width: 500px;
height: 500px;
background: #ccc;
border: 1px solid blue;
position: relative;
overflow: hidden;
}
p{
display: inline-block;
}
span{
display: block;
}
</style>
</head>
<body>
<div class="out">
</div>
<button onclick="reset()">再玩一局</button>
得分:<p></p>
<span>得分大于等于5,改变速度。得分大于等于10,改变速度。</span>
<script src="./snake.js"></script>
<script>
var col=10;
var row=10;
var w=50;
var h=50;
var out=$('.out')[0];
var score=$('p')[0];
var bodys=[];
var num=0;
var time=1000;//速度
//背景
createBg(out,col,row)
// 蛇头
var head=createNode(1,out)
// 食物
var food=createNode(2,out)//createFood(out,w,h,col,row,1)
createKeyEvent(head);
//计时器
var timer=setInterval(play,time)
//
function play() {
//身体移动
moveBody(bodys,head)
//头部移动
moveHead(head);
var checkstate=check(head,food);
if(checkstate){
//计算分数
num+=Number(food.getAttribute('value'));
score.innerHTML=num+"分"
//判断分数 改变速度
if (num>=5&&num<10) {
time=600;
clearInterval(timer);
timer=setInterval(play,time);
}
else if(num>=10){
time=300;
clearInterval(timer);
timer=setInterval(play,time);
}
//删除food
out.removeChild(food);
//创建food(food不能创建在身体上)
food=createNode(2,out)
//创建身体
if (bodys.length>0) {
// var body=createBody(out,w,h,bodys[bodys.length-1])
var body=createNode(3,out,bodys[bodys.length-1])
console.log(body)
}else{
// var body=createBody(out,w,h,head)
var body=createNode(3,out,head)
console.log(body)
}
bodys.push(body)
}
var bodycheckstate=checkbody(head,bodys);
if (bodycheckstate==false) {
clearInterval(timer);
alert("咬到自己了!")
}
var borderstate=checkBorder(head,out);
if (borderstate==false) {
clearInterval(timer);
alert("game over!")
}
}
</script>
</body>
</html>
<!--
1.背景墙 确定行列
2.创建蛇头
3.蛇头移动
4.蛇头变相
5.创建实物
6.碰撞检测
7.增加身体
8.食物消失 随机创建新的
9身体蛇头一起移动
-------完成-------
-->
//获取元素方法
function $(string){
var tag=string.charAt(0);
var ele=null;
switch(tag){
case ".":
ele=document.getElementsByClassName(string.slice(1))
break;
case "#":
ele=document.getElementById(string.slice(1))
break;
default:
ele=document.getElementsByTagName(string);
break;
}
return ele;
}
//创建背景方法
function createBg(parent,col,row){
//创建表格
parent.style.width=row*50+"px";
parent.style.height=col*50+"px";
for (var i = 0; i < row; i++) {
for (var j = 0; j < col; j++) {
var div =document.createElement('div')
div.style.width="48px"
div.style.height="48px"
div.style.border="1px solid white"
div.style.float='left'
parent.appendChild(div);
}
}
}
//事件监听
function createKeyEvent(head){
document.onkeyup=function(event){
console.log(event)
var event=event||window.event
var key=event.keyCode;
if (head.className=='top'&&key==40) {
return;
}
else if (head.className=='right'&&key==37) {
return;
}
else if (head.className=='down'&&key==38) {
return;
}
else if (head.className=='left'&&key==39) {
return;
}
switch(key){
case 40:
head.className='down'
break;
case 37:
head.className="left"
break;
case 38:
head.className="top"
break;
case 39:
head.className="right"
break;
}
}
}
//身体碰撞检测
function checkbody(obj1,arr) {
for (var i = 1; i < arr.length; i++) {
if (obj1.offsetTop==arr[i].offsetTop&&obj1.offsetLeft==arr[i].offsetLeft) {
return false;
}
}
}
//碰撞检测
function check(obj1,obj2){
if (obj1.offsetLeft==obj2.offsetLeft&&obj1.offsetTop==obj2.offsetTop) {
return true;
}
return false;
}
//头部移动
function moveHead(head){
var left=0;
var top=0;
switch(head.className){
case 'left':
left=head.offsetLeft-50;
top=head.offsetTop
break;
case 'right':
left=head.offsetLeft+50;
top=head.offsetTop
break;
case 'top':
left=head.offsetLeft;
top=head.offsetTop-50
break;
case 'down':
left=head.offsetLeft;
top=head.offsetTop+50
break;
}
head.style.left=left+'px'
head.style.top=top+'px'
}
//移动body
function moveBody(array){
if (array.length>0) {
for (var i = array.length - 1; i >= 0; i--) {
switch(array[i].className){
case 'left':
x=array[i].offsetLeft-50;
y=array[i].offsetTop
break;
case 'right':
x=array[i].offsetLeft+50;
y=array[i].offsetTop
break;
case 'top':
x=array[i].offsetLeft;
y=array[i].offsetTop-50
break;
case 'down':
x=array[i].offsetLeft;
y=array[i].offsetTop+50
break;
}
array[i].style.left=x+"px";
array[i].style.top=y+'px'
if (i==0) {
array[i].className=head.className
}else{
array[i].className=array[i-1].className
}
}
}
}
/*
检测坐标是否重合
*/
function checkfood(x,y,array){
console.log(head)
if (x==head.offsetLeft&&y==head.offsetTop) {
return false
}
for (var i = 0; i < array.length; i++) {
// 检测到重复
if (array[i].offsetLeft==x&&array[i].offsetTop==y) {
return false;
}
if (i==array.length-1) {
return true;
}
}
return true;
}
/*
创建节点对象
type 1 蛇头 2 food 3 身体
*/
function createNode(type,parent,preObj){
var x=0;
var y=0;
var w=50;
var h=50;
var bgColor;
var fen;
var className="";
var preObj=preObj?preObj:null
switch(type){
case 1:
bgColor="red"
className="right"
break;
case 2:
var foodtype=parseInt(Math.random()*10)%3
var foods=[['yellow',1],['skyblue',2],['pink',3]]
bgColor=foods[foodtype][0]
fen=foods[foodtype][1]
var array=bodys;
// console.log(array)
test();
function test(){
var a=parseInt(Math.random()*row)*50;
var b=parseInt(Math.random()*col)*50;
var state=checkfood(a,b,array)
if (state) {
x=a;
y=b;
}else{
test();
}
}
break;
case 3:
switch(preObj.className){
case 'left':
x=preObj.offsetLeft+50;
y=preObj.offsetTop
break;
case 'right':
x=preObj.offsetLeft-50;
y=preObj.offsetTop
break;
case 'top':
x=preObj.offsetLeft;
y=preObj.offsetTop+50
break;
case 'down':
x=preObj.offsetLeft;
y=preObj.offsetTop-50
break;
}
className=preObj.className;
bgColor='black'
break ;
default:
break
}
var node=document.createElement('div');
node.style.background=bgColor;
node.style.position="absolute";
node.style.left=x+"px";
node.style.top=y+"px";
node.style.width=w+"px";
node.style.height=h+"px";
node.style.zIndex=999;
node.className=className;
node.setAttribute("value",fen)
parent.appendChild(node)
return node;
}
function reset(){
window.location.reload();
}
//检测碰撞到边界框
function checkBorder(obj1,obj2) {
if (obj1.offsetLeft>obj2.offsetWidth||obj1.offsetLeft<0||obj1.offsetTop<0||obj1.offsetTop>obj2.offsetHeight) {
return false;
}
return true;
}