小白成長日記:寫個貪吃蛇

仍是用的vue,原本覺得不合適,但想法錯了。貪吃蛇並非經過操做dom來完成移動的,而是經過記錄貪吃蛇的路徑來將身體渲染出來。css

通常移動元素,咱們都是變更它的css達到目的,但我在寫貪吃蛇的時候發現這樣很難以實現,參考了網上的資源,發現大部分人是經過記錄貪吃蛇的路徑,保存進數組,經過數組變更來表示貪吃蛇的下一步,主要是增長頭部位置,去除尾部位置,再動態添加css樣式,這樣就達到移動的效果。html

演示

連接描述vue

html&&data:

<div id="snake">
        <table>
        <tr v-for="(col,y) in cols"><td v-for="(row,x) in rows" :class="body(x,y)||showfood(x,y)?'active':''"></td></tr>
        </table>
        <button @click="start()">開始</button>
</div>

data(){
    return{
        rows:'',//橫框
        cols:'',//豎框
        position:[[0,0],[1,0],[2,0],[3,0]],//蛇的初始位置
        direction:1,//方向
        food:[]//食物的位置
    }
},

初始化準備

methods:{
    background(){//生成橫框和豎框的函數
        this.rows=Array(30)
        this.cols=Array(30)
    }, 
    keyboard(){//鍵盤事件
        let _this = this;
        document.onkeydown = function(e){
            if(e.keyCode===37){
                _this.change(-1)
            }else if(e.keyCode===38){
                _this.change(-2)
            }else if(e.keyCode===39){
                _this.change(1)
            }else{
                _this.change(2)
            }
        }
    },
    creatfood(){//創造食物
        this.food[0]=Math.floor(Math.random()*30)
        this.food[1]=Math.floor(Math.random()*30)
    },
    showfood(x,y){//顯示食物
        if(this.food[0]===x&&this.food[1]===y){
            return true
        }
    },
    body(x,y){//顯示身體
        for(i=0;i<this.position.length;i++){//循環身體函數,利用索引和身體位置作畢竟,若是索引和身體數組重合就會添加active樣式
            if(this.position[i][0]===x&&this.position[i][1]===y){
                return true
            }
        }
    },

前期準備就是這麼多,接下來就是跑起來,先聲明一個計時器git

let timer=''

接着就用定時器開始跑github

start(){//開始按鈕
    timer=setInterval(()=>this.autorun(),300)
}

這裏的autorun就是咱們要寫的跑動函數數組

autorun(){                    
    let direction=this.direction//目前方向
    let headX,headY//
        headX=this.position[this.position.length-1][0]//複製蛇頭的X座標
        headY=this.position[this.position.length-1][1]//複製蛇頭的Y座標
        if(direction===1||direction===-1){//若是方向是在左右跑動                        
            direction>0?headX++:headX--//往右跑X座標+1,往左跑X座標-1                                        
        }else{
            direction>0?headY++:headY--//若是方向是在上下跑動,Y座標作對應處理
        }
//此時蛇頭的下一個座標位置就是[headX,headY],接下來就能夠判斷是否結束遊戲,若是結束了,蛇頭就不必添加了
        if(headX<0||headX>29||headY<0||headY>29||this.body(headX,headY)){//當蛇頭下一個位置出了邊界或者這個位置是符合身體函數(即蛇頭撞上了身體)
            alert('Game Over')//結束
            clearInterval(timer)//清除定時器
            this.position=[[0,0],[1,0],[2,0],[3,0]]//還原身體
            this.creatfood()//從新創造食物
            this.direction=1//還原方向
        }else{//若是蛇頭下一個位置是符合規則的                        
            this.position.push([headX,headY])//將下一個位置添加進數組,頭部長一節
            if(headX!==this.food[0]||headY!==this.food[1]){//若是下一個頭部位置不是食物的位置,即吃食物開始                            
                this.position.shift()//咱們將尾部去掉,一長一短實現了蛇的走動
            }else{//若是下一個頭部位置是食物
                this.creatfood()//不去除尾部,再次建立食物(這裏有個小bug,隨機的食物有概率與身體重合)
            }
        }                                    
},
change(dir){//改變方向
    if(Math.abs(dir)===Math.abs(this.direction)){//若是方向相同或者想法,不作任何操做
        return
    }else{
        this.direction=dir//不然把方向改動
    }
},

就是這個樣子,貪吃蛇就寫完了,邏輯方面並非太複雜,可是對於數組的操做有不少,這裏提下我遇見的幾個問題:dom

  • vue中的數組對象在更新的時候和單獨的數據是不同的,只有某些特定的函數會去主動更新數組,不然的話須要用vm.$set( target, key, value )這個去更新數組
  • 二維數組和一維數組是不一樣的,indexOf()無論用,沒法檢測;並且相似this.position[0]===[0,0]也是沒法正確判斷的,這致使我在寫這個小demo的時候犯了不少錯。
let po=[[0,0],[1,0],[2,0],[3,0]]
let qo=[[0,0]]
let oo=[0,0]
console.log(po[0]==qo[0])//false
console.log(qo[0]==oo)//false

這大概就是最大的收穫,我還太年輕。
由於JavaScript裏面Array是對象,==或===操做符只能比較兩個對象是不是同一個實例,也就是是不是同一個對象引用。目前JavaScript沒有內置的操做符判斷對象的內容是否相同。
可是慣性思惟讓人覺得數組也是值,是能夠比較的。(這段是複製的,別人總結的,和我想法如出一轍)但願能給同爲小白的朋友們提個醒函數

源碼

https://github.com/yuyeqianxu...
但願能幫助到和我同樣的小白朋友們,有bug麻煩反饋,謝謝!this

相關文章
相關標籤/搜索