Moving Sammy the snake

So, we have Sammy the snake on the screen, sitting there, looking snaky. However, it isn't much of a game. If it were, we could finish the book right here! What we need to do now is get that snake slithering across the screen!

First, let's sort out the playing area. Currently, the resolution is 640 x 480 pixels and the snake texture is 32 x 32. This means we have a grid of 20 x 15—derived by dividing up the resolution by the texture (640/32 = 20, 480/32 = 15)— of the different positions the snake head could be in. The reason we are going to do it this way is because the original game moved with a periodic movement of one snake component at a time. We are going to do the same.

Let's define our timer. We are going to start off with an interval of one second between movements. So let's create a constant field:

    private static final float MOVE_TIME = 1F;

Now, define a variable to keep track of the time:

    private float timer = MOVE_TIME;

Finally, let's get it updated in every frame. This is in the render() method:

    timer -= delta;
    if (timer <= 0) {
        timer = MOVE_TIME;
    }

Here we are deducting the time from the last frame. If the timer reaches zero or below, we reset it.

What we want to do next is move the snake head to the next block once the timer has reached zero or below. Since we only want to make the snake move right, we will be adding 32 px to the position of the snake.

Let's add an x and y component for the snake, and a constant for moving:

    private static final int SNAKE_MOVEMENT = 32;
    private int snakeX = 0, snakeY = 0;

Next, let's update the render() method:

    @Override
    public void render(float delta) {
        timer -= delta;
        if (timer <= 0) {
            timer = MOVE_TIME;
            snakeX += SNAKE_MOVEMENT;
        }
        Gdx.gl.glClearColor(Color.BLACK.r, Color.BLACK.g, Color.BLACK.b, Color.BLACK.a);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        batch.draw(snakeHead,snakeX,snakeY);
        batch.end();
    }

So now every time the timer reaches zero or below, the snake will move to the right by 32 px.

Run the default project and check it out!

So what did you see? Hopefully, it was the snake head scrolling across the screen in intervals of 1 second. Then it probably disappeared off to the right? Yes, we should have been expecting that. We told the snake head to move to the right indefinitely. What we should do, staying true to the original, is have the snake reappear on the left-hand side.

Let's create a method to check for the position of the snake:

    private void checkForOutOfBounds() {
        if (snakeX >= Gdx.graphics.getWidth()) {
            snakeX = 0;
        }
    }

Now we should have this method called after we move the snake. What we are doing here is checking whether the position of the snake head is outside the screen. We do this by querying the screen's width and checking whether the snake's x position is greater than or equal to it. We then reset it to zero.

Running the project now, you will see that the snake head will return back to the start of the screen.

This is all well and good, but again, it isn't much of a game just having the snake move to the right. What we need to do is give the snake a direction:

    private static final int RIGHT = 0;
    private static final int LEFT = 1;
    private static final int UP = 2;
    private static final int DOWN = 3;
    private int snakeDirection = RIGHT;

By adding some constants and a variable, we can keep track of the snake's direction. Now that we have a direction, we need to be more precise on how we mean to move the snake. Let's replace the current code for moving with the following method:

    private void moveSnake() {
        switch (snakeDirection) {
            case RIGHT: {
                snakeX += SNAKE_MOVEMENT;
                return;
            }
            case LEFT: {
                snakeX -= SNAKE_MOVEMENT;
                return;
            }
            case UP: {
                snakeY += SNAKE_MOVEMENT;
                return;
            }
            case DOWN: {
                snakeY -= SNAKE_MOVEMENT;
                return;
            }
        }
    }

Now, depending the direction set, the snake will move; give it a go and set the snake to move in a different direction.

Ah, I bet you've seen the problem with this already. We only check whether the snake is on the screen when moving right, and that means we need to update our bounds to check method to cover all cases:

    private void checkForOutOfBounds() {
        if (snakeX >= Gdx.graphics.getWidth()) {
            snakeX = 0;
        }
        if (snakeX < 0) {
            snakeX = Gdx.graphics.getWidth() - SNAKE_MOVEMENT;
        }
        if (snakeY >= Gdx.graphics.getHeight()) {
            snakeY = 0;
        }
        if (snakeY < 0) {
            snakeY = Gdx.graphics.getHeight() - SNAKE_MOVEMENT;
        }
    }

That should be better!

Just before we move on to controlling the snake, let's do a little code refactor to stop things from getting a bit too messy in our render() method. You will see in the samples that this has already been done!

Controlling Sammy with event polling

Now we are going to look at how to control our snake. Normally, there are a couple of approaches to handle user input. One is event polling, where we can query the state of the input and then update our game accordingly. Generally, this polling will occur during the main game loop, just before the rendering. The other method is to listen to events; we register a listener that will receive events from the LibGDX framework when the player interacts with the game, that is, presses a key. For now, we will just work with polling.

As we are working in desktop mode, we will take advantage of the arrow keys on the keyboard. Because LibGDX is so awesome, there is a really convenient way to poll for user input, Gdx.input. There is a vast array of methods that we can call here to determine what the player has pressed. For this example, we will be focus on the Gdx.input.isKeyPressed() method. Here we can specify the key to query by passing in a key code. The codes are available as constants that live inside the Keys static class; please check the official documentation at http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Input.Keys.html to access the whole list.

So how do we use it?

Well, let's create a method called queryInput() in it. We will check whether the arrow keys have been pressed and update the snake direction accordingly:

    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) snakeDirection = LEFT;
        if (rPressed) snakeDirection = RIGHT;
        if (uPressed) snakeDirection = UP;
        if (dPressed) snakeDirection = DOWN;
    }

So firstly, we query the four keys we are interested in, and then we set the direction.

Now, add this method to the top of the render() method.

Run the project and you will find that you can control the snake with the arrow keys.

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

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