当前位置:首页 >时尚 >OpenHarmony基于JS实现的贪吃蛇 数组索引0为蛇的尾巴

OpenHarmony基于JS实现的贪吃蛇 数组索引0为蛇的尾巴

2024-06-29 07:25:11 [百科] 来源:避面尹邢网

OpenHarmony基于JS实现的实蛇贪吃蛇

作者:阿毛0920 系统 OpenHarmony 根据蛇的身体长度(就是每个小圆点)来确定要划分多少个格子,形成一个坐标轴,贪吃后面食物,实蛇蛇的贪吃移动都根据这坐标轴来确定。

​​想了解更多关于开源的实蛇内容,请访问:​​

OpenHarmony基于JS实现的贪吃蛇 数组索引0为蛇的尾巴

​​51CTO 开源基础软件社区​​

OpenHarmony基于JS实现的贪吃蛇 数组索引0为蛇的尾巴

​​https://ost.51cto.com​​

OpenHarmony基于JS实现的贪吃蛇 数组索引0为蛇的尾巴

前言

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

实现效果如下:

 #夏日挑战赛# OpenHarmony基于JS实现的贪吃贪吃蛇-开源基础软件社区

具体实现思路

容器初始化

  1. 在onShow钩子函数那里获取到游戏容器的宽高,其实我是实蛇不想在这里获取的,但没办法,贪吃好像getBoundingClientRect()需要挂载后才能拿到值,实蛇在这之前的钩子函数中都拿不到具体的属性值(ps:这是我猜的,因为文档写的很…我找不到只能挨个试)。
  2. 拿到容器宽高后,根据蛇的身体长度(就是每个小圆点)来确定要划分多少个格子,形成一个坐标轴,后面食物,蛇的移动都根据这坐标轴来确定。
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();

},

移动图如下:

 #夏日挑战赛# OpenHarmony基于JS实现的贪吃蛇-开源基础软件社区

蛇的死亡判定

当蛇头的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

重新开始游戏

代码

HTML

<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>

css

.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;
}

JS

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​​。

责任编辑:jianghua 来源: 鸿蒙社区 JS应用开发

(责任编辑:焦点)

    推荐文章
    • 北交所开市首日三大看点 10股盘中均二次临停

      北交所开市首日三大看点 10股盘中均二次临停11月15日,中国多层次资本市场建设又将迎来里程碑事件——筹备了两个多月的北交所正式开市。从当日市场表现来看,新股表现可谓惊艳。据Wind数据统计,10只新股当日平均涨幅近20 ...[详细]
    • 割双眼皮什么梗

      割双眼皮什么梗双眼冒光是什么梗?意思就是双眼看见了盼望已久的人或物时的眼光状态。意思就是双眼看见了盼望已久的人或物时的眼光状态。单眼皮是什么梗?单眼皮就是上眼皮是单层的。单眼皮和双眼皮都跟遗传基因有关。单眼皮就是上 ...[详细]
    • 熟剩香辣蟹过夜能吃吗

      熟剩香辣蟹过夜能吃吗隔夜的香辣蟹可以吃吗?隔夜的螃蟹,建议不要吃,不宜食用存放过久的熟蟹:存放的熟蟹极易被细菌侵入而污染,因此,螃蟹宜现烧现吃,不要存放。万一吃不完,剩下的一定要保存在干净、阴。香辣蟹过夜了还可以吃吗?香 ...[详细]
    • 歌曲先生再见

      歌曲先生再见前言:答:《先生再见》歌曲是陈瑞根据卢慕贞写给孙中山的离别信改编而来的,这首歌曲并不是写给谁的。其实《先生再见》也是一封信,原本是卢慕贞和孙中山离婚时,写给孙中山的。信中表达了卢氏的豁达大度,但也流露 ...[详细]
    • 比速科技(01372.HK)发布公告:拟发行4000万股认购股份

      比速科技(01372.HK)发布公告:拟发行4000万股认购股份比速科技(01372.HK)发布公告,2021年3月7日,公司(作为发行人)与各认购人订立认购协议,内容有关按认购价每股4.80港元认购合共4000万股认购股份。认购股份合共相当于公司现有已发行股本2 ...[详细]
    • 59负重轮是什么梗

      59负重轮是什么梗如何区分59,69坦克59式坦克,主炮是100毫米线膛炮,69式坦克,主炮是100毫米滑膛炮。59式坦克,发动机功率382千瓦,69式坦克,发动机功率426千瓦。59式坦克,...为什么中国坦克用五对 ...[详细]
    • 尿酸高如何降低

      尿酸高如何降低前言:怎样降低尿酸在生活中,经常会有一些尿酸高的情况的出现,那么对于这种情况,大家有什么了解呢?尿酸高怎么办呢?相信大家很想了解一下,下面就让我们来好好了解一下关于这些方面的情况吧,希望对大家能够有所 ...[详细]
    • 怎么样提高新陈代谢

      怎么样提高新陈代谢前言:如何提高新陈代谢?新陈代谢提高的标准就是基础代谢率的提高,基础代谢率是指我们安静状态所消耗的能量。一般怎样提高我们的新陈代谢,可以通过两方面:一个就是饮食;另一个是运动。饮食要注意以下几点:第一 ...[详细]
    • 银保监会完善相关政策措施 支持符合绿色低碳发展需求的保险产品和服务

      银保监会完善相关政策措施 支持符合绿色低碳发展需求的保险产品和服务11月19日,中国银保监会新闻发言人就保险机构支持绿色、低碳、循环经济发展的主要进展,以及下一步在推动实现碳达峰碳中和目标上有什么具体考虑等相关问题回答了记者的提问。中国银保监会表示,支持保险机构规范 ...[详细]
    • 鸟为什么会有气味

      鸟为什么会有气味鸟为什么会有气味?能正常新陈代谢的动物都有气味,鸟常时期在上空飞翔,大气污染和灰尘都会首先沾到羽毛上,就会有气味。鸟,又称作鸟儿。体表被覆羽毛的卵生脊椎动物,鸟的主要特。为什么鸟会无缘无故的臭?能正常 ...[详细]
    热点阅读