Stopping a function, Arrays, and Integer Check - javascript
So I made code for creating 5 ships in a battleship game. I succesfully made some code that layed out all the players ships. It had no bugs. I had the player write out the cords for where he wanted to position his ship. It would then write in the ship position to the corresponding part in a two dimensional array which was the game map.. Of course the cords had to be integers or it would crash and burn.
So I then made something to check if the coordinate was a integer before doing anything else. If it wasn't it would restart the function making so that the rest of the function wouldn't run. If you write in the numbers correctly there are no problems. The problem is that if you don't write in a number the function does restart but the function or some part of it must still be running because a ship gets written to the array for no reason. The cords haven't even been specified for it so I have no clue how this can be possible.
Here is the code I made for checking if its an integer and restarting the function.
userYTest = parseInt(prompt("Horizontal Coordinate position for the first unit of a ship"));
userXTest = parseInt(prompt("Vertical Coordinate position for the first unit of a ship"));
if(userXTest % 1 === 0 && userYTest % 1 === 0) {
userY = userYTest-1;
userX = userXTest-1;
direction = prompt("Now choose the direction you want the rest of your ship to face. You may use the words left, right up, or down.").toLowerCase();
}
else{
window.alert("You must enter a number between one and ten for the two coordinates.");
ship();
//ship is the name of the function
}
Here is all the code.
//These are all the different game boards you need to keep track of. Two possible values in each position 1 or 0
var user = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var cpu = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var userGuessed = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var userHit = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var cpuGuessed = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var cpuHit = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
var clearBoard = [[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0]];
// These are just used to set left the game board.
// I counted 10 by 10 - it should be 10 by 10
var userY = 0;
var userX = 0;
var cpuX = 0;
var cpuY = 0;
var cpuDir = 0;
var cpuWork = false;
var direction = "";
var isThere = false;
var i=0;
var userXTest;
var userYTest;
// In battleship, there is 1x5 length ship, 1x4 length ship, 2 1x3 length ship, and 1x2 length ship. down now it checks how many units are covered to see if you have all the ships. Later we need to add so they ships are the down shape
//User will add their ships here one by one. If you can think of a better have a go at it!
for(i=0;i<4;i++){
if (i===0){
window.alert("We will be placing your 1 by 5 length ship. Take note that you are playing on a 10 by 10 board.");
ship();
}
if (i===1){
window.alert("We will be placing your 1 by 4 length ship. Take note that you are playing on a 10 by 10 board.");
ship();
}
if (i===2){
window.alert("We will be placing your two 1 by 3 length ships. Take note that you are playing on a 10 by 10 board.");
ship();
ship();
}
if (i===3){
window.alert("We will be placing your 1 by 2 length ship. Take note that you are playing on a 10 by 10 board.");
ship();
}
function ship(){
userYTest = parseInt(prompt("Horizontal Coordinate position for the first unit of a ship"));
userXTest = parseInt(prompt("Vertical Coordinate position for the first unit of a ship"));
if(userXTest % 1 === 0 && userYTest % 1 === 0) {
userY = userYTest-1;
userX = userXTest-1;
direction = prompt("Now choose the direction you want the rest of your ship to face. You may use the words left, right up, or down.").toLowerCase();
}
else{
window.alert("You must enter a number between one and ten for the two coordinates.");
ship();
}
//Making sure the ship will fit and nothing is already there!
if ((userY+4-i)>9 && direction=== "down"){
window.alert("You are too close to the down edge of the board to do that. Restarting...");
ship();
}
else if ((userY-4-i)<0 && direction=== "up"){
window.alert("You are too close to the up edge of the board to do that. Restarting...");
ship();
}
else if ((userX+4-i)>9 && direction=== "right"){
window.alert("You are too close to the bottom edge of the board to do that. Restarting...");
ship();
}
else if ((userX-4-i)<0 && direction=== "left"){
window.alert("You are too close to the top edge of the board to do that. Restarting...");
ship();
}
else if (user[userY][userX] === 1) {
window.alert("Coordinate already used. Please try again");
ship();
}
else if (user[userY][userX] === null || user[userY][userX] === ""){
window.alert("That coordinate isn't on the board. Restarting...");
ship();
}
else if(direction ==="left" || direction ==="right" || direction ==="up" || direction ==="down") {
for(var a=1; a<5-i; a++){
if(direction=== "down"){
if(user[userY+a][userX] === 1){
window.alert("Can't place your ship in that direction, another ship is in your way.");
isThere=true;
}
}
if(direction=== "up"){
if(user[userY-a][userX] === 1){
window.alert("Can't place your ship in that direction, another ship is in your way.");
isThere=true;
}
}
if(direction=== "right"){
if(user[userY][userX+a] === 1 ){
window.alert("Can't place your ship in that direction, another ship is in your way.");
isThere=true;
}
}
if(direction=== "left"){
if(user[userY][userX-a] === 1){
window.alert("Can't place your ship in that direction, another ship is in your way.");
isThere=true;
}
}
if(isThere===true){
isThere = false;
ship();
return false;
}
else{
user[userY][userX] = 1;
}
}
}
else{
window.alert("Sorry but you didn't type in the direction you wanted your ship to go correctly. Restarting...");
ship();
}
// Building Ship 1x5
for(var b=1; b<5-i; b++){
if (direction==="left"){
user[userY][userX-b] =1;
}
else if (direction==="right"){
user[userY][userX+b] =1;
}
else if (direction==="up"){
user[userY-b][userX] =1;
}
else if (direction==="down"){
user[userY+b][userX] =1;
}
}
}
}
console.log(user);
First, understand that calling a function within itself does not stop running the original function. Try this (jsfiddle) to see how it works:
var i = 0;
function askDogsName() {
var dogsName = prompt("What is the dog's name?");
if (dogsName != "Rover") {
askDogsName();
}
i++;
document.body.innerHTML += "i = " + i
+ "; dog's name: " + dogsName + '<br />';
}
askDogsName();
After the new recursion of the function has completed, the original one simply carries on where it left off; it does not 'restart'. So this is not a good way of responding to user input that is not valid, especially because you are using global variables. Each recursion of the function can alter those variables in a way that can become difficult to predict, before returning control to its 'parent' (the recursion of the function that called it).
What you can do instead is to use return values to check whether the correct input has been given or not:
function ship() {
var c;
while (!c) {
c = getValidCoords();
}
x = c[0];
y = c[1];
// then make the ship at x, y
}
function getValidCoords() {
y = parseInt(prompt("Horizontal Coordinate position for the first unit of a ship"));
x = parseInt(prompt("Vertical Coordinate position for the first unit of a ship"));
// conduct various tests on x and y
if (testsFail) {
return false;
}
return [x, y];
}
You can't recurse when its wrong. Try something like this:
var done;
while (!done) {
if(userXTest % 1 === 0 && userYTest % 1 === 0) {
userY = userYTest-1;
userX = userXTest-1;
direction = prompt("Now choose the direction you want the rest of your ship to face. You may use the words left, right up, or down.").toLowerCase();
... All the other tests that are after the else part ...
else { // if its a good answer
done = true;
}
}
else{
window.alert("You must enter a number between one and ten for the two coordinates.");
}
}
You will want some way they can say they want to quit too.
Related
JavaScript variable changes to outcome the line after it is defined
I am working on creating a computer bot that plays itself at chopsticks. I have invented a while loop to run until one of the computers wins. I store the computer's gameState in a variable that looks like [[1,1],[1,1]]. The first item in the list is player one, and his left hand and right hand values are at 1. The second player is the same way. However, the line after I define gameState, I console.log() the gameState variable and get the end result of the game, the line after I define it as [[1,1],[1,1]]. The problem with this is that during the while loop, I'm not able to get information about the moves that the computer is making. Help! Here is my code: function makeMove(s, player, m) { //source, player, move //if it is player 2, flip it around if (player == 2) { var s = [s[1], s[0]]; } var target; var source; //move 0 is when the left hand targets the opponent's right hand //move 1 is when the right hand targets the opponent's left hand //move 2 is when the left hand targets the opponent's left hand //move 3 is when the right hand targets the opponent's right hand //the state [[1,1],[1,1]] stores the values of each hand and each opponent if (m == 0 || m == 3) { target = [1, 0]; } else { target = [1, 1]; } if (m == 0 || m == 2) { source = [0, 0]; } else { source = [0, 1]; } s[target[0]][target[1]] += s[source[0]][source[1]]; s[target[0]][target[1]] %= 5; if (player == 2) { s = [s[1], s[0]]; } return s; } function playmatch() { //the original state, var gameState = [[1, 1], [1, 1]]; //right after I create the value, for some reason it changes to the end result when I log it the next line. console.log(gameState); var winner = -1; while (winner == -1) { var choice = [0,1,2,3]; var move = choice[Math.floor(Math.random() * choice.length)]; gameState = makeMove(gameState, 1, move); var move = choice[Math.floor(Math.random() * choice.length)]; gameState = makeMove(gameState, 2, move); if (gameState[0][0] == 0 && gameState[0][1] == 0) { winner = 2; } if (gameState[1][0] == 0 && gameState[1][1] == 0) { winner = 1; } console.log(gameState); } return winner; } playmatch(); And a link to the codepen pen: https://codepen.io/gmoyer/pen/EeepbE
The behavior of console.log is not standardized. As suggested by MDN, you should serialize your object. Do this console.log(JSON.parse(JSON.stringify(obj))); instead of console.log(obj); to ensure that what is passed to console.log is a snapshot of the object at that moment in time rather than a reference to the object. I assume that console.log is not executing right when you call it and is given a reference to your array. Thus, your array changes, and later when console.log executes, it logs the changed array.
JS Function Calls from HTML + Reactive display
The game is WAR, or Get Your Neighbour, a traditional game utilising a standard deck of 52 cards, no jokers. Currently the code recognises when a card is above 10 and so the rules of the game are being followed, all that is great, I've designed a timer that takes the value of the card 2-14, subtracts 10, then uses that number for the round of turns the other player has to draw above 10 before you win. Still building the cooperative/multiplayer element but for now, I'd just like to get this bloody button working! When I click it, it does nothing. Before, it would tell me that "'timerf' is not a function". I'm probably doing something very obvious like problems with the order that things are loaded/data is parsed, but I'm still learning so I'd appreciate any help! Any questions, let me know. var card = null; // setem 160517 var timer = null; // window.onload = function() { function draw(min, max) { // draw a card between 2-14 card = document.getElementById("draw").innerHTML = Math.floor(Math.random()*((max - min)+1) + min); // min 2, max 14 if (card > 10) { timer = card - 10; timerf(timer); } else if (card < 11 && timer > 0) { timer = timerf(timer-1); } } // draw //draw(2,14); document.getElementById("clickMe").onclick = draw(2,14); } // window.onload function timerf(timer) { // print turns to win if (timer > 0 && timer < 5 && timer != 1) { // print turns to win console.log("you have " + timer + " turns to win!"); } else if (timer == 1) { console.log("you have " + timer + " turn to win!"); } } <div id="draw"></div> <button id="clickMe">WAR!</button>
The return value of the draw function is undefined because it has no return statement. document.getElementById("clickMe").onclick = draw(2,14); … so you are assigning undefined to the onclick property. You have to assign the function you want to call.
Iterating through different-sized grids to play audio for Conway's Game of Life
So I have an iteration question for my version of Conway's Game of Life (That is not my code, just an example of the game logic). So basically there are multiple sizes of the game board, going from 32(W)X16(H), and increasing in powers of 2 to 1024(W)X512(H). I am creating an audio version, so that whenever a cell becomes alive, web audio plays an oscillator note for a brief duration. The frequency and gain of that note depends on where on the board the audio is located. I have 32 frequency nodes and 16 gain nodes, so the cell at the top most right of the board would play the note at the highest frequency and the largest gain (.8). My problem comes when the board sizes increases, such as 64X32. I am having trouble figuring out the logic of how to determine which note and gain to use, as the cells in position 0 and 1 (left to right from the bottom) would have the same frequency, as would the cells in position 0 and 1 (bottom to top from the left corner) be having the same gain. Here is the code for my portion where I am having problems: function updateGame() { // GO THROUGH THE UPDATE GRID AND USE IT TO CHANGE THE RENDER GRID for (var i = 0; i < gridHeight; i++) { for (var j = 0; j < gridWidth; j++) { // HOW MANY NEIGHBORS DOES THIS CELL HAVE? var numLivingNeighbors = calcLivingNeighbors(i, j); // CALCULATE THE ARRAY INDEX OF THIS CELL // AND GET ITS CURRENT STATE var index = (i * gridWidth) + j; var testCell = updateGrid[index]; // CASES // 1) IT'S ALIVE if (testCell === LIVE_CELL) { if (gridWidth == 32) { if (gainHeight == 0) { gainNode[0].gain.value = .05; osc[i].connect(gainNode[0]); gainNode[0].connect(context.destination); } else { gainNode[j].gain.value = .05 * j; osc[i].connect(gainNode[j]); gainNode[j].connect(context.destination); } osc[i].start(context.currrentTime); if (context.currentTime == .5) { gainNode[0].gain.value = 0; osc[i].connect(gainNode[0]); gainNode[0].connect(context.destination); } } else if (gridWidth == 64) //issues begin here { if (gainHeight == 0 && (j == 0 || j == 1)) { } else { } } else if (gridWidth == 128) { } else if (gridWidth == 256) { } else if (gridWidth == 512) { } else { } // 1a FEWER THAN 2 LIVING NEIGHBORS if (numLivingNeighbors < 2) { // IT DIES FROM UNDER-POPULATION renderGrid[index] = DEAD_CELL; } // 1b MORE THAN 3 LIVING NEIGHBORS else if (numLivingNeighbors > 3) { // IT DIES FROM OVERCROWDING renderGrid[index] = DEAD_CELL; } // 1c 2 OR 3 LIVING NEIGHBORS, WE DO NOTHING else { renderGrid[index] = LIVE_CELL; } } // 2) IT'S DEAD else if (numLivingNeighbors === 3) { renderGrid[index] = LIVE_CELL; } else { renderGrid[index] = DEAD_CELL; } } } } I haven't actually implemented the audio portion of the code yet, as I wanted to make sure I had the correct logic going forward before I started messing with web audio. I have an array filled with 32 oscillator nodes, and an array filled with 16 gain nodes valued from .05 to .8. Thanks for the help, and hopefully this made sense!
It should be as simple as dividing the coordinate by how much you are scaled up past 32x16. For a width of 64, you'd use Math.floor(i/2) instead of just i. Sorry if this was obvious and I missed the point of the question...
Display images according to number set from interval
i try to display from svg ,layers according to numbers set from an interval.I have 2 random numbers (left and right) set to display from interval (10,99) both.That works good,but, i need to display layer 1(banane1) from svg if left || right belongs to interval (10,20) , then if left || right belongs to interval (20,30) to display layer 2(banane2) from svg and so on untill left || right belongs to interval (90,99) to display layer 9(banane9). There are 9 intervals and 9 layers from svg to display. Code i wrote looks like : FIDDLE: http://jsfiddle.net/r68Bg/ for(var i = 0; i < 2; i++){ panouri = document.getElementById('panou' + i); svgDoc = panouri.contentDocument; } where panou0 and panou1 are 2 svg that has layers 2 numbers where i display later random numbers set from intervals and 9 layers each with different content which must be displayed according to random numbers. function randomIntFromInterval(min,max) { return Math.floor(Math.random()*(max-min+1)+min); }; function conditions(){ left = randomIntFromInterval(10,99); right = randomIntFromInterval(10,99); for(var i = 0; i < 2; i++){ ecuations.push(left, right); randoms = document.getElementById("panou" + i).contentDocument; numere = randoms.getElementById("number"); numere.textContent = ecuations[i]; } }; where i add into my svg (panou0 and panou1) randoms numbers from set intervals. function setBananeState(state) { for(var i = 1; i < 10; i++){ svgItem = svgDoc.getElementById("banane" + i); svgItem.setAttribute("display", "none"); svgItem = svgDoc.getElementById(state); svgItem.setAttribute("display", "inline"); } }; function getBanane(){ if(left || right >= 30 && left || right <= 40){ bananeState = "banane3"; setBananeState(bananeState); } }; Here i have all layers from svgs which contains bananas to display according to random number given and a function getBanane() which has condition to display layer1 (banane1 by id from svg) if random number is from interval (10,20).Unfortunately this doesnt work...and i must have 8 more condition to display layers from svg if random numbers are from different interval
This isn't going to work: if(left || right == randomIntFromInterval(10,20)){ What you are doing here is a ORing left with right which will give you a boolean which you are then comparing to randomIntFromInterval. I think what you are trying to do is this: var interval = randomIntFromInterval(10,20); if (left == interval || right == interval) { EDIT: Okay you changed your question. So now this: if(left || right >= 30 && left || right <= 40){ Is not right, you can't write an if statement like that in javascript, or in most (probably all) programming languages. You can't say "if a or b is greater than x", like you would in normal English speech because it's ambiguous. You have to explicitly say "if (a is greater than x) or (b is greater than x)". So your if statement above needs to become: if ((left >= 30 || right >=30) && (left <= 40 || right <= 40)) { Although I'm not sure this is exactly what you want either. Because here if left==0 and right==41, then this statement would be true. I think you want either left or right to be in the interval, so your best check would be: if ((left >= 30 && left <= 40) || (right >= 30 && right <= 40)) {
What is wrong with this code? Am I going about this the right way?
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");
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!