Search code examples
javascriptundefined2d-games

Undefined in Snake Game written in JS


I'm making my own snake game to master my JS and I have the following problem:

I made Movement Log which tracks the position of head of the snake. Every next snake segment should take position due to the log history. Every move sequence function add position coordinates to log. The problem is that some of objects add to the log array are undefined. Can someone tell me why??

//ELEMENTS
const segments = document.querySelectorAll(".segment");
const snake = document.getElementById("snake");
snake.style.position = "absolute";
let moveLog = []; //LOG REMEMBERING MOVEMENTS

//CONFIG

//start position
let position = {
  t: 300,
  l: 300,
  dir: "top",
};
let wonszSize = 30; //SNAKE SIZE
let movementSpeed = 1 * wonszSize;

//EVENTS LISTENERS

document.addEventListener("keydown", Turn);
document.addEventListener("click", () => {
  console.log(moveLog);
}); //I USE IT TO LOOK INTO LOG AND DEBUG

//FUNCTIONS

//REFRESHES POSITION
function setPosition(t, l) {
  snake.style.top = `${t}px`;
  snake.style.left = `${l}px`;
}

//ASIGNMENT OF ID FOR EACH SEGMENT
function SegmentsID() {
  let i = 0;
  segments.forEach((segment) => {
    segment.id = i;
    ++i;
  });
}

//SETTING POSITION OF SEGMENTS (STARTING)
function setSegments(t, l) {
  segments.forEach((segment) => {
    segment.style.top = `${t + segment.id * 30}px`;
    segment.style.left = `${l}px`;
  });
}

//MAKING TURNS
function Turn(e) {
  if (position.dir == "top") {
    switch (e.code) {
      case "KeyA":
        position.dir = "left";
        break;
      case "KeyD":
        position.dir = "right";
        break;
    }
  } else if (position.dir == "left") {
    switch (e.code) {
      case "KeyW":
        position.dir = "top";
        break;
      case "KeyS":
        position.dir = "bot";
        break;
    }
  } else if (position.dir == "bot") {
    switch (e.code) {
      case "KeyA":
        position.dir = "left";
        break;
      case "KeyD":
        position.dir = "right";
        break;
    }
  } else {
    switch (e.code) {
      case "KeyW":
        position.dir = "top";
        break;
      case "KeyS":
        position.dir = "bot";
        break;
    }
  }
}

// CONSTANT MOVEMENT - MARKS COORDINATES IN THE LOG HISTORY /IT'S HISTORY OF HEAD MOVEMENTS
function movement() {
  let logObject = {
    t: position.t,
    l: position.l,
  }; //HERE COMES THE PROBLEM SINCE SOME LOGS ARE NOT ADD AS OBJECTS BUT AS UNDEFINED <---------
  moveLog.push(logObject);
  if (position.dir == "bot") {
    position.t += movementSpeed;
  } else if (position.dir == "top") {
    position.t -= movementSpeed;
  } else if (position.dir == "left") {
    position.l -= movementSpeed;
  } else {
    position.l += movementSpeed;
  }

  setPosition(position.t, position.l); // REFRESH FOR NOW WORKS FOR HEAD ONLY
}

//MOVE ALL THE BODY <- THIS MEANT TO MOVE ALL THE SEGMENTS TO DESTINATIONS IN MOVMENTLOG HISTORY
function bodyMovin() {
  segments.forEach((segment) => {
    let destination = moveLog[moveLog.length - segment.id];
    console.log(destination); // <----SOME ARE UNDEFINED DON'T KNOW WHY
    /* 
    THIS WILL BE HERE IF CODE WORKS.

     RefreshPostion(destination.t, destination.l)
    
    */
  });
}

//TIME
let MoveTimeHead = setInterval(movement, 300);
let MoveTimeBody = setInterval(bodyMovin, 300);

// MAIN
function main() {
  SegmentsID();
  setSegments(position.t, position.l);
  MoveTimeHead;
  MoveTimeBody;
}
main();

HTML:

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./style.css" />
  </head>
  <body>
    <div class="plansza">
      <div class="snake">
        <div class="snake-head segment" id="snake"></div>
        <div class="segment"></div>
        <div class="segment"></div>
        <div class="segment"></div>
      </div>
    </div>
    <script src="app3.js"></script>
  </body>
</html>

Solution

  • If array.length is the number of items in an array then array[array.length - 1] is the last item in the array. If you access array[array.length] you will get undefined

    The problem is in the function bodyMovin with the following line...

    let destination = moveLog[moveLog.length - segment.id];
    

    segment.id starts at 0 and counts up. Thus the first index you use to access the array is moveLog.length - segment.id or moveLog.length - 0 which is one past the last item in the array, and thus the undefined item

    If you use

    let destination = moveLog[moveLog.length - 1 - segment.id];
    

    and as long as there are no segments.id greater than moveLog.length - 1 you will not be getting undefined again as there are no undefined items in the array moveLog.

    However having an index for one array dependent on the number of items in another array is just waiting to bug you again.