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>
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.