libgdx蛇逻辑解释
libgdx snake logic explained
这是我正在阅读的一本书中的代码。这只是一个蛇游戏。您可以将此代码粘贴到编辑器中,并将 3 个纹理文件更改为计算机上的文件。代码工作正常,这可能真的很愚蠢,但我无法在 snakeBody 部件和它们的位置之间建立联系。蛇(不是头)的 body 到底是怎么知道蛇头改变位置后应该去哪里的?你能详细说明一下吗?谢谢
// class 1/2:
public class MyGdxGame extends Game {
@Override
public void create () {
setScreen(new GameScreen());
}
}
class 2/2:
package com.mygdx.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.utils.Array;
public class GameScreen extends ScreenAdapter{
private static final float MOVE_TIME = 0.5F;
private static final int SNAKE_MOVEMENT = 32;
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 SpriteBatch batch;
private Texture snakeHead;
private Texture snakeBody;
private Texture apple;
private boolean appleAvailable = false;
private int appleX, appleY;
private float timer = MOVE_TIME;
private int snakeX = 0, snakeY = 0;
private int snakeXBeforeUpdate = 0, snakeYBeforeUpdate = 0;
private int snakeDirection = RIGHT;
private Array<BodyPart> bodyParts = new Array<BodyPart>();
@Override
public void show() {
super.show();
batch = new SpriteBatch();
snakeHead = new Texture(Gdx.files.internal("snakehead.png"));
snakeBody = new Texture(Gdx.files.internal("snakeBody.png"));
apple = new Texture(Gdx.files.internal("apple.png"));
}
@Override
public void render(float delta) {
super.render(delta);
queryInput();
timer -= delta;
if (timer <= 0) {
timer = MOVE_TIME;
moveSnake();
checkForOutOfBounds();
updateBodyPartsPosition();
}
checkAppleCollision();
checkAndPlaceApple();
clearScreen();
draw();
}
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;
}
private void moveSnake() {
snakeXBeforeUpdate = snakeX;
snakeYBeforeUpdate = snakeY;
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;
}
}
}
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;
}
}
private void updateBodyPartsPosition() {
if (bodyParts.size > 0) {
BodyPart bodyPart = bodyParts.removeIndex(0);
bodyPart.updateBodyPosition(snakeXBeforeUpdate, snakeYBeforeUpdate);
bodyParts.add(bodyPart);
}
}
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);
}
}
private void checkAppleCollision() {
if (appleAvailable && appleX == snakeX && appleY == snakeY) {
BodyPart bodyPart = new BodyPart(snakeBody);
bodyPart.updateBodyPosition(snakeX, snakeY);
bodyParts.insert(0,bodyPart);
appleAvailable = false;
}
}
private void clearScreen() {
Gdx.gl.glClearColor(Color.BLACK.r, Color.BLACK.g, Color.BLACK.b, Color.BLACK.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
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();
}
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);
}
}
}
首先它在 moveSnake() 中移动头部,确保跟踪头部在移动之前的位置。然后在 updateBodyPartsPosition() 中,它将 body 的最后一块放在刚刚移动头部的地方。
这是我正在阅读的一本书中的代码。这只是一个蛇游戏。您可以将此代码粘贴到编辑器中,并将 3 个纹理文件更改为计算机上的文件。代码工作正常,这可能真的很愚蠢,但我无法在 snakeBody 部件和它们的位置之间建立联系。蛇(不是头)的 body 到底是怎么知道蛇头改变位置后应该去哪里的?你能详细说明一下吗?谢谢
// class 1/2:
public class MyGdxGame extends Game {
@Override
public void create () {
setScreen(new GameScreen());
}
} class 2/2:
package com.mygdx.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.utils.Array;
public class GameScreen extends ScreenAdapter{
private static final float MOVE_TIME = 0.5F;
private static final int SNAKE_MOVEMENT = 32;
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 SpriteBatch batch;
private Texture snakeHead;
private Texture snakeBody;
private Texture apple;
private boolean appleAvailable = false;
private int appleX, appleY;
private float timer = MOVE_TIME;
private int snakeX = 0, snakeY = 0;
private int snakeXBeforeUpdate = 0, snakeYBeforeUpdate = 0;
private int snakeDirection = RIGHT;
private Array<BodyPart> bodyParts = new Array<BodyPart>();
@Override
public void show() {
super.show();
batch = new SpriteBatch();
snakeHead = new Texture(Gdx.files.internal("snakehead.png"));
snakeBody = new Texture(Gdx.files.internal("snakeBody.png"));
apple = new Texture(Gdx.files.internal("apple.png"));
}
@Override
public void render(float delta) {
super.render(delta);
queryInput();
timer -= delta;
if (timer <= 0) {
timer = MOVE_TIME;
moveSnake();
checkForOutOfBounds();
updateBodyPartsPosition();
}
checkAppleCollision();
checkAndPlaceApple();
clearScreen();
draw();
}
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;
}
private void moveSnake() {
snakeXBeforeUpdate = snakeX;
snakeYBeforeUpdate = snakeY;
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;
}
}
}
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;
}
}
private void updateBodyPartsPosition() {
if (bodyParts.size > 0) {
BodyPart bodyPart = bodyParts.removeIndex(0);
bodyPart.updateBodyPosition(snakeXBeforeUpdate, snakeYBeforeUpdate);
bodyParts.add(bodyPart);
}
}
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);
}
}
private void checkAppleCollision() {
if (appleAvailable && appleX == snakeX && appleY == snakeY) {
BodyPart bodyPart = new BodyPart(snakeBody);
bodyPart.updateBodyPosition(snakeX, snakeY);
bodyParts.insert(0,bodyPart);
appleAvailable = false;
}
}
private void clearScreen() {
Gdx.gl.glClearColor(Color.BLACK.r, Color.BLACK.g, Color.BLACK.b, Color.BLACK.a);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
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();
}
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);
}
}
}
首先它在 moveSnake() 中移动头部,确保跟踪头部在移动之前的位置。然后在 updateBodyPartsPosition() 中,它将 body 的最后一块放在刚刚移动头部的地方。