I was following the tutorial in the book called LibGDX Game Development By Example but then
I got stuck. I’ve succeeded to make the snake move like I want and I control it using the arrow
keys on my keyboard. But when I tried to follow the next step in the book and wrote in the code
that was needed I didn’t get it to add parts to the snakes body.
By the way I did a wall that the snake just stops with when it reaches it instead. Just to play
around a little and test what I were able to do. I might have some uneccesary code because
I was trying to accomplish different things if you want to be aware of it.
This project is generated by libGDX and when generating the project the desktop and html
checkboxes were checked.
So what I’m asking for is: How do you add body parts to the snake when it has eaten the apple?
I need to increase the snakes length and make the other body part move along with each other.
The three files I’m working with in Android Studio is called:
MyGdxGame.java
BodyPart.java
DesktopLauncher.java
assets
apple.png
snakeBody.png
snakeHead.png
wall.png
DesktopLauncher
package com.mygdx.game.desktop;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.mygdx.game.MyGdxGame;
public class DesktopLauncher {
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
new LwjglApplication(new MyGdxGame(), config);
}
}
MyGdxGame
package com.mygdx.game;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
// Delta time
// https://www.youtube.com/watch?v=zoavsd6w0HA
public class MyGdxGame extends ApplicationAdapter {
SpriteBatch batch;
// Images that are going to be used in the game
private Texture snakeHead;
private Texture apple;
private Texture wall;
// Snake movement delta time handling
private static float MOVE_TIME = 0.5F;
private float timer = MOVE_TIME;
// Snake properties
private static final int SNAKE_MOVEMENT = 32;
protected int snakeX = 0, snakeY = 0;
// Removed code because I didn't get it to work with
// adding body parts to the end of the snake
//private Array<BodyPart> bodyParts = new Array<BodyPart>();
//private int snakeXBeforeUpdate = 0, snakeYBeforeUpdate = 0;
// Snake movement controls
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 = -1;
// Apple properties
private boolean appleAvailable = false;
private int appleX, appleY;
// Wall properties
private boolean wallAvailable = false;
private int wallX, wallY;
// Snake touch controls (NOT DEFINED YET)
private OrthographicCamera camera;
private ExtendViewport viewport;
@Override
public void create () {
batch = new SpriteBatch();
snakeHead = new Texture(Gdx.files.internal("D:/Programming/Java/LibGDX/SnakeDesktop/desktop/src/assets/snakeHead.png"));
apple = new Texture(Gdx.files.internal("D:/Programming/Java/LibGDX/SnakeDesktop/desktop/src/assets/apple.png"));
wall = new Texture(Gdx.files.internal("D:/Programming/Java/LibGDX/SnakeDesktop/desktop/src/assets/wall.png"));
//snakeBody = new Texture(Gdx.files.internal("D:/Programming/Java/LibGDX/SnakeDesktop/desktop/src/assets/snakeBody.png"));
}
@Override
public void render() {
queryInput();
checkForOutOfBounds();
// Get the time elapsed since it started
timer -= Gdx.graphics.getDeltaTime();
checkAppleCollision();
checkAndPlaceApple();
checkAndPlaceWall();
checkWallCollision();
//updateBodyPartsPosition();
Gdx.gl.glClearColor(Color.BLACK.r, Color.BLACK.g, Color.BLACK.b, Color.BLACK.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
draw();
}
private void draw() {
batch.begin();
batch.draw(snakeHead, snakeX, snakeY);
/*for (BodyPart bodyPart : bodyParts) {
batch.draw(snakeBody, snakeX, snakeY);
}*/
if (wallAvailable) {
batch.draw(wall, wallX, wallY);
}
// Render the apple if it has been placed
if (appleAvailable) {
batch.draw(apple, appleX, appleY);
}
batch.end();
}
// Check if the snake is out of the screen and replace it back if so
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;
}
}
/* ##############################################################
* The snake movement controls are in these functions as well as
* the delta time that makes the snake move in correct time. These
* functions are called in the render method.
* ##############################################################*/
// Check for the user to press right, left, up or down arrow key
private void queryInput() {
boolean aPressed = Gdx.input.isKeyPressed(Input.Keys.LEFT);
boolean dPressed = Gdx.input.isKeyPressed(Input.Keys.RIGHT);
boolean wPressed = Gdx.input.isKeyPressed(Input.Keys.UP);
boolean sPressed = Gdx.input.isKeyPressed(Input.Keys.DOWN);
if (aPressed) snakeDirection = LEFT;
if (dPressed) snakeDirection = RIGHT;
if (wPressed) snakeDirection = UP;
if (sPressed) snakeDirection = DOWN;
moveSnake();
}
// Move the snake left, right, up or down
private void moveSnake() {
//snakeXBeforeUpdate = snakeX;
//snakeYBeforeUpdate = snakeY;
// Let the snake move by 32 frames on 1 second
if (timer <= 0) {
timer = MOVE_TIME;
switch (snakeDirection) {
case RIGHT:
snakeX += SNAKE_MOVEMENT;
break;
case LEFT:
snakeX -= SNAKE_MOVEMENT;
break;
case UP:
snakeY += SNAKE_MOVEMENT;
break;
case DOWN:
snakeY -= SNAKE_MOVEMENT;
break;
}
}
}
/* Update the body parts positions and place them correctly on the snake
private void updateBodyPartsPosition() {
if (bodyParts.size > 0) {
BodyPart bodyPart = bodyParts.removeIndex(0);
bodyPart.updateBodyPosition(snakeXBeforeUpdate, snakeYBeforeUpdate);
bodyParts.add(bodyPart);
}
}*/
/* ##############################################################
* End of the snake control code block
* ############################################################## */
// Checks if an apple needs to be placed onto the screen
private void checkAndPlaceApple() {
if (!appleAvailable) {
do {
appleX = MathUtils.random(Gdx.graphics.getWidth()
/ SNAKE_MOVEMENT - 1) * SNAKE_MOVEMENT;
appleY = MathUtils.random(Gdx.graphics.getHeight()
/ SNAKE_MOVEMENT - 1) * SNAKE_MOVEMENT;
appleAvailable = true;
} while (appleX == snakeX && appleY == snakeY);
}
}
// Check for apple and snake head coordinates to match
private void checkAppleCollision() {
if (appleAvailable && appleX == snakeX && appleY == snakeY) {
/* Create new body part to the snake
BodyPart bodyPart = new BodyPart(snakeBody);
bodyPart.updateBodyPosition(snakeX, snakeY);
bodyParts.insert(0, bodyPart);*/
appleAvailable = false;
if (MOVE_TIME > 0.2f) {
MOVE_TIME -= 0.1f;
}
else {
MOVE_TIME = 0.5f;
}
}
}
// Check and place the wall
private void checkAndPlaceWall() {
if (!wallAvailable) {
do {
/*wallX = MathUtils.random(Gdx.graphics.getWidth()
/ SNAKE_MOVEMENT - 1) * SNAKE_MOVEMENT;
wallY = MathUtils.random(Gdx.graphics.getHeight()
/ SNAKE_MOVEMENT - 1) * SNAKE_MOVEMENT;*/
wallX = 64;
wallY = 64;
wallAvailable = true;
} while (wallX == snakeX && wallY == snakeY);
}
}
// Check if the snake coordinates match the wall coordinates
// and make the snake stop.
private void checkWallCollision() {
if (wallAvailable && wallX == snakeX && wallY == snakeY) {
// Opposite signs for wall to make the snake stop
// Check which direction the snake was going and
// make it stop at that direction when it hits the
// wall.
switch (snakeDirection) {
case RIGHT:
snakeX -= SNAKE_MOVEMENT;
break;
case LEFT:
snakeX += SNAKE_MOVEMENT;
break;
case UP:
snakeY -= SNAKE_MOVEMENT;
break;
case DOWN:
snakeY += SNAKE_MOVEMENT;
break;
}
snakeDirection = -1;
}
}
}
BodyPart
package com.mygdx.game;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
/**
* Created by Kevin on 2015-12-29.
*/
public class BodyPart extends MyGdxGame {
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);
}
}
}