1、在页面中做好页面布局以及屏幕事件
可以在index文件夹中写代码,也可以在page目录下新建一个snake文件夹来书写。
.wxml文件:
<!--snake.wxml-->
<!-- bindtouchstart:触摸开始;bindtouchmove:触摸移动;bindtouchend:触摸结束 -->
<view class="control" bindtouchstart="tapStart" bindtouchmove="tapMove" bindtouchend="tapEnd">
<view class="score">
<view class="scoredetail">
<button class="btn-start" bindtap="start">开始游戏♪(´▽`)</button>
</view>
<view class="scoredetail">
<view class="scoredesc">得分(* ̄▽ ̄*)</view>
<view class="scorenumber">{{score}}</view>
</view>
</view>
<view class="ground">
<view wx:for="{{ground}}" class="rows" wx:for-item="cols">
<view wx:for="{{cols}}" class="block block_{{item}}">
</view>
</view>
</view>
<view class="scoredetail">
<view class="scoredesc">历史最高分数</view>
<view class="scorenumber">{{maxscore}}</view>
<button class="reset" bindtap="clear">清空</button>
</view>
<modal class="modal" hidden="{{modalHidden}}" no-cancel bindconfirm="modalChange">
<view> 游戏结束,得分{{score}} </view>
</modal>
</view>
wxss文件:
.score {
display: flex;
}
.title {
flex: 1;
height: 150rpx;
line-height: 150rpx;
background: rgb(0, 102, 255);
margin: 40rpx 20rpx 40rpx 40rpx;
text-align: center;
font-size: 1.5rem;
color: white;
border-radius: 8rpx;
}
.scoredetail {
flex: 1;
height: 110rpx;
background: #e9b47e;
margin: 40rpx 20rpx;
text-align: center;
border-radius: 8rpx;
}
.scoredetail:last-child {
margin-right: 40rpx;
position: relative;
}
.scoredesc {
font-size: 0.8rem;
line-height: 60rpx;
}
.btn-start {
height: 100%;
background-color: #e9b47e;
font-weight: 800;
}
.scorenumber {
line-height: 70rpx;
}
.ground {
width: 660rpx;
height: 840rpx;
margin-left: 40rpx;
}
.block {
width: 30rpx;
height: 30rpx;
float: left;
background: #ccc;
}
.rows {
width: 660rpx;
height: 30rpx;
}
.control {
width: 100%;
height: 100%;
}
.block_1 {
background: rgb(25, 0, 255);
}
.block_2 {
background: rgb(255, 0, 0);
}
.reset {
width: 60px;
height: 30px;
font-size: 14px;
margin: 0;
position: absolute;
top: 550px;
left: 20px;
}
2、js逻辑书写
思路分析:
1.实现随机位置出现食物,点击开始游戏时,“蛇”被创建出来并开始移动。
2.捕捉屏幕滑动事件,设置变向函数,改变蛇的移动方向。
3.蛇吃到食物,分数自增,蛇的方块数自增,可设置吃到多次后给予分数奖励。
4.蛇头碰到墙壁或者蛇的身体时,游戏结束,弹出提示弹窗,比较当前分数与本地储存的最高分数,高于则保存,低于则舍弃。
5.设置事件音效,增强反馈效果。
.js文件:
//snake.js
var app = getApp();
Page({
data: {
score: 0, //比分
maxscore: 0, //最高分
startx: 0,
starty: 0,
endx: 0,
endy: 0, //以上四个做方向判断
ground: [], //存储地图每个方块
rows: 28, //地图纵向长度
cols: 22, //地图横向长度
snake: [], //蛇
food: [], //食物
direction: '', //方向
modalHidden: true, //模块隐藏(开)
timer: '',
txt: 0, //一个小标记
},
// 记录最高分
onLoad: function () {
var maxscore = wx.getStorageSync('maxscore');
if (!maxscore) maxscore = 0
this.setData({
maxscore: maxscore
});
this.initGround(this.data.rows, this.data.cols); //初始化地图
this.creatFood(); //初始化食物
},
//点击开始游戏
start: function () {
if (this.data.txt == 0) { //当txt=0时,允许游戏开始
this.sound("start")
this.data.direction = 'right', //初始化移动方向
this.initSnake(4); //初始化蛇,数字为蛇的长度
this.move(); //蛇移动
this.data.txt = 1 //改变txt的值
}
},
//计分器
storeScore: function () {
this.sound("AddScore");
if (this.data.maxscore < this.data.score) {
this.setData({
maxscore: this.data.score
})
wx.setStorageSync('maxscore', this.data.maxscore)
}
},
// 清空最高分
clear: function () {
wx.removeStorageSync('maxscore', this.data.maxscore);
this.setData({
maxscore: 0
});
},
//地图
initGround: function (rows, cols) {
for (var i = 0; i < rows; i++) {
var arr = [];
this.data.ground.push(arr);
for (var j = 0; j < cols; j++) {
this.data.ground[i].push(0);
}
}
},
//蛇
initSnake: function (len) {
for (var i = 0; i < len; i++) {
this.data.ground[0][i] = 1; //前者为蛇的初始纵坐标,后者为蛇的初始横坐标
this.data.snake.push([0, i]);
}
},
//移动函数
move: function () {
var that = this;
this.data.timer = setInterval(function () {
that.changeDirection(that.data.direction);
that.setData({
ground: that.data.ground
});
}, (300)); //蛇的移动速度
},
// 触摸开始点
tapStart: function (event) {
this.setData({
startx: event.touches[0].pageX,
starty: event.touches[0].pageY,
})
},
// 触摸移动事件
tapMove: function (event) {
this.setData({
endx: event.touches[0].pageX,
endy: event.touches[0].pageY
})
},
// 触摸结束点
tapEnd: function (event) {
var heng = (this.data.endx) ? (this.data.endx - this.data.startx) : 0;
var shu = (this.data.endy) ? (this.data.endy - this.data.starty) : 0;
if (Math.abs(heng) > 5 || Math.abs(shu) > 5) {
var direction = (Math.abs(heng) > Math.abs(shu)) ? this.computeDir(1, heng) : this.computeDir(0, shu);
switch (direction) { //防止反方向移动
case 'left':
if (this.data.direction == 'right') return;
break;
case 'right':
if (this.data.direction == 'left') return;
break;
case 'top':
if (this.data.direction == 'bottom') return;
break;
case 'bottom':
if (this.data.direction == 'top') return;
break;
default:
}
this.setData({
startx: 0,
starty: 0,
endx: 0,
endy: 0,
direction: direction
})
}
},
// 判断触摸移动的方向
computeDir: function (heng, num) {
this.sound("Change")
if (heng) return (num > 0) ? 'right' : 'left';
return (num > 0) ? 'bottom' : 'top';
},
creatFood: function () {
var x = Math.floor(Math.random() * this.data.rows);
var y = Math.floor(Math.random() * this.data.cols);
var ground = this.data.ground;
ground[x][y] = 2;
this.setData({
ground: ground,
food: [x, y], //随机生成食物的坐标
});
},
//触发变向事件的代码,左、右、上、下
changeDirection: function (dir) {
switch (dir) {
case 'left':
return this.changeLeft();
break;
case 'right':
return this.changeRight();
break;
case 'top':
return this.changeTop();
break;
case 'bottom':
return this.changeBottom();
break;
default:
}
},
// 变向事件,可以被封装
changeLeft: function () {
var arr = this.data.snake;
var len = this.data.snake.length;
var snakeHEAD = arr[len - 1][1];
var snakeTAIL = arr[0];
var ground = this.data.ground;
ground[snakeTAIL[0]][snakeTAIL[1]] = 0;
for (var i = 0; i < len - 1; i++) {
arr[i] = arr[i + 1];
};
var x = arr[len - 1][0];
var y = arr[len - 1][1] - 1;
arr[len - 1] = [x, y];
this.checkGame(snakeTAIL);
for (var i = 1; i < len; i++) {
ground[arr[i][0]][arr[i][1]] = 1;
}
this.setData({
ground: ground,
snake: arr
});
return true;
},
changeRight: function () {
var arr = this.data.snake;
var len = this.data.snake.length;
var snakeHEAD = arr[len - 1][1];
var snakeTAIL = arr[0];
var ground = this.data.ground;
ground[snakeTAIL[0]][snakeTAIL[1]] = 0;
for (var i = 0; i < len - 1; i++) {
arr[i] = arr[i + 1];
};
var x = arr[len - 1][0];
var y = arr[len - 1][1] + 1;
arr[len - 1] = [x, y];
this.checkGame(snakeTAIL);
for (var i = 1; i < len; i++) {
ground[arr[i][0]][arr[i][1]] = 1;
}
this.setData({
ground: ground,
snake: arr
});
return true;
},
changeTop: function () {
var arr = this.data.snake;
var len = this.data.snake.length;
var snakeHEAD = arr[len - 1][1];
var snakeTAIL = arr[0];
var ground = this.data.ground;
ground[snakeTAIL[0]][snakeTAIL[1]] = 0;
for (var i = 0; i < len - 1; i++) {
arr[i] = arr[i + 1];
};
var x = arr[len - 1][0] - 1;
var y = arr[len - 1][1];
arr[len - 1] = [x, y];
this.checkGame(snakeTAIL);
for (var i = 1; i < len; i++) {
ground[arr[i][0]][arr[i][1]] = 1;
}
this.setData({
ground: ground,
snake: arr
});
return true;
},
changeBottom: function () {
var arr = this.data.snake;
var len = this.data.snake.length;
var snakeHEAD = arr[len - 1];
var snakeTAIL = arr[0];
var ground = this.data.ground;
ground[snakeTAIL[0]][snakeTAIL[1]] = 0;
for (var i = 0; i < len - 1; i++) {
arr[i] = arr[i + 1];
};
var x = arr[len - 1][0] + 1;
var y = arr[len - 1][1];
arr[len - 1] = [x, y];
this.checkGame(snakeTAIL);
for (var i = 1; i < len; i++) {
ground[arr[i][0]][arr[i][1]] = 1;
}
this.setData({
ground: ground,
snake: arr
});
return true;
},
// 若蛇头碰到墙或者自己的身体,游戏结束
checkGame: function (snakeTAIL) {
var arr = this.data.snake;
var len = this.data.snake.length;
var snakeHEAD = arr[len - 1];
if (snakeHEAD[0] < 0 || snakeHEAD[0] >= this.data.rows || snakeHEAD[1] >= this.data.cols || snakeHEAD[1] < 0) {
clearInterval(this.data.timer);
this.sound("ikun");
this.setData({
modalHidden: false,
})
}
for (var i = 0; i < len - 1; i++) {
if (arr[i][0] == snakeHEAD[0] && arr[i][1] == snakeHEAD[1]) {
clearInterval(this.data.timer);
this.setData({
modalHidden: false,
})
}
}
// 得分规则
if (snakeHEAD[0] == this.data.food[0] && snakeHEAD[1] == this.data.food[1] && this.data.score % 50 == 0 && this.data.score != 0) //如果分数达到了50的倍数,除了0分以外吃掉食物都可以得到20分
{
arr.unshift(snakeTAIL);
this.setData({
score: this.data.score + 20 //吃一个食物奖励20分
});
this.storeScore();
this.creatFood();
}
if (snakeHEAD[0] == this.data.food[0] && snakeHEAD[1] == this.data.food[1]) { //如果分数不是50的倍数,或者0分时吃掉食物都可以得到10分
arr.unshift(snakeTAIL);
this.setData({
score: this.data.score + 10 //吃一个食物奖励10分
});
this.storeScore(); //存储分数
this.creatFood(); //再次创建食物
}
},
modalChange: function () {
this.data.txt = 0; //游戏结束时,让txt=0
this.setData({
score: 0,
ground: [],
snake: [],
food: [],
modalHidden: true,
direction: ''
})
this.onLoad();
},
// 游戏音效
sound: function (x) {
const innerAudioContext = wx.createInnerAudioContext()
innerAudioContext.autoplay = false // 是否自动开始播放,默认为 false
innerAudioContext.loop = false // 是否循环播放,默认为 false
wx.setInnerAudioOption({ // ios在静音状态下能够正常播放音效
obeyMuteSwitch: false, // 是否遵循系统静音开关,默认为 true。当此参数为 false 时,即使用户打开了静音开关,也能继续发出声音。
success: function (e) {},
fail: function (e) {}
})
innerAudioContext.src = `/pages/mp3/${x}.mp3`
innerAudioContext.play()
}
});
效果图: