0

I’m having trouble getting my snake to turn and not leave a trail. Every time my snake turns to go in a different direction it leaves behind pieces of itself. Each piece is a class of “hover” applied to a div block.

I created a function that I hoped would remove the excess pieces whenever a turn was made. My function removeExtra does remove the excess pieces on every turn (removeExtra is called from the moveSnake function each time an arrow is hit), but it also removes every piece of the snake when it turns. So every time I make a turn the snake starts over in that direction and then expands to its current size. A user could play and never run into any of the snake’s body pieces. If I don’t use this function though it leaves little snake turds all over the board!

Can someone help me fix my removeExtra function so that it only removes the class of hover that is not part of the snake body’s array? (var snake) In the removeExtra function I create an array of every hover class (every snake piece). I then use the length of this in the for loop. I have also tried using the difference between this array and the current snake array (var combo) as the second parameter of the for loop, but this doesn’t consistently clear the snake bits when I make turns.

I realize my code sucks. I’ve made this way more complicated than it should be. I should have used a canvas. But I’ve come this far, and I’m hoping there’s some way to salvage the game and never think about snakes again. If there really is no way to fix the mess I’ve made, just let me know, so that I can move on with my life. Thanks!

Here is the Codepen with the game.

Here is the function that's giving me trouble:

removeExtra = function(){

var array = [];

$(".hover").each(function() {
  array.push($(this).attr("data"));
});

var len = array.length
var len2 = snake.length
var combo = len-len2

for (var i=0;i<len;i++){
  $('*[data="' + array[i] + '"]').removeClass("hover");

}}

Since this is a work-in-progress (surprise!), just refresh the page if you don’t see any blue “food” pieces. Arrows keys will move the snake. You might have to click the board first.

//In the moveSnake function I had to use code from the below link in order to ignore multiple keydown events.
//https://stackoverflow.com/questions/9098901/how-to-disable-repetitive-keydown-in-jquery

$(document).ready(function() {
  makebox();
  addSnake();
  moveSnake();
  addBorder();
  addFood();
  killSnake();
  addToSnake();
});

function makebox() {
  var size = 30; //24
  var boxSize = 20; //12
  for (i = 1; i <= size * size; i++) {
    $("#container").append("<div class='box'></div>");
  };
  $("#container").width(size * boxSize + "px");
  $(".box").width(boxSize + "");
  $(".box").height(boxSize + "px");
  $(".box").each(function(i) {
    $(this).attr('data', (i + 1));
  });
};

function addBorder() {
  //find all of the border divs and add a border class to them
  $(".box").each(function() {

    if ($(this).attr('data') % 25 == 0) {
      $(this).addClass("right-border")
    } else if ($(this).attr('data') % 25 == 1) {
      $(this).addClass("left-border")
    } else if ($(this).attr('data') < 25) {
      $(this).addClass("top-border")
    } else if ($(this).attr('data') >= 877) {
      $(this).addClass("bottom-border")
    }
  })
}

function addSnake() {

  var rightTime, leftTime, downTime, upTime;


  moveRight = function() {
    down = {}
    rightTime = setInterval(function() {
      for (var i = 0; i < snake.length; i++) {
        snake[i]++
          $('*[data="' + snake[i] + '"]').addClass("hover moving")
        $('*[data="' + (snake[snake.length - 1] - snake.length) + '"]').removeClass("hover");

      }
    }, 150)

  };

  moveLeft = function() {
    down = {}
    leftTime = setInterval(function() { //snake -= 1
      for (var i = 0; i < snake.length; i++) {
        snake[i] -= 1
        $('*[data="' + snake[i] + '"]').addClass("hover");
        $('*[data="' + (snake[snake.length - 1] + snake.length) + '"]').removeClass("hover");

      }
    }, 150)

  };

  moveDown = function() {
    down = {}
    downTime = setInterval(function() { //snake += 25
      for (var i = 0; i < snake.length; i++) {
        snake[i] += 25
        $('*[data="' + snake[i] + '"]').addClass("hover");
        $('*[data="' + (snake[snake.length - 1] - 25 * snake.length) + '"]').removeClass("hover");


      }
    }, 150)

  };

  moveUp = function() {
    down = {}
    upTime = setInterval(function() { //snake -= 25
      for (var i = 0; i < snake.length; i++) {
        snake[i] -= 25
        $('*[data="' + snake[i] + '"]').addClass("hover");
        $('*[data="' + (snake[snake.length - 1] + 25 * snake.length) + '"]').removeClass("hover");
      }
    }, 150)

  };

  addTail = function() {
    snake.push(snake[snake.length - 1])
  }

  var snake = [42]

  $('*[data="' + snake[0] + '"]').addClass("hover");

  var down = {};

  removeExtra = function() {

    var array = [];

    $(".hover").each(function() {
      array.unshift($(this).attr("data"));
    });

    var len = array.length
    var len2 = snake.length
    var combo = len - len2

    for (var i = 0; i < len; i++) {
      $('*[data="' + array[i] + '"]').removeClass("hover");

    }
  }

  moveSnake = function() {

    $(document).keydown(function(event) {

      var keycode = (event.keyCode ? event.keyCode : event.which);

      if (keycode == '39') {
        if (down['39'] == null) {
          window.clearInterval(leftTime);
          window.clearInterval(downTime);
          window.clearInterval(upTime);
          moveRight();
          removeExtra();
          down['39'] = true;
        }
      } else if (keycode == '37') {
        if (down['37'] == null) {
          window.clearInterval(rightTime);
          window.clearInterval(downTime);
          window.clearInterval(upTime);
          moveLeft();
          removeExtra();
          down['37'] = true;
        }
      } else if (keycode == '40') {
        if (down['40'] == null) {
          window.clearInterval(leftTime);
          window.clearInterval(rightTime);
          window.clearInterval(upTime);
          moveDown();
          removeExtra();
          down['40'] = true;
        }
      } else if (keycode == '38') {
        if (down['38'] == null) {
          window.clearInterval(leftTime);
          window.clearInterval(rightTime);
          window.clearInterval(downTime);
          moveUp();
          removeExtra();
          down['38'] = true;
        }
      }

    });

    addToSnake = function() {
      var count = 0;

      var config = {
        attributes: true,
        childList: true,
        characterData: true
      };

      $(".box, .food").each(function() {
        var target = this;
        var observer = new MutationObserver(function(mutations) {
          mutations.forEach(function(mutation) {
            if ($(".food").hasClass("hover") == true) {
              $(".box").removeClass("food")
              addTail();
              addFood();
            }
          });
        });

        observer.observe(target, config);

      });

    }

    killSnake = function() {
      var config = {
        attributes: true,
        childList: true,
        characterData: true,
        subtree: true
      };

      $(".right-border, .left-border, .top-border, .bottom-border").each(function() {
        var target = this;
        var observer = new MutationObserver(function(mutations) {
          mutations.forEach(function(mutation) {
            console.log("Game over!")
          });
        });

        observer.observe(target, config);
      });
    }
  }

  addFood = function() {
    var random = Math.floor(Math.random() * (900 - 1 + 1)) + 1;
    $('*[data="' + random + '"]').addClass("food")

  };

};
.box {
  display: inline-block;
  border: 2px grey solid;
}

#container {
  display: block;
  border: 2px black solid;
  border-radius: 5px;
  font-size: 0;
  margin: 10px auto;
}

.hover {
  background-color: black;
}

.food {
  background-color: blue;
}

.white {
  background-color: white;
}

.right-border,
.left-border,
.top-border,
.bottom-border {
  background: red;
  border: 2px red solid;
}
<!DOCTYPE html>

<html lang="en">

<head>

  <title>Snake</title>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

  <link rel="stylesheet" href="style.css">

  <script type="text/javascript" src="script.js"></script>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>

</head>

<body>

  <div class="container">

    <center>
      <h1>Snake</h1>

      <div id="container"></div>
    </center>

  </div>

</body>

</html>
Barmar
  • 741,623
  • 53
  • 500
  • 612
Pat Mellon
  • 360
  • 2
  • 5
  • 12
  • What are the `len2` and `combo` variables for? – Barmar May 25 '17 at 00:18
  • Post your code here, not just at a remote site. You can use [Stack Snippets](https://stackoverflow.blog/2014/09/introducing-runnable-javascript-css-and-html-code-snippets/) to make it executable. – Barmar May 25 '17 at 00:21
  • What do I have to do to start the game? I see the blue food, but nothing I do makes the snake go. – Barmar May 25 '17 at 00:22
  • My guess is you should be looping from `len to len2` and removing the class from those elements. – Barmar May 25 '17 at 00:23
  • I added the snippet and clarified that you might have to click on the board first. len2 is the length of the snake itself. Combo is the difference between the array length (the amount of every excess snake piece on the board--made when the turns happen) and the snake body. My thinking was that I could delete the difference between the 2 arrays and that would get ride of the excess pieces. Nope. If you comment out the removeExtra function you will see the extra pieces being made on each turn. – Pat Mellon May 25 '17 at 00:31
  • Nothing happens when I click on the board. – Barmar May 25 '17 at 00:32
  • Sorry! Click the board and then use the arrows keys. – Pat Mellon May 25 '17 at 00:34
  • The way to move a snake is to just remove the last piece of the tail and add a new piece in the direction it's moving. You don't need to do anything to the segments in the middle. You're making it too complicated. – Barmar May 25 '17 at 00:42
  • Also note that when the snake wraps left to right, it descends one row. Similarly, it ascends one row when wrapping right to left. There may be more problems here than just *removeExtra*. – James Danylik May 25 '17 at 02:55
  • @JamesDanylik Yep. There are definitely a lot of problems. I'm going to work on fixing the functions that move the snake in different directions as Barmar suggested. – Pat Mellon May 25 '17 at 15:06

0 Answers0