More on collisions

You might have found while playing our little game that you can make the snake turn back on itself or it even goes through itself. Anyone who remembers the original will know that this results in an immediate game over!

What we are going to look at now can essentially be split into two parts. First, we will fix the snake's ability to slither back on itself, as seen in the following screenshot:

More on collisions

Second, we will look at stopping the game when the snake collides with another part of its body, as seen in the following screenshot:

More on collisions

Stopping the doubleback

With our snake slithering around, if you change the direction of the snake and you tell it to go back the way it is traveling, it will slide right through itself. This isn't how the game should be!

Essentially, what we want to do is, if the player tells the snake to change its direction and move in the exact opposite direction, ignore that input command.

First, we will create a method to do this precise check:

private void updateIfNotOppositeDirection(int newSnakeDirection, int oppositeDirection) {
   if (snakeDirection != oppositeDirection) snakeDirection = newSnakeDirection;
}

What we will pass into this method is the new direction that we would like to send the snake in, but then also the opposite direction (left and right or up and down) so we make the check and only update the direction if it isn't the opposite.

Next, we create a method that will call updateIfNotOppositeDirection() with all the possible combinations. We are lucky there are only four!

The following method shows how we will do this:

private void updateDirection(int newSnakeDirection) {
  if (!directionSet && snakeDirection != newSnakeDirection) {
     directionSet = true;
     switch (newSnakeDirection) {
       case LEFT: {
          updateIfNotOppositeDirection(newSnakeDirection, RIGHT);
       }
       break;
       case RIGHT: {
          updateIfNotOppositeDirection(newSnakeDirection, LEFT);
       }
       break;
       case UP: {
          updateIfNotOppositeDirection(newSnakeDirection, DOWN);
       }
       break;
       case DOWN: {
          updateIfNotOppositeDirection(newSnakeDirection, UP);
       }
       break;
     }
  }
}

Now, to take a little side step, you may have noticed that I have introduced a new member to the GameScreen class here: directionSet—a Boolean flag. This is needed because of how we poll for input compared to the snake update. The snake currently has its movement updated periodically, currently every half a second, yet we poll for input at a rate of up to 1/60th of a second. This means our snake's direction can change up to 30 times before it moves! This would allow a player to negate what we are trying to stop—the snake turning back on itself.

So what we do is, once we detect a new input after we move the snake, we take that input. However, we take it if the newSnakeDirection value is not equal to that of the current snakeDirection value.

We reset the directionSet flag after we move the snake.

Finally, we update our quertInput() method to call our new updateDirection() method:

private void queryInput() {
   boolean lPressed = Gdx.input.isKeyPressed(Input.Keys.LEFT);
   boolean rPressed = Gdx.input.isKeyPressed(Input.Keys.RIGHT);
   boolean uPressed = Gdx.input.isKeyPressed(Input.Keys.UP);
   boolean dPressed = Gdx.input.isKeyPressed(Input.Keys.DOWN);

   if (lPressed) updateDirection(LEFT);
   if (rPressed) updateDirection(RIGHT);
   if (uPressed) updateDirection(UP);
   if (dPressed) updateDirection(DOWN);
}

If you now launch the game, you will see that the snake can now no longer slither back onto itself!

However, did you notice the deliberate mistake I've included?

If you try to change to the opposite direction while the snake is only a head, it won't let you! Try it, go ahead!

To fix this, we need to update our updateIfNotOppositeDirection() method to also check on the size of the snake, as follows:

private void updateIfNotOppositeDirection(int newSnakeDirection, int oppositeDirection) {
   if (snakeDirection != oppositeDirection || bodyParts.size == 0) snakeDirection = newSnakeDirection;
}

Now try it. You will find that it is all fixed!

Colliding with the body

On to the second part of this topic. We will now look into stopping the game when the snake collides with itself. To achieve this, we will need to do a few things:

  • Introduce a collision flag
  • Check the snake's head position compared to its body parts
  • Update the collision flag when there is a collision
  • Stop the movement of the snake if the flag returns true

First, let's introduce the flag:

private boolean hasHit = false;

Add this flag to the GameScreen class. We will update it later!

Next, we need to check for the collision. This is fairly straightforward, as we know the location of our snake's body parts and head. Let's create a method called checkSnakeBodyCollision() in our GameScreen class:

private void checkSnakeBodyCollision() {
   for (BodyPart bodyPart : bodyParts) {
   if (bodyPart.x == snakeX && bodyPart.y == snakeY) hasHit = true;
}
}

The preceding code checks whether the x and y coordinates of our snake's head match its body parts. If true, let's set our flag. Simple!

We now add this method call to our updateSnake() method block:

private void updateSnake(float delta) {
   timer -= delta;
   if (timer <= 0) {
       timer = MOVE_TIME;
    moveSnake();
    checkForOutOfBounds();
    updateBodyPartsPosition();
    checkSnakeBodyCollision();
    directionSet = false;
    }
}

Finally, to complete this, we add a check on our flag before we go on to update our snake.

private void updateSnake(float delta) {
   if (!hasHit) {
     //Update snake code omitted
   }
}

Now if you launch the game, you will see that it will appear to stop when you make the snake collide with its body.

We almost have a complete game on our hands!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.178.9