Increasing the length of the snake

We have the snake eating the apple; however, there aren't any consequences to this. As a part of the game, we need to make the snake increase the length of his body for each apple he eats. Our requirements for this are as follows:

  • Add a body part to the snake when it eats an apple
  • As the snake moves, the body parts should follow
  • There will be multiple body parts

First, let's create a class that will contain the length of the snake's body. This can take the form of an inner class for now:

    private class BodyPart {

        private int x, y;
        private Texture texture;

        public BodyPart(Texture texture) {
            this.texture = texture;
        }

        public void updateBodyPosition(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public void draw(Batch batch) {
            if (!(x == snakeX && y == snakeY)) batch.draw(texture, x, y);
        }
    }

As you can see, it contains the x and y components along with the texture to be drawn. It also has a draw() method which will only draw the texture if the body part is not in the same location as the snake's head. This is important for when you collect the apple; you wouldn't want the body part showing over the head before the snake moves.

Next, let's create the texture:

private Texture snakeBody;

Again in our show() method, let's add code to instantiate the object:

snakeBody = new Texture(Gdx.files.internal("snakeBody.png"));

Let's create an array of body parts:

private Array<BodyPart> bodyParts = new Array<BodyPart>();

Here, we are using LibGDX's built-in Array<T> class. It has some useful methods for accessing the the first and last element of the array that we will need shortly.

Now, when that part is set up, we can add a body part when a collision between the snakes head and apple occurs:

    private void checkAppleCollision() {
        if (appleAvailable && appleX == snakeX && appleY == snakeY) {
            BodyPart bodyPart = new BodyPart(snakeBody);
            bodyPart.updateBodyPosition(snakeX, snakeY);
            bodyParts.insert(0,bodyPart);
            appleAvailable = false;
        }
    }

When a collision is detected, we create a new body part, set its position, and insert it at the front of the array. We are reusing the texture for the body parts, so we can reduce our memory footprint by not loading it multiple times. We can do this as the drawing of the texture doesn't require it to be a different instance of the texture every time we draw it in the same render cycle.

Next, we need to update the body parts every time the snake moves; if we don't do this, they will remain in their place for all eternity. Let's add the following code to our game:

    private int snakeXBeforeUpdate = 0, snakeYBeforeUpdate = 0;
    private void moveSnake() {
        snakeXBeforeUpdate = snakeX;
        snakeYBeforeUpdate = snakeY;
    // Rest of method omitted
    }
    private void updateBodyPartsPosition() {
        if (bodyParts.size > 0) {
            BodyPart bodyPart = bodyParts.removeIndex(0);
            bodyPart.updateBodyPosition(snakeXBeforeUpdate, snakeYBeforeUpdate);
            bodyParts.add(bodyPart);
        }
    }

Right, first we need to keep track of the previous position of the snake—the reason for this will be clear in a minute. Then we have the updateBodyPartsPosition() method, where we take the front element of the array, which would be the body part that is the tail part of the snake, and we remove it from the array. We then update the position and add it to the back of the array, which is the front of the snake. This means we are only updating the one body part as the others won't need to move unless they are the tail of the snake.

Add a call to this method after we check whether the snake is out of bounds:

            // render method
  moveSnake();
  checkForOutOfBounds();
  updateBodyPartsPosition();

Before we run the project and see what we have created, we need to update our draw() method to draw out the body of the snake:

private void draw() {
  batch.begin();
  batch.draw(snakeHead, snakeX, snakeY);
  for (BodyPart bodyPart : bodyParts) {
    bodyPart.draw(batch);
  }
  if (appleAvailable) {
    batch.draw(apple, appleX, appleY);
  }
  batch.end();
}

With that in place, if you run the project now, you will see that the snake grows every time it eats an apple.

Increasing the length of the snake
..................Content has been hidden....................

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