零基础萌新的微信小程序DEMO

博客班级  https://edu.cnblogs.com/campus/zjcsxy/SE2020/
作业要求  https://edu.cnblogs.com/campus/zjcsxy/SE2020/homework/11334
作业目标
  • 编写一个小程序,可以全新编写,也可以学习别人的小程序进行修改
  • 熟悉git代码管理流程,将源代码上传到到github
  • 在博客园班级中写一篇相应的博文
作业源代码 https://github.com/zlc201910161013711/snakegame
学号  31801130
姓名 章立晨
院系 浙大城市学院计算机系 

前言

软件工程的第一次小作业,我之前没有微信小程序的编写经验和WEB前端的相关基础,所以刚刚收到要做这个作业的通知的时候是很慌的。在确定主题的时候也想过很多,咨询了学长,在CSDN和博客园上看了很多教程,最终跟着B站教程,一步一步做了这个粗糙的贪吃蛇小游戏。在这里写一些简单的心得体会,都是最基本的东西(实在是太弱了...)

首先是效果演示:

 

 

 

界面就这一个,游戏的主界面,可以通过手指的上下左右滑动调动蛇头的方向,并且蛇在吃了一个食物后会变长一个单位,并且加10分,在顶部会记录历史最高得分。

游戏界面设计

首先,刚刚创建一个新Project的时候,只有四个文件和一个基础界面。我在App.json文件里面增加了一个页面路径,创建游戏的主界面。

"pages":[
    "pages/snake/snake","pages/index/index",
    "pages/logs/logs"
  ],

刚刚创建完的游戏主界面自带4个文件,分别是Js、Json、Wxss、Wxml。在学习过后我懂了,Js是用于申明整个页面的全局变量和函数的文件,这也是整个Project码量最大的文件。

Json是存放顶部导航栏样式的文件,而Wxss和Wxml分别对应WEB里的css和html文件,用于编写整个界面。

首先要在wxss和wxml文件里编写游戏界面,这里我对着视频学会了怎么调用块状元素View来完成标题块、当前分数块、最高分数块、游戏主操场的设计。

首先是标题块,这里采用的是嵌套的方法,在最外层开一个view,这样这一层里生成的所有块都是最外层指定的类型。这是最外层定义的样式:

.score{
  display: flex;
}

然后标题块的样式,我对着视频学会了如何在wxss里编写来调整想要的标题块的大小、颜色、边框、位置。

这是Title采用的样式

.title{
  flex: 1;
  background: pink;
  height: 150rpx;
  margin: 40rpx 20rpx 40rpx 40rpx;
  text-align: center;
  font-size: 70rpx;
  line-height: 150rpx;
  color: white;
  border-radius: 20rpx;
}

然后是得分块。样式方面和得分是一样的,有一个问题是要在这个块里动态的展示当前的分数,每吃一个食物分数加10。

这里我学会了用两个大括号嵌套一个变量实现这个效果,像这样:

<view class="scoredetail">
      <view class="scoredesc">得分</view>
      <view class="scorenumber">{{score}}</view>
    </view>

这个变量Score就定义在Js文件里。

历史最高分也是同理,在Js文件里多定义一个Maxscore即可。

然后是操场,我采用的方法是定义一个蓝色小块的样式表示操场的一个像素,打印28*22个小块实现操场的样式。这里采用wx:for渲染实现这个效果。

<view class="ground">
    <view class="rows" wx:for="{{ground}}" wx:for-item="cols">
      <view wx:for="{{cols}}" class="block block_{{item}}"></view>
    </view>
  </view>

最后是弹窗部分,当游戏失败的时候(蛇撞到边框),弹出一个重新开始的按钮,这里调用的是Modal组件和wx.showModal

<modal class="modal" hidden="{{modalHidden}}" no-cancel
  bindconfirm="modalConfirm">
    <view>游戏结束,需要重新开始嘛?</view>
  </modal>

游戏核心代码

这个游戏是如何让贪吃蛇动起来的核心代码在Js文件中编写。首先,我们需要在data模块里定义好所有要用到的变量:

data: {
    score:0,//当前得分
    maxscore:900,//历史最高分
    startx:0,//触摸开始的横坐标
    starty:0,//触摸开始的纵坐标
    endx: 0,//触摸结束的横坐标
    endy:0,//触摸结束的纵坐标
    ground:[],//存储操场的每个方块
    rows:28,//行数
    cols:22,//列数
    snake:[],//
    food:[],//食物
    direction:"",//移动方向
    timer:"",//初始化定时器
    modalHidden:true,//modal是否隐藏
    cnt: 0
  },

学习之后我明白了Onload函数的意思是存储一进入界面就要调用的函数,

这里进入界面的时候我需要初始化操场、小蛇、食物、移动函数

onLoad: function (options) {
    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()
  },

初始化最高分的时候要调用Wx的一个接口叫getStorageSync,解决本地缓存问题。

然后是计分器函数的编写,就是当当前分数大于Maxscore的时候更新Maxscore,同时调用getStorageSync接口。

storeScore:function(){
    if(this.data.maxscore<this.data.score){
      this.setData({
        maxscore:this.data.score
      })
    }
    wx.setStorageSync("maxscore", this.data.maxscore)
  }

然后是操场界面的初始化:

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])
    }
  }

食物的初始化:

createFood:function(){
    this.data.cnt=3
    for (var k=1;k<=1;k++) {
      var x = Math.floor(Math.random()*this.data.rows)
      var y = Math.floor(Math.random()*this.data.cols)
      var ground=this.data.ground
      var snake=this.data.snake
      ground[x][y]=3
      //console.log(ground)
      for(var i=0;i<snake.length;i++){
        var node = snake[i][1]
        // console.log(node)
        if (x == 0 && y == node) {
          this.createFood()
          return
        } else {
          this.setData({
            ground: ground,
            food: [x, y]
          })
        }  
    }
  }
  }

这里用0 1 2 分别代表空的块、蛇身、食物。样式里分别定义了block_0 block_1 block_2 这样就可以分别调用三种样式。

编写到这里,贪吃蛇游戏的界面已经成型。但是小蛇还无法动起来。

在学习之后我明白了,可以在函数里加一个参数e,是事件event的简称,在函数里用e.touche[0].PageX e.touch[0].PageY获得当前手指触摸的坐标。

开始触摸函数:

tapStart:function(e){
    // console.log("开始点击")
    // console.log(e)
    this.setData({
      startx:e.touches[0].pageX,
      starty:e.touches[0].pageY
    })
  },

手指触摸移动:

tapMove:function(e){
    // console.log("移动")
    // console.log(e)
    this.setData({
      endx:e.touches[0].pageX,
      endy:e.touches[0].pageY
    })
  }

手指触摸结束实现蛇的形状变化:

tapEnd:function(){
    //获取滑动距离
    var heng=(this.data.endx)?(this.data.endx-this.data.startx):0
    var zong=(this.data.endy)?(this.data.endy-this.data.starty):0
    if(Math.abs(heng)>5||Math.abs(zong)>5){
      var direction = Math.abs(heng) > Math.abs(zong) ? this.computerDir(1, heng) : this.computerDir(0, zong)
      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;
      }
      this.setData({
        direction:direction,
        startx:0,
        starty:0,
        endx:0,
        endy:0
      })
    }
    // console.log(this.data.direction)
  },

获取滑动距离,用后续编写的判断滑动方向的函数来判断滑动方向

移动函数:

move:function(){
    var that=this
    this.data.timer=setInterval(function(){
      that.changeDirection(that.data.direction)
      that.setData({
        ground:that.data.ground
      })
    },300)
  },

学习之后我明白了,这里的Interval是设定一个定时器。按照指定的周期(以毫秒计)来执行注册的回调函数

变换蛇的形状:

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

这是向左变换的,剩余三个方向都是类似的,调整x 和 y的值就行。

游戏状态的判断:

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]<0||snakeHEAD[1]>=this.data.cols){
      clearInterval(this.data.timer)
      this.setData({
        modalHidden:false
      })
    }
    for(var i=0;i<len-1;i++){
      if (snakeHEAD[0] == arr[i][0] && snakeHEAD[1] == arr[i][1]) {
        clearInterval(this.data.timer)
        this.setData({
          modalHidden:false
        })
      }
    }
    if(snakeHEAD[0]==this.data.food[0]&&snakeHEAD[1]==this.data.food[1]){
      arr.unshift(snakeTAIL)
      this.setData({
        score:this.data.score+10
      })
      this.createFood()
      this.storeScore()
    }
  }

先取出蛇头和蛇身长度,当蛇撞到边框时判游戏失败,当蛇撞到自己的时候判游戏失败,当蛇吃到食物时分数加10,同时蛇长度加一。

这就是这个小程序的全部了,我刚刚开始学,只能写一些在大佬们看来非常非常简单的东西,并且肯定有很多出错的地方,接受大家的批评...

posted @ 2020-10-22 11:44  章立晨_软件工程  阅读(250)  评论(2)    收藏  举报