贪吃蛇
最近自学小程序,在练手,就写了个贪吃蛇的代码。借此熟悉下小程序的一些基本元素和语法。
小程序语法上跟js是差不多的。有一些小程序特有的东西。
本篇文章要用到的知识点有:
![](https://images2018.cnblogs.com/blog/1232262/201803/1232262-20180327152321770-706188177.png)
![](https://images2018.cnblogs.com/blog/1232262/201803/1232262-20180327153036706-1654249056.png)
<view class="scoreBar"> <view class="snakeView">Snake</view> <view class="scoreView"> <view class="text">得分</view> <view class="num">{{score}}</view> </view> <view class="scoreView"> <view class="text">最高</view> <view class="num">{{maxscore}}</view> </view> </view> <!-- controller要把ground包起来 --> <view class="controller" bindtouchstart='tapStart' bindtouchmove='tapMove' bindtouchend='tapEnd'> <view class="ground"> <view wx:for="{{ground}}" class="row" wx:for-item="row"> <view wx:for="{{row}}" class="block block_{{item}}"> </view> </view> </view> </view> <!--no-cancel 隐藏cancel按钮 --> <modal class="modal" hidden="{{modalHidden}}" no-cancel bindconfirm="modalChange"> <view>游戏结束,重新开始吗?</view> </modal>
然后是wxss:
.controller{ width: 100%; height: 100%; } .scoreBar{ display: flex; height: 85px; padding: 3px } .scoreBar view{ flex: 1; margin: 3px 3px; border: 1px grey solid; background-color: grey; } .snakeView{ line-height: 70px; text-align: center; font-size: 21px; background-color: deepskyblue !important; border-color: deepskyblue !important; } .text{ text-align: center; font-size: 12px; height:40% !important; line-height: 30px; } .num{ text-align: center; height:40% !important; margin-right: 5px; line-height: 30px; } .ground{ width: 660rpx; height:840rpx; margin-left: 40rpx; /* background-color: #ccc; */ } .row{ width:660rpx; height: 30rpx; } .block{ width:30rpx; height: 30rpx; float: left; background: grey } .block_1{ background:#f00; } .block_2{ background:#0f0; }
接着会发现wxss里面有一些元素是要取值的(这种{{}}就是取值表达式),是从.js文件里面定义的Page对象里面data属性来取。
所以接下来写js里面的名为data的json对象:
var app=getApp(); Page({ data:{ //隐藏modal modalHidden:true, //分数 score:0, maxscore:0, //场地(二维数组,存里面颜色的值,0是灰色,1是红色,2是绿色) ground: [], rows:28, cols:22, //蛇(存的是坐标,例如[[4,5],[5,5],[6,5]],后面会用这个坐标具体修改场地里面的颜色) snake:[], food:[], //方向 direction:'', //起始位置 startx:0, starty:0, //结束位置 endx:0, endy:0, //时间 timer:'', //判断横竖的变量,大于49是竖 probability : Math.floor(Math.random() * 100) } });
getApp()是用来获取小程序实例。
关于Page()函数详细请看:https://mp.weixin.qq.com/debug/wxadoc/dev/framework/app-service/page.html
本篇贪吃蛇只用到了Page的data和onLoad。
data就是页面的初始数据,onLoad是页面加载的回调函数,一个页面只会调用一次。
然后是onLoad函数:
onLoad:function(){ var maxscore = wx.getStorageSync("maxscore") if (!maxscore){ maxscore = 0; } this.setData({ maxscore: maxscore }); this.initGround(this.data.rows, this.data.cols); //初始化蛇 this.initSnake(3); //初始化食物 this.createFood(); //移动 this.move(); },
初始化场地、蛇、食物:
initGround:function(rows,cols){ for(var i=0;i<rows;i++){ var colArr=[] this.data.ground.push(colArr); for(var j=0;j<cols;j++){ this.data.ground[i].push(0) } } }, initSnake: function (len){ var x = Math.floor(Math.random() * this.data.rows); var y = Math.floor(Math.random() * this.data.cols); if (this.data.probability>49){ //heng //if排除越界情况 if (y > this.data.cols - len) { //重新生成 this.initSnake(len) } else { for (var i = 0; i < len; i++) { this.data.ground[x][y + i] = 1; this.data.snake.push([x, y + i]); } } }else{ //shu //if排除越界情况 if (x > this.data.rows-len){ //重新生成 this.initSnake(len) }else{ for (var i = 0; i < len; i++) { this.data.ground[x + i][y] = 1; this.data.snake.push([x + i, y]); } } } }, createFood:function(){ var x=Math.floor(Math.random()*this.data.rows); var y=Math.floor(Math.random()*this.data.cols); var ground=this.data.ground; //不能生成在蛇身体的位置 if (ground[x][y]==1){ this.createFood() }else{ ground[x][y] = 2 this.setData({ ground: ground, food: [x, y] }) } },
这样页面还差一步就能显示了,就是修改utils下面的app.json内容将snake进行加载,把红色框里面的写在第一行就能显示出页面了
接下来是触摸事件(游戏开始和控制方向):
//触发游戏: 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; var direction=''; if(Math.abs(heng)>5 || Math.abs(shu)>5){ //根据横竖判断方向(0:上下,1:左右) 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){ if(heng){ return (num>0)?'right':'left'; } return (num>0)?'bottom':'top'; },
关于触摸事件的对象,他们的结构,我这里将其copy了出来:
{ "type": "touchstart", "timeStamp": 2439, "target": { "id": "", "offsetLeft": 221, "offsetTop": 199, "dataset": {} }, "currentTarget": { "id": "", "offsetLeft": 0, "offsetTop": 91, "dataset": {} }, "touches": [ { "identifier": 0, "pageX": 221, "pageY": 200, "clientX": 221, "clientY": 200 } ], "changedTouches": [ { "identifier": 0, "pageX": 221, "pageY": 200, "clientX": 221, "clientY": 200 } ] }
{ "type": "touchmove", "timeStamp": 2689, "target": { "id": "", "offsetLeft": 161, "offsetTop": 223, "dataset": {} }, "currentTarget": { "id": "", "offsetLeft": 0, "offsetTop": 91, "dataset": {} }, "touches": [ { "identifier": 0, "pageX": 165, "pageY": 365, "clientX": 165, "clientY": 365 } ], "changedTouches": [ { "identifier": 0, "pageX": 165, "pageY": 365, "clientX": 165, "clientY": 365 } ] }
{ "type": "touchend", "timeStamp": 18564, "target": { "id": "", "offsetLeft": 101, "offsetTop": 259, "dataset": {} }, "currentTarget": { "id": "", "offsetLeft": 0, "offsetTop": 91, "dataset": {} }, "touches": [], "changedTouches": [ { "identifier": 0, "pageX": 188, "pageY": 284, "clientX": 188, "clientY": 284 } ] }
然后是蛇的移动:
以左拐弯为例,假如一个竖直的蛇,头向下,并且要左拐弯,那么snake数组里面snake[0]尾巴的坐标都是要去掉的(但是也要单独保存),然后后面的元素往前面copy,最后更新最新蛇头的坐标,逻辑就是这样了。
然后就是将功能用代码实现(主要看left,因为剩下3个方向其实是差不多的):
move: function () { var that = this; this.data.timer = setInterval(function () { that.changeDirection(that.data.direction); that.setData({ ground: that.data.ground }) }, 400); }, 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 snakeArr = this.data.snake; var snakeLen = this.data.snake.length; //蛇尾坐标 var snakeTail = snakeArr[0] var ground = this.data.ground; ground[snakeTail[0]][snakeTail[1]] = 0;//尾巴位置重置颜色 for (var i = 0; i < snakeLen - 1; i++) {//数组元素往前移一位,尾巴剔除 snakeArr[i] = snakeArr[i + 1]; } //修改头的坐标 var x = snakeArr[snakeLen-1][0]; var y = snakeArr[snakeLen - 1][1] - 1;//往左 snakeArr[snakeLen-1]=[x,y] //蛇头坐标(push操作是栈的先进后出) var snakeHead = snakeArr[snakeLen - 1] this.checkGame(snakeTail, snakeArr, snakeLen, snakeHead)//检查游戏是否结束 for(var i=0;i<snakeLen;i++){ ground[snakeArr[i][0]][snakeArr[i][1]] = 1 } this.setData({ ground:ground, snake: snakeArr }) }, changeRight: function () { var snakeArr = this.data.snake; var snakeLen = this.data.snake.length; //蛇尾坐标 var snakeTail = snakeArr[0] var ground = this.data.ground; ground[snakeTail[0]][snakeTail[1]] = 0;//尾巴位置重置颜色 for (var i = 0; i < snakeLen - 1; i++) {//数组元素往前移一位,尾巴剔除 snakeArr[i] = snakeArr[i + 1]; } //修改头的坐标 var x = snakeArr[snakeLen - 1][0]; var y = snakeArr[snakeLen - 1][1] + 1;//往右 snakeArr[snakeLen - 1] = [x, y] //蛇头坐标(push操作是栈的先进后出) var snakeHead = snakeArr[snakeLen - 1] this.checkGame(snakeTail, snakeArr, snakeLen, snakeHead)//检查游戏是否结束 for (var i = 0; i < snakeLen ; i++) { ground[snakeArr[i][0]][snakeArr[i][1]] = 1 } this.setData({ ground: ground, snake: snakeArr }) }, changeTop: function () { var snakeArr = this.data.snake; var snakeLen = this.data.snake.length; //蛇尾坐标 var snakeTail = snakeArr[0] var ground = this.data.ground; ground[snakeTail[0]][snakeTail[1]] = 0;//尾巴位置重置颜色 for (var i = 0; i < snakeLen - 1; i++) {//数组元素往前移一位,尾巴剔除 snakeArr[i] = snakeArr[i + 1]; } //修改头的坐标 var x = snakeArr[snakeLen - 1][0] - 1;//往上 var y = snakeArr[snakeLen - 1][1]; snakeArr[snakeLen - 1] = [x, y] //蛇头坐标(push操作是栈的先进后出) var snakeHead = snakeArr[snakeLen - 1] this.checkGame(snakeTail, snakeArr, snakeLen, snakeHead)//检查游戏是否结束 for (var i = 0; i < snakeLen; i++) { ground[snakeArr[i][0]][snakeArr[i][1]] = 1 } this.setData({ ground: ground, snake: snakeArr }) }, changeBottom: function () { var snakeArr = this.data.snake; var snakeLen = this.data.snake.length; //当前蛇尾坐标 var snakeTail = snakeArr[0] var ground = this.data.ground; ground[snakeTail[0]][snakeTail[1]] = 0;//尾巴位置重置颜色 for (var i = 0; i < snakeLen - 1; i++) {//数组元素往前移一位,尾巴剔除 snakeArr[i] = snakeArr[i + 1]; } //更新当前蛇头的坐标 var x = snakeArr[snakeLen - 1][0] + 1;//往下 var y = snakeArr[snakeLen - 1][1]; snakeArr[snakeLen - 1] = [x, y] //蛇头坐标(push操作是栈的先进后出) var snakeHead = snakeArr[snakeLen - 1] //检查游戏是否结束,判断是否吃到食物,如果吃到,尾巴变长 this.checkGame(snakeTail, snakeArr, snakeLen, snakeHead) for (var i = 0; i < snakeLen; i++) { ground[snakeArr[i][0]][snakeArr[i][1]] = 1 } this.setData({ ground: ground, snake: snakeArr }) }, checkGame: function (snakeTail, snake, len, snakeHead){ //碰到边界 if (snakeHead[0] < 0 || snakeHead[0]>=this.data.rows || snakeHead[1]>=this.data.cols || snakeHead[1] < 0){ clearInterval(this.data.timer); this.setData({ modalHidden:false }) } //头碰到了身体其他部位 for(var i=0;i<len-1;i++){ if (snake[i][0] == snakeHead[0] && snake[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]) {//吃到食物 snake.unshift(snakeTail); this.setData({ score: this.data.score + 10 }); this.storeScore(); this.createFood(); } }, //计分器(刷新最高分) storeScore: function () { if (this.data.maxscore < this.data.score) { this.setData({ maxscore: this.data.score }) wx.setStorageSync("maxscore", this.data.maxscore) } }, modalChange:function(){ this.setData({ scoure:0, ground:[], snake:[], food:[], modalHidden:true, direction:'' }) this.onLoad() }
源码地址:https://download.csdn.net/download/u010591472/10310123
如有不足欢迎指出,欢迎转载~~~