Reputation: 21
Okay, so I'm fairly new to programming. I've been learning to code for quite sometime now, but I hadn't really MADE anything. That considered, I'm attempting to make my first project using JavaScript and make a snake game. Unfortunately, I've ran into multiple problems, which obviously is something that comes hand in hand with programming, but I am new and I'm stuck. Can someone help me figure out if I'm coding this in an efficient way. Also, I have a more specific issue. I've added basic movement functionality to the head of my snake, but I can't figure out how to get the rest of it's parts to follow. If someone could explain to me how to do this, that would be incredible. I've worked about two weeks now to try and figure it out and I'm just stumped. I'm using Raphael's JavaScript Library to generate the graphics on an SVG canvas.
/*
Libraries in use:
1. Rapheal
2. jQuery
*/
// This variable is set to an array so that we can add multiple snakeParts to our PrimarySnake.
var snakeParts = [],
// This variable uses Raphael to generate a canvas.
snakeCanvas = Raphael(10, 10, 400, 400),
// This generates a rectangle that fills the canvas.
snakeCanvasBg = snakeCanvas.rect(0,0,400,400),
// This variable is set to an array so that we can use each and every direction that is pressed.
direction = [],
// This variable is set to an array so that we can use the turn coordinates of our first snake part.
turnCoords = [];
// Generates and returns a random number between 0 and 400. This function is used to help generate the goal of our snake at a random location on the canvas.
function getRandNum () {
var rand = Math.round(Math.random()*400);
// This while loop ensures that our snakeGoal never exceeds the coordinates x = 390 or y = 390. If it did, it's parts would be cut from the canvas.
while (rand > 395) {
rand = Math.round(Math.random()*400);
}
// This while loop ensures that our rand variabe will always be divisible by 10, which is used to make sure our snakeGoal and snakePart elements are always rendered in coordinates divisible by 10.
while (rand % 10 !== 0) {
var randString = rand.toString(),
// This variable stores the whole length of our randString variable.
randStringLength = randString.length,
// This variable stores the last number of our rand as a string character.
subtractionChar = randString.charAt(randStringLength - 1),
// This variable stores the last number of our rand as a integer.
subtractionInt = parseInt(subtractionChar),
// Finally, this line subtracts the last number of our rand from the entirety and then sets that value equal to rand, ensuring that rand is always divisible by 10.
rand = rand - subtractionInt;
}
return rand;
}
// This function is called any time a button is pressed. The jQuery which method allows our code to compare if the key pressed is equal to the keyCode of a designated key.
$(document).keydown(
function (pressedDirection) {
if (pressedDirection.which === 37) {
direction.push("left");
} else if (pressedDirection.which === 38) {
direction.push("up");
} else if (pressedDirection.which === 39) {
direction.push("right");
} else if (pressedDirection.which === 40) {
direction.push("down");
} else if (pressedDirection.which === 32) {
direction.push("stop");
}
if (pressedDirection.which === 37 || pressedDirection.which === 38 || pressedDirection.which === 39 || pressedDirection.which === 40 || pressedDirection.which === 32) {
console.log(direction[direction.length - 1]);
PrimarySnake.addTurnCoords();
PrimarySnake.movePeice();
}
// This prevents our screen from scrolling when an arrow key is
pressedDirection.preventDefault();
}
);
function Snake () {
// This method generates a new peice to the Snake.
this.addPart = function () {
console.log(snakeParts.length);
snakeParts[snakeParts.length] = snakeCanvas.rect(0,0,10,10);
snakeParts[snakeParts.length - 1].attr("fill", "blue");
snakeParts[snakeParts.length - 1].attr("stroke-width", ".25");
}
// This method provides the movement functionality of our Snake.
this.moveDirection = function () {
for (value in snakeParts) {
var currentCoord = [snakeParts[value].attr("x"), snakeParts[value].attr("y")];
// This if-else statement moves the snakePart at the -value- index up, down, left, or right according to the last direction pressed.
if (direction[direction.length - 1] === "up") {
snakeParts[value].attr("y", currentCoord[1] - 10);
} else if (direction[direction.length - 1] === "down") {
snakeParts[value].attr("y", currentCoord[1] + 10);
} else if (direction[direction.length - 1] === "left") {
snakeParts[value].attr("x", currentCoord[0] - 10);
} else if (direction[direction.length - 1] === "right") {
snakeParts[value].attr("x", currentCoord[0] + 10);
}
}
}
this.moveInterval;
// This function makes our moveDirection move our snakePeice every 50 milliseconds.
this.movePeice = function () {
var moveDirection = this.moveDirection;
// clearInterval is used to eliminate any interval previously running, ensuring that our peices only move one direction at a time.
clearInterval(this.moveInterval);
this.moveInterval = setInterval(function(){moveDirection()}, 50);
}
// This function adds an array of coordinates to the turnCoords array.
this.addTurnCoords = function () {
turnCoords.push([snakeParts[0].attr("x"), snakeParts[0].attr("y")]);
}
}
// This generates a new instance of our Snake class.
var PrimarySnake = new Snake();
// This generates a new part on the canvas.
PrimarySnake.addPart();
// This fills our snakeCanvasBg with a grey color, giving us a grey background.
snakeCanvasBg.attr("fill", "#CDCDCD");
Upvotes: 0
Views: 51
Reputation: 58
Well, your code seems nice, or at least "efficient" as you are calling it.
To make the parts of your snake follow its head, you must iterate through its parts and assign each (n+1) piece the coordinates from (n). To do so, start with the last piece and iterate up to the first one, which movement is defined by the user, like in:
this.moveDirection = function () {
// Move every piece except the head.
for (var i = snakeParts.length - 1; i > 0; i--) {
snakeParts[i].attr("x", snakeParts[i-1].attr("x"));
snakeParts[i].attr("y", snakeParts[i-1].attr("y"));
}
// Now move the head.
if (direction[direction.length - 1] === "up") {
snakeParts[value].attr("y", currentCoord[1] - 10);
} else if (direction[direction.length - 1] === "down") {
snakeParts[value].attr("y", currentCoord[1] + 10);
} else if (direction[direction.length - 1] === "left") {
snakeParts[value].attr("x", currentCoord[0] - 10);
} else if (direction[direction.length - 1] === "right") {
snakeParts[value].attr("x", currentCoord[0] + 10);
}
}
That code may need a bit of work but that's the idea. Hope it helps!
Upvotes: 1