2017-08-25 118 views
1

我正在編寫/遵循蛇遊戲編碼教程,並且似乎擊中了一個點,在那裏我發現了教練沒有遇到的錯誤,而且我似乎沒有了解問題的由來。Javascript | P5.JS庫 - 貪吃蛇遊戲(X)未定義

我甚至評論每行描述函數,每一行都可能幫助我找出問題,但我已經消除了。

明確指出存在問題的路線。

完全錯誤透過Chrome控制檯:

Uncaught TypeError: Cannot read property 'x' of undefined
--at Snake.show (snake:95)
--at draw (snake:37)
--at p5.redraw (p5.js:17153)
--at p5. (p5.js:12358)

具體問題的行:

rect(this.tail[i].x, this.tail[i].y, scl, scl); // Draw The Tail At The End.

當我無論碰到一個邊界牆或轉到我最初打算在相反的方向運行到自己與3 +長度的尾巴我得到這個錯誤。 有人可以解釋什麼導致這個錯誤?這一定與死亡方面有關。

全碼:

<!DOCTYPE html> 
<html> 
    <head> 
     <title>Snake Game</title> 
     <script src="http://sethjfreeman.com/resources/jquery-3.1.1.js"></script> 
     <script src="http://sethjfreeman.com/resources/P5/p5.js"></script> 
     <link href="http://sethjfreeman.com/projects/snake.css" rel="stylesheet" type="text/css"> 
    </head> 
    <body> 
     <script> <!-- Uses p5.js Javascript Library --> 
      var s; // Snake Character. 
      var scl = 20; // Size Of Everything. 
      var food; // Food Items. Makes Em Grow When Eatin. 

      function setup() { 
       createCanvas($(window).width() - 10, $(window).height() - 10); // Creates De Canvas For Everything To Be In. 
       s = new Snake(); // Creates A New Snake | Calls Snake Function To Create A Snake |. 
       frameRate(10); // Sloooowwwssss Down The Game To Actully Be Able To Control The Snake. 
       pickLocation(); // Calls Pick Location To Pick A Location For The First Food Item To Be Placed. 
      } 

      function pickLocation() { // A Function To Control Where The Food Goes 
       var cols = floor(width/scl); // Creates An Imaginary Vertical Grid Every 20 Pixels. Floor Is Being Used To Prevent A Column From Being Placed At E.G: 40.6 Pixels. 
       var rows = floor(height/scl); // Creates An Imaginary Horizontal Gird Every 20 Pixels. Floor Is Being Used To Prevent A Column From Being Placed At E.G: 40.6 Pixels. 
       food = createVector(floor(random(cols)), floor(random(rows))); // Assigns Food To Being At The Random Location. 
       food.mult(scl); // Makes Sure The Food Vector Is Set In The 20 Pixels Guide Lines. Not The 20.5 Pixel Guide Lines. 
      } 

      function draw() { // Controls Everything That Is Being Drawn To The Canvas. 
       background(51); // Sets Background To Be A Grayscale Value. 

       if(s.eat(food)) { // Checks If Food Was Eatin, If True Picks A New Location For A Food Peice. 
        pickLocation(); // Calls Pick Locatoin Function. 
       } 
       s.death(); // Calls Death Function. 
       s.update(); // Calls Update Function. 
       s.show(); // Calls Show Function. 

       fill(255, 0, 100); // Sets Food's Background Color. 
       rect(food.x, food.y, scl, scl); // Creates A New Food Item. 
      } 

      function Snake() { // Controls Everything To Do With De Snake Character. 
       this.x = 0; // Holds The X Pos Of Player. 
       this.y = 0; // Holds The Y Pos Of The Player. 
       this.xspeed = 1; // Moves Player (X) Speed. 
       this.yspeed = 0; // Moves Player (X) Speed. 
       this.total = 0; // Holds The Amount Of Squares On Snake. 
       this.tail = []; // History For Where Each Part Of The Body Needs To Go. 

       this.dir = function(x, y) { // Controls The Direction Of The Snake. 
        this.xspeed = x; // Recives The Intput From keyPressed. 
        this.yspeed = y; // Recives The Intput From keyPressed. 
       } 

       this.eat = function(pos) { // Controls What Happens When A Food Item Was Eatin. 
        var d = dist(this.x, this.y, pos.x, pos.y); // Holds The Distance Between Two Points, In This Case, Between The Snake & The Food Item. 
        if(d < 1) { // If The Distance Is Less Than 1 Pixel From Food Item Add 1 To Total. 
         this.total++; 
         return true; 
        } else { // Else Go To Sleep. 
         return false; 
        } 
       } 

       this.death = function() { // Controls When The Player Dies. 
        for(var i = 0; i < this.tail.length; i++) { // Loops Through Snake Length. Loop Used For Checking If Snake Runs Into Self. 
         var pos = this.tail[i]; // Checks Position Of Each Square Of Tail 
         var d = dist(this.x, this.y, pos.x, pos.y); // Holds The Distance Between Two Points, In This Case, Between The Snake Head & The Particular Spot On The Tail Thats Being Hit. 
         if(d < 1) { // If The Pixel Between The Distance, Restart The Player. 
          total = 0; // Resets Total. 
          this.tail = []; // Resets Tail. 
         } 
        } 
       } 

       this.update = function() { // Updates Everything. Simple Right? 
        if(this.total === this.tail.length) { 
         for(var i = 0; i < this.tail.length - 1; i++) { // Loops Through Whole Snake Besides Head. 
          this.tail[i] = this.tail[i + 1]; // Shifts Each Body Square Location By 1. 
         } 
        } 
        this.tail[this.total - 1] = createVector(this.x, this.y); 

        this.x = this.x + this.xspeed * scl; // The X Cords Of Snake Changes Depending On X Speed * The Scale Of The Snake 
        this.y = this.y + this.yspeed * scl; // The Y Cords Of Snake Changes Depending On Y Speed * The Scale Of The Snake 

        this.x = constrain(this.x, 0, width - scl); // Constrains The Snake Between The Left Border And Right Border Of The Sceen 
        this.y = constrain(this.y, 0, height - scl); // Constrains The Snake Between The Top Border And Bottom Border Of The Sceen 
       } 
       /* 
        _____ _____ ____ ____ _  ______ __ __ 
        | __ \| __ \/__ \| _ \| | | ____| \/ | 
        | |__) | |__) | | | | |_) | | | |__ | \/| 
        | ___/| _ /| | | | _ <| | | __| | |\/| | 
        | | | | \ \| |__| | |_) | |____| |____| | | | 
        |_| |_| \_\\____/|____/|______|______|_| |_| 

       */ 
       this.show = function() { 
        fill(255); // Draw The Tail White. 
        for(var i = 0; i < this.tail.length; i++) { // Draw The Tail. 
         rect(this.tail[i].x, this.tail[i].y, scl, scl); // Draw The Tail At The End. 
        } 

        rect(this.x, this.y, scl, scl); 
       } 
      } 

      function keyPressed() { // Checks Which Keys Were Pressed. 
       if(keyCode === UP_ARROW) { // If Up Arrow Was Pressed Move Snake Upwards. 
        s.dir(0, -1); // Because Direction Starts From Left & Top, -1 = Subtract From Top Pos. +1 = Add From Top Pos. 
       } else if(keyCode === DOWN_ARROW) { // If Down Arrow Was Pressed Move Snake Downwards. 
        s.dir(0, 1); // Because Direction Starts From Left & Top, -1 = Subtract From Top Pos. +1 = Add From Top Pos. 
       } else if(keyCode === RIGHT_ARROW) { // If Right Arrow Was Pressed Move Snake Right. 
        s.dir(1, 0); // Because Direction Starts From Left & Top, -1 = Subtract From Top Left. +1 = Add From Top Left. 
       } else if(keyCode === LEFT_ARROW) { // If Left Arrow Was Pressed Move Snake Left. 
        s.dir(-1, 0); // Because Direction Starts From Left & Top, -1 = Subtract From Top Left. +1 = Add From Top Left. 
       } 
      } 
     </script> 
    </body> 
</html> 

回答

1

你將不得不debug程序。 (該教程是處理,但其基本思想是一樣的。)

你知道你的問題是在這條線:

rect(this.tail[i].x, this.tail[i].y, scl, scl); 

而且你知道你的錯誤是:Uncaught TypeError: Cannot read property 'x' of undefined

那告訴你this.tail[i]是未定義的。這通常意味着您試圖訪問this.tail數組不具有的索引(如試圖訪問僅包含10個項目的數組的索引100)。

但是看看你的代碼,你只能循環到this.tail.length,所以它不是那麼簡單。所以現在你必須調試你的代碼才能找出幾件事情:

  • this.tail.length的值是什麼?
  • i的值是多少?
  • 在開始該循環之前,每個索引this.tail處的內容是什麼?

然後,您將需要進一步調試,以確定何時更改this.tail。你有沒有試過用調試器來代碼,或者至少用一張紙和一支鉛筆進行追蹤?

你需要經歷這個過程,直到你明白到底發生了什麼。如果你可以縮小到幾行,並不符合你的期望,那麼請發佈MCVE,我們將從那裏開始。祝你好運。

+0

即使您的評論沒有提供直接的解決方案,我也會100%接受它作爲答案,因爲堆棧溢出不是關於問題和答案,更多是關於尋找答案的過程。這正是我喜歡你的答案的原因。 –

+1

@SethJ。弗里曼我很欣賞這一點,但如果你想吸引其他答案,隨時保持你的問題更長時間。但是編碼絕對是關於解決問題的過程,所以讓我知道你是否想要隨時進行討論。祝你好運。 –

+0

謝謝你讓我的火車回到鐵軌上。問題是由this.death函數引起的。當我向相反的方向發送蛇時,它最初進入了3個以上的尾部,頭部正在進入身體的其餘部分。所以,如果我要去 - >然後去< - 頭部會碰到第二個尾部●然後碰到最後一個尾部□現在身體不見了。同樣可以想象,在身體被抓住之前頭部被壓扁,所以一旦最後一個尾巴部分趕上了被壓扁的頭部,沒有剩下的蛇,並且遊戲困惑在哪裏畫下一個尾巴部分。 –