文章目录
- 不知道干啥,那就敲代码吧,写个贪吃蛇,很显然,被自己菜哭了,自己写的贪吃蛇自己都不会玩(ps:我曾经可是在不会死亡的情况下完了好长时间>_<)。 实现效果如下:
-
- 在onShow钩子函数那里获取到游戏容器的宽高,其实我是不想在这里获取的,但没办法,好像getBoundingClientRect()需要挂载后才能拿到值,在这之前的钩子函数中都拿不到具体的属性值(ps:这是我猜的,因为文档写的很…我找不到只能挨个试)。 拿到容器宽高后,根据蛇的身体长度(就是每个小圆点)来确定要划分多少个格子,形成一个坐标轴,后面食物,蛇的移动都根据这坐标轴来确定。 onShow(){ // 第一次初始化 this.conH = this.$refs["con"].getBoundingClientRect().height ; this.conW = this.$refs["con"].getBoundingClientRect().width ; this.h = Math.floor(this.conH / this.snakeBody); this.w = Math.floor(this.conW / this.snakeBody); for (var i = 0; i < this.w; i++) { //绘制网格 this.grid.push([]) for (var j = 0; j < this.h; j++) { this.grid[i].push({ x: i, y: j }); } } this.init(); //初始化函数 }
- 用一个数组实现,数组索引0为蛇的尾巴,索引length-1为头。 init(){ const snakePos = [ //蛇的初始化的身体 { x : 0, y : 0, flag : 'b', id : Math.random() }, { x : 1, y : 0, flag : 'b', id : Math.random() }, { x : 2, y : 0, flag : 'h', id : Math.random() } ]; this.snake.snakePos = snakePos; //把初始化的身体赋给蛇 this.randomFood(); //随机生成食物 }
- 食物随机生成,位置在网格中任意位置,但不能生成在蛇的身体位置中。 randomFood(){ //随机生成食物 while(true){ let x = Math.floor(Math.random() * this.conW); let y = Math.floor(Math.random() * this.conH); x = x - (x % this.snakeBody); //x,y化为和蛇身体倍数的坐标 y = y - (y % this.snakeBody); let is = this.snake.snakePos.find((item)=>{ return item.x == x && item.y == y; }) this.food.x = x; this.food.y = y; if(!is) { //当食物的位置不为蛇不和蛇的位置重叠就跳出结束死循环 break; } } }
- 蛇的移动是通过对数组的push和shift实现,蛇有移动的方向,根据方向来修改新增蛇头的x和y的值。 des:{//蛇的方向 "-20":{ // 向上移动一位 x:0, y:-1, flag: '' }, "20":{//向下 x:0, y:1, flag: '' }, "10":{ //右 x:1, y:0, flag: '' }, "-10":{ //左 x:-1, y:0, flag: '' } }, addHead(des){ //添加蛇头 des为蛇的方向,一共有四个方向上下左右,每次移动是都会传一个方向过来 const oHead = this.snake.snakePos[this.snake.snakePos.length -1]; const newHead ={ x : oHead.x + des.x, y : oHead.y + des.y, flag : 'h', id : Math.random() } this.isEnd(newHead); this.snake.snakePos.push(newHead); oHead.flag = 'b'; }, move(des){ // 蛇移动时,原头变身体,原尾巴去掉,也就是push一个头,shift一个尾巴 this.addHead(des); this.snake.snakePos.shift(); }, 移动图如下:
- 当蛇头的x >= 地图的x最大值 || x < 0 || 蛇头的Y >= 地图的Y最大值 || Y < 0 || 蛇头的(x,y) == 蛇身体任意一个 (x,y)。 isEnd(newHead){ // 判定蛇是是否死亡 if(newHead.x >= this.w || newHead.x < 0 || newHead.y >= this.h || newHead.y < 0){ this.setIsEnd(); } let is = this.snake.snakePos.find((item)=>{ //循环查询是否撞到自己 return item.x == newHead.x && item.y == newHead.y; }) if(is){ this.setIsEnd(); //结束游戏 } },setIsEnd(){ clearInterval(this.timeId); //清除蛇的移动定时器 this.isEndP = true; //这个属性是用来是否显示游戏结果界面 }
- -20,20,10,-10,原本是一开用来判定是否当前移动的方向是否和原来的方向冲突,后来发现还是用坐标轴香,也就懒得改了。 intervalMove(d){ // 自动跑 if(!this.isStart) return;//判定是否开始 clearInterval(this.timeId); //清除以前的定时时器 this.timeId = setInterval(()=>{ const head = this.snake.snakePos[this.snake.snakePos.length - 1]; this.move(d); if(this.snakeBody * head.x == this.food.x && this.food.y == this.snakeBody * head.y ){ //蛇吃到食物 this.addHead(d); //新增蛇头,这个不去除尾巴 this.randomFood(); //再次重新生成食物 this.result++; //分数 } },1000/this.level); //this.level级别,决定蛇移动的速度 }, isCuurDes(value = '',x1,x2){ // 判断当前蛇的方向,x1 为新方向,x2为以前的方向,主要是判断点击的按钮是否左右,上下冲突 if((+x1 + +x2) == 0 ) return false; //这里+x1,+x2 是用来把字符串转成数字 if(this.isEndP) return;//当游戏结束无法再修改方向 this.currDes = value; //存下方向 return true; },clickBut(m){// 点击按钮 const value = m.target.dataSet.value; switch(value){ case "-20":{ //上 //判断方向是否相反,如果相反则不切换方向 this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y) && this.intervalMove(this.des[value]); break; } case "20":{// 下 this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y) && this.intervalMove(this.des[value]); break; } case "-10":{ //左 this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x) && this.intervalMove(this.des[value]); break; } case "10":{ // 右 this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x) && this.intervalMove(this.des[value]); break; } case "1": { //开始或暂停 if(this.isEndP) return this.isStart = !this.isStart; if(this.isStart && !this.isEndP){ this.intervalMove(this.currDes); }else{ clearInterval(this.timeId); } break; } } }
-
- 名称 类型 备注 result number 分数 conW number 容器宽度 conH number 容器高度 snakeBody number 蛇身体单位 h number 网格的y长度 w number 网格的x长度 grid Array<Array> 网格地图 food object 食物 timeId number 定时器id level number 游戏难度级别 des Object<Object> 蛇的四个方向 isStart Boolean 判断是否开始 snake Object<Object> 蛇 currDes object 当前蛇前进的方向 isEndP Boolean 判断游戏是否结束
- 名称 参数 备注 init 无 初始化函数 onShow 无 框架生命周期钩子函数 isEnd newHead : object 判断游戏是否结束 setIsEnd 无 设置游戏结束相关数据 randomFood 无 随机生成食物 addHead des : object 增加新头 move des : object 蛇的移动 intervalMove d :object 蛇自动移动 isCuurDes value:object ,x1:string,x2:string 定时器id clickBut m:object 操作蛇的移动的点击事件 reInit 无 重新开始游戏
-
- <div class="container"> <div class="game-container" id="con1" ref="con" > <div class="food" style="left:{{ food.x }}px ;top: {{ food.y }}px;" ></div> <div for="{{snake.snakePos}}" tid="id" class=" {{ $item.flag == 'b' ?'snake-body' : 'snake-head' }}" style="left: {{$item.x * snakeBody}}px;top:{{$item.y * snakeBody}};" > </div> </div> <div class="buts"> <div class="center"> <button data-value="-20" class="but" @click="clickBut"> 上 </button> </div> <div class="center" > <button data-value="-10" class="but" @click="clickBut"> 左 </button> <button data-value="1" class="but" @click="clickBut"> {{ isStart ? '暂停' : '开始' }} </button> <button data-value="10" class="but" @click="clickBut"> 右 </button> </div> <div class="center"> <button data-value="20" class="but" @click="clickBut"> 下 </button> </div> </div> <div class="end" if="{{isEndP == true}}"> <div> <text> 游戏结束! </text> </div> <div> <text> 当前得分:{{result}} 分 </text> </div> <div @click="reInit" style="width: 120px;margin: 10px 0 0 30px; border-radius: 5px;"> <text> 点击重开 </text> </div> </div> <div class="result"> <text> 分数:{{result}} </text> </div></div>
- .container{ height: 100%; width: 100%;}.container,.buts, .end{ display: flex; flex-direction: column; position: relative;}.game-container{ width: 100%; height: 540px; position: relative; background-color: #85ce61;}.snake-head{ height: 20px; width: 20px; position: absolute; border-radius: 10px; background-color: red;}.snake-body{ height: 20px; width: 20px; position: absolute; border-radius: 10px; background-color: white;}.food{ height: 20px; width: 20px; position: absolute; border-radius: 10px; background-color: black;}.center{ display: flex; justify-content:center; height: 50px; margin:2px 0;}.but{ width: 50px; border-radius: 5px; font-weight: 700; margin: 0 2px ; background-color: #85ce61;}.buts{ margin-top:10px ;}.end{ position: fixed; top: 50%; left: 50%; transform: translate(-25%,-100%);}.result{ position: fixed; top: 0; left: 260px;}
- export default { data: { result:0, conW : 0,// 游戏界面宽 conH : 0, snakeBody: 20, h:0, w:0, grid:[], food:{ x:0, y:0 }, timeId:null, // 计时器id level:5,//档位 des:{//蛇的方向 "-20":{ // 向上移动一位 x:0, y:-1, flag: '' }, "20":{//向下 x:0, y:1, flag: '' }, "10":{ //右 x:1, y:0, flag: '' }, "-10":{ //左 x:-1, y:0, flag: '' } }, isStart:false, snake:{ snakePos:null }, currDes:{x:1,y:0}, isEndP:false }, init(){ const snakePos = [ { x : 0, y : 0, flag : 'b', id : Math.random() }, { x : 1, y : 0, flag : 'b', id : Math.random() }, { x : 2, y : 0, flag : 'h', id : Math.random() } ]; this.snake.snakePos = snakePos this.randomFood() }, onShow(){ // 第一次初始化 this.conH = this.$refs["con"].getBoundingClientRect().height ; this.conW = this.$refs["con"].getBoundingClientRect().width ; this.h = Math.floor(this.conH / this.snakeBody); this.w = Math.floor(this.conW / this.snakeBody); for (var i = 0; i < this.w; i++) { this.grid.push([]) for (var j = 0; j < this.h; j++) { this.grid[i].push({ x: i, y: j }); } } this.init(); }, isEnd(newHead){ if(newHead.x >= this.w || newHead.x < 0 || newHead.y >= this.h || newHead.y < 0){ this.setIsEnd(); } let is = this.snake.snakePos.find((item)=>{ return item.x == newHead.x && item.y == newHead.y }) if(is){ this.setIsEnd(); } }, setIsEnd(){ clearInterval(this.timeId) this.isEndP = true } , randomFood(){ //随机生成食物 while(true){ let x = Math.floor(Math.random() * this.conW); let y = Math.floor(Math.random() * this.conH); x = x - (x % this.snakeBody); y = y - (y % this.snakeBody); let is = this.snake.snakePos.find((item)=>{ return item.x == x && item.y == y }) this.food.x = x; this.food.y = y; if(!is) { break; } } }, addHead(des){ const oHead = this.snake.snakePos[this.snake.snakePos.length -1]; const newHead ={ x : oHead.x + des.x, y : oHead.y + des.y, flag : 'h', id : Math.random() } this.isEnd(newHead); this.snake.snakePos.push(newHead); oHead.flag = 'b'; }, move(des){ // 蛇移动时,原头变身体,原尾巴去掉,也就是push一个头,shift一个尾巴 this.addHead(des); this.snake.snakePos.shift(); }, intervalMove(d){ // 自动跑 if(!this.isStart) return clearInterval(this.timeId); this.timeId = setInterval(()=>{ const head = this.snake.snakePos[this.snake.snakePos.length - 1]; this.move(d); if(this.snakeBody * head.x == this.food.x && this.food.y == this.snakeBody * head.y ){ this.addHead(d); this.randomFood(); this.result++; } },1000/this.level); }, isCuurDes(value = '',x1,x2){ // 判断当前蛇的方向,x1 为新方向,x2为以前的方向,主要是判断点击的按钮是否左右,上下冲突 if((+x1 + + x2) == 0 ) return false; if(this.isEndP) return ; this.currDes = value; //存下方向 return true; }, clickBut(m){// 点击按钮 const value = m.target.dataSet.value; switch(value){ case "-20":{ //上 //判断方向是否相反,如果相反则不切换方向 this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y) && this.intervalMove(this.des[value]); break; } case "20":{// 下 this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y) && this.intervalMove(this.des[value]); break; } case "-10":{ //左 this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x) && this.intervalMove(this.des[value]); break; } case "10":{ // 右 this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x) && this.intervalMove(this.des[value]); break; } case "1": { //开始或暂停 if(this.isEndP) return this.isStart = !this.isStart; if(this.isStart && !this.isEndP){ this.intervalMove(this.currDes); }else{ clearInterval(this.timeId); } break; } } }, reInit(){ this.init(); this.isEndP = false; this.isStart = false; this.currDes={x:1,y:0}; }}
- 嗯…问就是要优化。 文章相关附件可以点击下面的原文链接前往下载: https://ost.51cto.com/resource/2199。 想了解更多关于开源的内容,请访问: 51CTO 开源基础软件社区 https://ost.51cto.com。

不知道干啥,那就敲代码吧,写个贪吃蛇,很显然,被自己菜哭了,自己写的贪吃蛇自己都不会玩(ps:我曾经可是在不会死亡的情况下完了好长时间>_<)。
实现效果如下:

- 在onShow钩子函数那里获取到游戏容器的宽高,其实我是不想在这里获取的,但没办法,好像getBoundingClientRect()需要挂载后才能拿到值,在这之前的钩子函数中都拿不到具体的属性值(ps:这是我猜的,因为文档写的很…我找不到只能挨个试)。
- 拿到容器宽高后,根据蛇的身体长度(就是每个小圆点)来确定要划分多少个格子,形成一个坐标轴,后面食物,蛇的移动都根据这坐标轴来确定。
onShow(){ // 第一次初始化
this.conH = this.$refs["con"].getBoundingClientRect().height ;
this.conW = this.$refs["con"].getBoundingClientRect().width ;
this.h = Math.floor(this.conH / this.snakeBody);
this.w = Math.floor(this.conW / this.snakeBody);
for (var i = 0; i < this.w; i++) { //绘制网格
this.grid.push([])
for (var j = 0; j < this.h; j++) {
this.grid[i].push({
x: i,
y: j
});
}
}
this.init(); //初始化函数
}
this.conH = this.$refs["con"].getBoundingClientRect().height ;
this.conW = this.$refs["con"].getBoundingClientRect().width ;
this.h = Math.floor(this.conH / this.snakeBody);
this.w = Math.floor(this.conW / this.snakeBody);
for (var i = 0; i < this.w; i++) { //绘制网格
this.grid.push([])
for (var j = 0; j < this.h; j++) {
this.grid[i].push({
x: i,
y: j
});
}
}
this.init(); //初始化函数
}
用一个数组实现,数组索引0为蛇的尾巴,索引length-1为头。
init(){
const snakePos = [ //蛇的初始化的身体
{
x : 0,
y : 0,
flag : 'b',
id : Math.random()
},
{
x : 1,
y : 0,
flag : 'b',
id : Math.random()
},
{
x : 2,
y : 0,
flag : 'h',
id : Math.random()
}
];
this.snake.snakePos = snakePos; //把初始化的身体赋给蛇
this.randomFood(); //随机生成食物
}
食物随机生成,位置在网格中任意位置,但不能生成在蛇的身体位置中。
randomFood(){ //随机生成食物
while(true){
let x = Math.floor(Math.random() * this.conW);
let y = Math.floor(Math.random() * this.conH);
x = x - (x % this.snakeBody); //x,y化为和蛇身体倍数的坐标
y = y - (y % this.snakeBody);
let is = this.snake.snakePos.find((item)=>{
return item.x == x && item.y == y;
})
this.food.x = x;
this.food.y = y;
if(!is) { //当食物的位置不为蛇不和蛇的位置重叠就跳出结束死循环
break;
}
}
}
蛇的移动是通过对数组的push和shift实现,蛇有移动的方向,根据方向来修改新增蛇头的x和y的值。
des:{//蛇的方向
"-20":{ // 向上移动一位
x:0,
y:-1,
flag: ''
},
"20":{//向下
x:0,
y:1,
flag: ''
},
"10":{ //右
x:1,
y:0,
flag: ''
},
"-10":{ //左
x:-1,
y:0,
flag: ''
}
},
addHead(des){
//添加蛇头 des为蛇的方向,一共有四个方向上下左右,每次移动是都会传一个方向过来
const oHead = this.snake.snakePos[this.snake.snakePos.length -1];
const newHead ={
x : oHead.x + des.x,
y : oHead.y + des.y,
flag : 'h',
id : Math.random()
}
this.isEnd(newHead);
this.snake.snakePos.push(newHead);
oHead.flag = 'b';
},
move(des){ // 蛇移动时,原头变身体,原尾巴去掉,也就是push一个头,shift一个尾巴
this.addHead(des);
this.snake.snakePos.shift();
},
移动图如下:

当蛇头的x >= 地图的x最大值 || x < 0 || 蛇头的Y >= 地图的Y最大值 || Y < 0 || 蛇头的(x,y) == 蛇身体任意一个 (x,y)。
isEnd(newHead){ // 判定蛇是是否死亡
if(newHead.x >= this.w || newHead.x < 0 || newHead.y >= this.h || newHead.y < 0){
this.setIsEnd();
}
let is = this.snake.snakePos.find((item)=>{ //循环查询是否撞到自己
return item.x == newHead.x && item.y == newHead.y;
})
if(is){
this.setIsEnd(); //结束游戏
}
},
setIsEnd(){
clearInterval(this.timeId); //清除蛇的移动定时器
this.isEndP = true; //这个属性是用来是否显示游戏结果界面
}
-20,20,10,-10,原本是一开用来判定是否当前移动的方向是否和原来的方向冲突,后来发现还是用坐标轴香,也就懒得改了。
intervalMove(d){ // 自动跑
if(!this.isStart) return;//判定是否开始
clearInterval(this.timeId); //清除以前的定时时器
this.timeId = setInterval(()=>{
const head = this.snake.snakePos[this.snake.snakePos.length - 1];
this.move(d);
if(this.snakeBody * head.x == this.food.x && this.food.y == this.snakeBody * head.y ){ //蛇吃到食物
this.addHead(d); //新增蛇头,这个不去除尾巴
this.randomFood(); //再次重新生成食物
this.result++; //分数
}
},1000/this.level); //this.level级别,决定蛇移动的速度
},
isCuurDes(value = '',x1,x2){
// 判断当前蛇的方向,x1 为新方向,x2为以前的方向,主要是判断点击的按钮是否左右,上下冲突
if((+x1 + +x2) == 0 ) return false; //这里+x1,+x2 是用来把字符串转成数字
if(this.isEndP) return;//当游戏结束无法再修改方向
this.currDes = value; //存下方向
return true;
},
clickBut(m){// 点击按钮
const value = m.target.dataSet.value;
switch(value){
case "-20":{ //上
//判断方向是否相反,如果相反则不切换方向
this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y)
&& this.intervalMove(this.des[value]);
break;
}
case "20":{// 下
this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y)
&& this.intervalMove(this.des[value]);
break;
}
case "-10":{ //左
this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x)
&& this.intervalMove(this.des[value]);
break;
}
case "10":{ // 右
this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x)
&& this.intervalMove(this.des[value]);
break;
}
case "1": { //开始或暂停
if(this.isEndP) return
this.isStart = !this.isStart;
if(this.isStart && !this.isEndP){
this.intervalMove(this.currDes);
}else{
clearInterval(this.timeId);
}
break;
}
}
}
|
名称 |
类型 |
备注 |
|
result |
number |
分数 |
|
conW |
number |
容器宽度 |
|
conH |
number |
容器高度 |
|
snakeBody |
number |
蛇身体单位 |
|
h |
number |
网格的y长度 |
|
w |
number |
网格的x长度 |
|
grid |
Array<Array> |
网格地图 |
|
food |
object |
食物 |
|
timeId |
number |
定时器id |
|
level |
number |
游戏难度级别 |
|
des |
Object<Object> |
蛇的四个方向 |
|
isStart |
Boolean |
判断是否开始 |
|
snake |
Object<Object> |
蛇 |
|
currDes |
object |
当前蛇前进的方向 |
|
isEndP |
Boolean |
判断游戏是否结束 |
|
名称 |
参数 |
备注 |
|
init |
无 |
初始化函数 |
|
onShow |
无 |
框架生命周期钩子函数 |
|
isEnd |
newHead : object |
判断游戏是否结束 |
|
setIsEnd |
无 |
设置游戏结束相关数据 |
|
randomFood |
无 |
随机生成食物 |
|
addHead |
des : object |
增加新头 |
|
move |
des : object |
蛇的移动 |
|
intervalMove |
d :object |
蛇自动移动 |
|
isCuurDes |
value:object ,x1:string,x2:string |
定时器id |
|
clickBut |
m:object |
操作蛇的移动的点击事件 |
|
reInit |
无 |
重新开始游戏 |
<div class="container">
<div class="game-container" id="con1" ref="con" >
<div class="food" style="left:{{ food.x }}px ;top: {{ food.y }}px;" ></div>
<div for="{{snake.snakePos}}" tid="id"
class=" {{ $item.flag == 'b' ?'snake-body' : 'snake-head' }}"
style="left: {{$item.x * snakeBody}}px;top:{{$item.y * snakeBody}};"
>
</div>
</div>
<div class="buts">
<div class="center">
<button data-value="-20" class="but" @click="clickBut">
上
</button>
</div>
<div class="center" >
<button data-value="-10" class="but" @click="clickBut">
左
</button>
<button data-value="1" class="but" @click="clickBut">
{{ isStart ? '暂停' : '开始' }}
</button>
<button data-value="10" class="but" @click="clickBut">
右
</button>
</div>
<div class="center">
<button data-value="20" class="but" @click="clickBut">
下
</button>
</div>
</div>
<div class="end" if="{{isEndP == true}}">
<div>
<text>
游戏结束!
</text>
</div>
<div>
<text>
当前得分:{{result}} 分
</text>
</div>
<div @click="reInit"
style="width: 120px;margin: 10px 0 0 30px;
border-radius: 5px;">
<text>
点击重开
</text>
</div>
</div>
<div class="result">
<text>
分数:{{result}}
</text>
</div>
</div>
<div class="game-container" id="con1" ref="con" >
<div class="food" style="left:{{ food.x }}px ;top: {{ food.y }}px;" ></div>
<div for="{{snake.snakePos}}" tid="id"
class=" {{ $item.flag == 'b' ?'snake-body' : 'snake-head' }}"
style="left: {{$item.x * snakeBody}}px;top:{{$item.y * snakeBody}};"
>
</div>
</div>
<div class="buts">
<div class="center">
<button data-value="-20" class="but" @click="clickBut">
上
</button>
</div>
<div class="center" >
<button data-value="-10" class="but" @click="clickBut">
左
</button>
<button data-value="1" class="but" @click="clickBut">
{{ isStart ? '暂停' : '开始' }}
</button>
<button data-value="10" class="but" @click="clickBut">
右
</button>
</div>
<div class="center">
<button data-value="20" class="but" @click="clickBut">
下
</button>
</div>
</div>
<div class="end" if="{{isEndP == true}}">
<div>
<text>
游戏结束!
</text>
</div>
<div>
<text>
当前得分:{{result}} 分
</text>
</div>
<div @click="reInit"
style="width: 120px;margin: 10px 0 0 30px;
border-radius: 5px;">
<text>
点击重开
</text>
</div>
</div>
<div class="result">
<text>
分数:{{result}}
</text>
</div>
</div>
.container{
height: 100%;
width: 100%;
}
.container,.buts, .end{
display: flex;
flex-direction: column;
position: relative;
}
.game-container{
width: 100%;
height: 540px;
position: relative;
background-color: #85ce61;
}
.snake-head{
height: 20px;
width: 20px;
position: absolute;
border-radius: 10px;
background-color: red;
}
.snake-body{
height: 20px;
width: 20px;
position: absolute;
border-radius: 10px;
background-color: white;
}
.food{
height: 20px;
width: 20px;
position: absolute;
border-radius: 10px;
background-color: black;
}
.center{
display: flex;
justify-content:center;
height: 50px;
margin:2px 0;
}
.but{
width: 50px;
border-radius: 5px;
font-weight: 700;
margin: 0 2px ;
background-color: #85ce61;
}
.buts{
margin-top:10px ;
}
.end{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-25%,-100%);
}
.result{
position: fixed;
top: 0;
left: 260px;
}
height: 100%;
width: 100%;
}
.container,.buts, .end{
display: flex;
flex-direction: column;
position: relative;
}
.game-container{
width: 100%;
height: 540px;
position: relative;
background-color: #85ce61;
}
.snake-head{
height: 20px;
width: 20px;
position: absolute;
border-radius: 10px;
background-color: red;
}
.snake-body{
height: 20px;
width: 20px;
position: absolute;
border-radius: 10px;
background-color: white;
}
.food{
height: 20px;
width: 20px;
position: absolute;
border-radius: 10px;
background-color: black;
}
.center{
display: flex;
justify-content:center;
height: 50px;
margin:2px 0;
}
.but{
width: 50px;
border-radius: 5px;
font-weight: 700;
margin: 0 2px ;
background-color: #85ce61;
}
.buts{
margin-top:10px ;
}
.end{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-25%,-100%);
}
.result{
position: fixed;
top: 0;
left: 260px;
}
export default {
data: {
result:0,
conW : 0,// 游戏界面宽
conH : 0,
snakeBody: 20,
h:0,
w:0,
grid:[],
food:{
x:0,
y:0
},
timeId:null, // 计时器id
level:5,//档位
des:{//蛇的方向
"-20":{ // 向上移动一位
x:0,
y:-1,
flag: ''
},
"20":{//向下
x:0,
y:1,
flag: ''
},
"10":{ //右
x:1,
y:0,
flag: ''
},
"-10":{ //左
x:-1,
y:0,
flag: ''
}
},
isStart:false,
snake:{
snakePos:null
},
currDes:{x:1,y:0},
isEndP:false
},
init(){
const snakePos = [
{
x : 0,
y : 0,
flag : 'b',
id : Math.random()
},
{
x : 1,
y : 0,
flag : 'b',
id : Math.random()
},
{
x : 2,
y : 0,
flag : 'h',
id : Math.random()
}
];
this.snake.snakePos = snakePos
this.randomFood()
},
onShow(){ // 第一次初始化
this.conH = this.$refs["con"].getBoundingClientRect().height ;
this.conW = this.$refs["con"].getBoundingClientRect().width ;
this.h = Math.floor(this.conH / this.snakeBody);
this.w = Math.floor(this.conW / this.snakeBody);
for (var i = 0; i < this.w; i++) {
this.grid.push([])
for (var j = 0; j < this.h; j++) {
this.grid[i].push({
x: i,
y: j
});
}
}
this.init();
},
isEnd(newHead){
if(newHead.x >= this.w || newHead.x < 0 || newHead.y >= this.h || newHead.y < 0){
this.setIsEnd();
}
let is = this.snake.snakePos.find((item)=>{
return item.x == newHead.x && item.y == newHead.y
})
if(is){
this.setIsEnd();
}
},
setIsEnd(){
clearInterval(this.timeId)
this.isEndP = true
}
,
randomFood(){ //随机生成食物
while(true){
let x = Math.floor(Math.random() * this.conW);
let y = Math.floor(Math.random() * this.conH);
x = x - (x % this.snakeBody);
y = y - (y % this.snakeBody);
let is = this.snake.snakePos.find((item)=>{
return item.x == x && item.y == y
})
this.food.x = x;
this.food.y = y;
if(!is) {
break;
}
}
},
addHead(des){
const oHead = this.snake.snakePos[this.snake.snakePos.length -1];
const newHead ={
x : oHead.x + des.x,
y : oHead.y + des.y,
flag : 'h',
id : Math.random()
}
this.isEnd(newHead);
this.snake.snakePos.push(newHead);
oHead.flag = 'b';
},
move(des){ // 蛇移动时,原头变身体,原尾巴去掉,也就是push一个头,shift一个尾巴
this.addHead(des);
this.snake.snakePos.shift();
},
intervalMove(d){ // 自动跑
if(!this.isStart) return
clearInterval(this.timeId);
this.timeId = setInterval(()=>{
const head = this.snake.snakePos[this.snake.snakePos.length - 1];
this.move(d);
if(this.snakeBody * head.x == this.food.x && this.food.y == this.snakeBody * head.y ){
this.addHead(d);
this.randomFood();
this.result++;
}
},1000/this.level);
},
isCuurDes(value = '',x1,x2){
// 判断当前蛇的方向,x1 为新方向,x2为以前的方向,主要是判断点击的按钮是否左右,上下冲突
if((+x1 + + x2) == 0 ) return false;
if(this.isEndP) return ;
this.currDes = value; //存下方向
return true;
},
clickBut(m){// 点击按钮
const value = m.target.dataSet.value;
switch(value){
case "-20":{ //上
//判断方向是否相反,如果相反则不切换方向
this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y)
&& this.intervalMove(this.des[value]);
break;
}
case "20":{// 下
this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y)
&& this.intervalMove(this.des[value]);
break;
}
case "-10":{ //左
this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x)
&& this.intervalMove(this.des[value]);
break;
}
case "10":{ // 右
this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x)
&& this.intervalMove(this.des[value]);
break;
}
case "1": { //开始或暂停
if(this.isEndP) return
this.isStart = !this.isStart;
if(this.isStart && !this.isEndP){
this.intervalMove(this.currDes);
}else{
clearInterval(this.timeId);
}
break;
}
}
},
reInit(){
this.init();
this.isEndP = false;
this.isStart = false;
this.currDes={x:1,y:0};
}
}
data: {
result:0,
conW : 0,// 游戏界面宽
conH : 0,
snakeBody: 20,
h:0,
w:0,
grid:[],
food:{
x:0,
y:0
},
timeId:null, // 计时器id
level:5,//档位
des:{//蛇的方向
"-20":{ // 向上移动一位
x:0,
y:-1,
flag: ''
},
"20":{//向下
x:0,
y:1,
flag: ''
},
"10":{ //右
x:1,
y:0,
flag: ''
},
"-10":{ //左
x:-1,
y:0,
flag: ''
}
},
isStart:false,
snake:{
snakePos:null
},
currDes:{x:1,y:0},
isEndP:false
},
init(){
const snakePos = [
{
x : 0,
y : 0,
flag : 'b',
id : Math.random()
},
{
x : 1,
y : 0,
flag : 'b',
id : Math.random()
},
{
x : 2,
y : 0,
flag : 'h',
id : Math.random()
}
];
this.snake.snakePos = snakePos
this.randomFood()
},
onShow(){ // 第一次初始化
this.conH = this.$refs["con"].getBoundingClientRect().height ;
this.conW = this.$refs["con"].getBoundingClientRect().width ;
this.h = Math.floor(this.conH / this.snakeBody);
this.w = Math.floor(this.conW / this.snakeBody);
for (var i = 0; i < this.w; i++) {
this.grid.push([])
for (var j = 0; j < this.h; j++) {
this.grid[i].push({
x: i,
y: j
});
}
}
this.init();
},
isEnd(newHead){
if(newHead.x >= this.w || newHead.x < 0 || newHead.y >= this.h || newHead.y < 0){
this.setIsEnd();
}
let is = this.snake.snakePos.find((item)=>{
return item.x == newHead.x && item.y == newHead.y
})
if(is){
this.setIsEnd();
}
},
setIsEnd(){
clearInterval(this.timeId)
this.isEndP = true
}
,
randomFood(){ //随机生成食物
while(true){
let x = Math.floor(Math.random() * this.conW);
let y = Math.floor(Math.random() * this.conH);
x = x - (x % this.snakeBody);
y = y - (y % this.snakeBody);
let is = this.snake.snakePos.find((item)=>{
return item.x == x && item.y == y
})
this.food.x = x;
this.food.y = y;
if(!is) {
break;
}
}
},
addHead(des){
const oHead = this.snake.snakePos[this.snake.snakePos.length -1];
const newHead ={
x : oHead.x + des.x,
y : oHead.y + des.y,
flag : 'h',
id : Math.random()
}
this.isEnd(newHead);
this.snake.snakePos.push(newHead);
oHead.flag = 'b';
},
move(des){ // 蛇移动时,原头变身体,原尾巴去掉,也就是push一个头,shift一个尾巴
this.addHead(des);
this.snake.snakePos.shift();
},
intervalMove(d){ // 自动跑
if(!this.isStart) return
clearInterval(this.timeId);
this.timeId = setInterval(()=>{
const head = this.snake.snakePos[this.snake.snakePos.length - 1];
this.move(d);
if(this.snakeBody * head.x == this.food.x && this.food.y == this.snakeBody * head.y ){
this.addHead(d);
this.randomFood();
this.result++;
}
},1000/this.level);
},
isCuurDes(value = '',x1,x2){
// 判断当前蛇的方向,x1 为新方向,x2为以前的方向,主要是判断点击的按钮是否左右,上下冲突
if((+x1 + + x2) == 0 ) return false;
if(this.isEndP) return ;
this.currDes = value; //存下方向
return true;
},
clickBut(m){// 点击按钮
const value = m.target.dataSet.value;
switch(value){
case "-20":{ //上
//判断方向是否相反,如果相反则不切换方向
this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y)
&& this.intervalMove(this.des[value]);
break;
}
case "20":{// 下
this.isCuurDes(this.des[value],this.des[value].y,this.currDes.y)
&& this.intervalMove(this.des[value]);
break;
}
case "-10":{ //左
this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x)
&& this.intervalMove(this.des[value]);
break;
}
case "10":{ // 右
this.isCuurDes(this.des[value],this.des[value].x,this.currDes.x)
&& this.intervalMove(this.des[value]);
break;
}
case "1": { //开始或暂停
if(this.isEndP) return
this.isStart = !this.isStart;
if(this.isStart && !this.isEndP){
this.intervalMove(this.currDes);
}else{
clearInterval(this.timeId);
}
break;
}
}
},
reInit(){
this.init();
this.isEndP = false;
this.isStart = false;
this.currDes={x:1,y:0};
}
}
嗯…问就是要优化。
文章相关附件可以点击下面的原文链接前往下载:
https://ost.51cto.com/resource/2199。