微信小程序-貪食蛇

很久很久以前,差不多大半年前吧,筆者發(fā)布了一篇關(guān)于OC版貪食蛇開(kāi)發(fā)的文章,時(shí)隔多月,微信小程序橫空出世,于是閑來(lái)無(wú)事的我又寫了一個(gè)小程序版

下面這段話請(qǐng)務(wù)必閱讀

筆者是做iOS的,而小程序大部分都是前端的知識(shí),筆者之前沒(méi)有做過(guò)類似開(kāi)發(fā),所以代碼寫的相當(dāng)爛,很多東西都是一邊查資料一邊寫的,請(qǐng)各位輕噴,阿門!

進(jìn)入正題

頁(yè)面布局

關(guān)于小程序筆者就不做介紹了,官方有詳細(xì)文檔,我們還是先來(lái)看張圖吧

就是這個(gè)樣子的,游戲界面跟之前的OC版是差不多的,以筆者的水平,只能設(shè)計(jì)成這樣了,畢竟不是專業(yè)的,話說(shuō)這蛇怎么長(zhǎng)的像個(gè)J(和)B(諧)啊??

先來(lái)看看用來(lái)添加組件的wxml文件

<view class="backView">
  <canvas canvas-id="snakeCanvas" class="canvas"/>
</view>
<view class="controlView">
    <button class="btnClass" bindtap="changeDirection" id="up">up</button>
    <view style="display:flex; height:33.33%">
        <button class="btnClass" bindtap="changeDirection" id="left">left</button>
        <button class="btnClass" bindtap="startGame" >{{btnTitle}}</button>
        <button class="btnClass" bindtap="changeDirection" id="right">right</button>
    </view>
    <button class="btnClass" bindtap="changeDirection" id="down">down</button>
</view>

內(nèi)容是相當(dāng)簡(jiǎn)單滴,上面一個(gè)view,里面放一個(gè)畫布,下面一個(gè)view,里面放5個(gè)按鈕

再來(lái)看看wxss布局

內(nèi)容不多,其實(shí)筆者對(duì)CSS也不是很了解,很多年前學(xué)習(xí)過(guò),然而早隨著??排出去了,也許還有更優(yōu)的布局方式,不過(guò)湊合著用吧

功能實(shí)現(xiàn)

布局還是很簡(jiǎn)單的,雖然不熟,但是多嘗試幾下還是可以弄出來(lái)的,接下來(lái)功能邏輯的實(shí)現(xiàn)才是重點(diǎn),編程語(yǔ)言當(dāng)然是js了。

話說(shuō)筆者當(dāng)年學(xué)js的時(shí)候,可是寫了滿滿一本的筆記,然而......算了,過(guò)去的就讓他過(guò)去吧,往事不提也罷。

思路其實(shí)與OC版的一樣

蛇:創(chuàng)建一個(gè)點(diǎn)坐標(biāo)數(shù)組,然后以坐標(biāo)點(diǎn)為中心在畫布上畫矩形
食物:隨機(jī)一個(gè)坐標(biāo)點(diǎn),該點(diǎn)不能在蛇身上,否則重新隨機(jī)
蛇的移動(dòng):把蛇尾的坐標(biāo)移到蛇頭前面就行了
吃到食物:每次蛇移動(dòng)完畢后,如果蛇頭的坐標(biāo)與食物的坐標(biāo)一樣,則蛇增長(zhǎng)
蛇的增長(zhǎng):在蛇尾后面加一個(gè)點(diǎn)坐標(biāo)即可
游戲結(jié)束:蛇頭越界或撞到自己身體即游戲結(jié)束

創(chuàng)建蛇
//創(chuàng)建蛇,初始為5節(jié),nodeWH為矩形的邊長(zhǎng)
function createSnake(){
  nodes.splice(0, nodes.length) //清空數(shù)組
  for (var i = 4; i >= 0; i--) {
    var node = new Node(nodeWH * (i + 0.5), nodeWH * 0.5)
    nodes.push(node);
  }
}
創(chuàng)建食物
function createFood(){
  //矩形的邊長(zhǎng)為10,畫布寬度為250,高度為350,所以x只能取5-245,y只能取5-345
  var x = parseInt(Math.random() * 24) * nodeWH + nodeWH * 0.5
  var y = parseInt(Math.random() * 34) * nodeWH + nodeWH * 0.5

  //如果食物的坐標(biāo)在蛇身上,則重新創(chuàng)建
  for (var i = 0; i < nodes.length; i++) {
    var node = nodes[i]
    if (node.x == x && node.y == y) {
      createFood()
      return
    }
  }
  //Node為自定義的類,有兩個(gè)屬性x和y,表示坐標(biāo)
  food = new Node(x,y)
}
蛇的移動(dòng)

蛇的移動(dòng)是有方向的,所以用一個(gè)變量direction來(lái)記錄蛇的移動(dòng)方向,游戲開(kāi)始時(shí),默認(rèn)是向右移動(dòng)。

上面有說(shuō)到蛇的移動(dòng)就是把蛇尾的坐標(biāo)移到蛇頭前面,但是這個(gè)前面并不是固定的,而是根據(jù)方向來(lái)判斷的,如果向右移動(dòng)則右邊為前方,以此類推

吃到食物與蛇增長(zhǎng)

每次移動(dòng)完畢后,判斷蛇頭的坐標(biāo)是否與食物的坐標(biāo)相等就OK了,吃到食物后蛇的長(zhǎng)度會(huì)增加,并且要?jiǎng)?chuàng)建一個(gè)新的食物

function isEatedFood(){
  var head = nodes[0]
  if (head.x == food.x && head.y == food.y) {
    score++
    nodes.push(lastPoint)
    createFood()
  }
}

上面的代碼中,lastPoint就是蛇每次移動(dòng)前,蛇尾的坐標(biāo),如果移動(dòng)后吃到食物,那么直接在移動(dòng)前的蛇尾處加上一節(jié)即可

游戲結(jié)束

每次移動(dòng)后,都要判斷蛇頭是否超過(guò)畫布,或者撞到自己的身體

function isDestroy(){
  var head = nodes[0]
  //判斷是否撞到自己身體
  for (var i = 1; i < nodes.length; i++) {
    var node = nodes[i]
    if (head.x == node.x && head.y == node.y) {
      gameOver()
    }
  }
  //判斷水平方向是否越界
  if (head.x < 5 || head.x > 245) {
    gameOver()
  }
  //判斷垂直方向是否越界
  if (head.y < 5 || head.y > 345) {
    gameOver()
  }
}
界面繪制

每次移動(dòng)都要繪制,所以需要一個(gè)定時(shí)器,筆者用的setInterval

function move(){
  lastPoint = nodes[nodes.length - 1]
  var node = nodes[0]
  var newNode = {x: node.x, y: node.y}
  switch (direction) {
    case 'up':
      newNode.y -= nodeWH;
    break;
    case 'left':
      newNode.x -= nodeWH;
    break;
    case 'right':
      newNode.x += nodeWH;
    break;
    case 'down':
      newNode.y += nodeWH;
    break;
  } 
  nodes.pop()
  nodes.unshift(newNode)
  moveEnd()
}

function startGame() {
  if (isGameOver) {
    direction = 'right'
    createSnake()
    createFood()
    score = 0
    isGameOver = false
  }
  timer = setInterval(move,300)
}

網(wǎng)上說(shuō)setInterval的性能并不怎么好,建議用requestAnimationFrame,但是很遺憾,筆者不會(huì)用,準(zhǔn)確的說(shuō)是不知道怎么暫停

var animateId = 0
function move(){
    .
    .
    .
    animateId = requestAnimationFrame(move)
}
function startGame(){
    .
    .
    .
    animateId = requestAnimationFrame(move)
}

使用上面的方法可以實(shí)現(xiàn)蛇的移動(dòng)與界面重繪,然而每次執(zhí)行animateId都會(huì)被賦予新的值,所以使用cancelAnimationFrame(animateId)無(wú)法暫停,如果有懂前端開(kāi)發(fā)的大神請(qǐng)指導(dǎo)下

差不多整個(gè)邏輯就是這樣的,喜歡研究的可以自己嘗試下,需要源碼的請(qǐng)自行下載,不要問(wèn)我怎么打開(kāi),不要問(wèn)我怎么打開(kāi),不要問(wèn)我怎么打開(kāi)?。。?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 關(guān)于于小程序筆者就不做介紹了,官方有詳細(xì)文檔,我們還是先來(lái)看張圖吧 就是這個(gè)樣子的,游戲界面跟之前的OC版是差不多...
    Programmer客棧閱讀 3,132評(píng)論 0 0
  • 前言 閑著沒(méi)事干,想起多年前學(xué)java時(shí),筆者擼過(guò)的俄羅斯方塊,坦克大戰(zhàn),貪食蛇,現(xiàn)如今已拋棄java多年,投入i...
    codingZero閱讀 8,232評(píng)論 12 54
  • 前天犯賤登錄了騙子的蘋果ID, 結(jié)果自己的ipad被騙子遠(yuǎn)程鎖定了, 如今變磚頭, 心情很down, 故參考網(wǎng)友的...
    imbaWales閱讀 1,409評(píng)論 3 11
  • 最近在做一個(gè)貪吃蛇的項(xiàng)目,這是我第一次用js來(lái)實(shí)現(xiàn)做一款游戲,雖然很low,但出現(xiàn)預(yù)想的效果時(shí)還是很開(kāi)心的,雖然做...
    風(fēng)之傷_3eed閱讀 343評(píng)論 0 0
  • 今天我發(fā)小結(jié)婚了,婚禮我沒(méi)有去, 因?yàn)樗麤](méi)有邀請(qǐng)我 我仔細(xì)想了下他為什么不邀請(qǐng)我 我覺(jué)得問(wèn)題還是在我身上 可能是因...
    毛衣毛閱讀 668評(píng)論 0 0

友情鏈接更多精彩內(nèi)容