请用Java实现贪吃蛇
时间: 2023-11-14 10:08:35 浏览: 33
好的,下面是基于JavaFX实现的贪吃蛇游戏代码:
```java
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class SnakeGame extends Application {
private static final int BLOCK_SIZE = 20;
private static final int WIDTH = 30 * BLOCK_SIZE;
private static final int HEIGHT = 20 * BLOCK_SIZE;
private static final int NUM_ROWS = HEIGHT / BLOCK_SIZE;
private static final int NUM_COLS = WIDTH / BLOCK_SIZE;
private static final int INITIAL_SNAKE_LENGTH = 3;
private Random random;
private Canvas canvas;
private GraphicsContext gc;
private Snake snake;
private Food food;
private List<Wall> walls;
private boolean gameOver;
private Label scoreLabel;
private int score;
@Override
public void start(Stage primaryStage) {
random = new Random();
canvas = new Canvas(WIDTH, HEIGHT);
gc = canvas.getGraphicsContext2D();
snake = new Snake();
food = new Food();
walls = new ArrayList<>();
gameOver = false;
scoreLabel = new Label("Score: " + score);
scoreLabel.setTextFill(Color.WHITE);
BorderPane root = new BorderPane();
root.setCenter(canvas);
root.setBottom(scoreLabel);
BorderPane.setAlignment(scoreLabel, Pos.CENTER);
Scene scene = new Scene(root, WIDTH, HEIGHT);
scene.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.UP) {
snake.setDirection(Direction.UP);
} else if (event.getCode() == KeyCode.DOWN) {
snake.setDirection(Direction.DOWN);
} else if (event.getCode() == KeyCode.LEFT) {
snake.setDirection(Direction.LEFT);
} else if (event.getCode() == KeyCode.RIGHT) {
snake.setDirection(Direction.RIGHT);
}
});
primaryStage.setScene(scene);
primaryStage.setTitle("Snake Game");
primaryStage.show();
AnimationTimer timer = new AnimationTimer() {
private long lastUpdate = 0;
private int moveCount = 0;
@Override
public void handle(long now) {
if (lastUpdate == 0) {
lastUpdate = now;
return;
}
if (now - lastUpdate < 1000000000 / 10) {
return;
}
lastUpdate = now;
if (gameOver) {
stop();
return;
}
moveCount++;
if (moveCount % 5 == 0) {
snake.move();
moveCount = 0;
if (snake.checkCollision(food)) {
score += 10;
scoreLabel.setText("Score: " + score);
snake.grow();
spawnFood();
}
for (Wall wall : walls) {
if (snake.checkCollision(wall)) {
gameOver = true;
}
}
if (snake.checkSelfCollision()) {
gameOver = true;
}
}
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, WIDTH, HEIGHT);
gc.setFill(Color.WHITE);
gc.setStroke(Color.GRAY);
gc.setLineWidth(2);
gc.strokeRect(0, 0, WIDTH, HEIGHT);
snake.draw(gc);
food.draw(gc);
for (Wall wall : walls) {
wall.draw(gc);
}
}
};
timer.start();
spawnFood();
spawnWalls();
}
private void spawnFood() {
int x = random.nextInt(NUM_COLS) * BLOCK_SIZE;
int y = random.nextInt(NUM_ROWS) * BLOCK_SIZE;
food.setPosition(x, y);
}
private void spawnWalls() {
for (int i = 0; i < 5; i++) {
int x = random.nextInt(NUM_COLS - 4) * BLOCK_SIZE + 2 * BLOCK_SIZE;
int y = random.nextInt(NUM_ROWS - 4) * BLOCK_SIZE + 2 * BLOCK_SIZE;
walls.add(new Wall(x, y));
}
}
private enum Direction {
UP, DOWN, LEFT, RIGHT
}
private class Snake {
private List<Block> blocks;
private Direction direction;
public Snake() {
blocks = new ArrayList<>();
direction = Direction.RIGHT;
for (int i = 0; i < INITIAL_SNAKE_LENGTH; i++) {
int x = (NUM_COLS / 2 - INITIAL_SNAKE_LENGTH / 2 + i) * BLOCK_SIZE;
int y = NUM_ROWS / 2 * BLOCK_SIZE;
blocks.add(new Block(x, y));
}
}
public void move() {
Block head = blocks.get(blocks.size() - 1);
Block newHead = null;
if (direction == Direction.UP) {
newHead = new Block(head.getX(), head.getY() - BLOCK_SIZE);
} else if (direction == Direction.DOWN) {
newHead = new Block(head.getX(), head.getY() + BLOCK_SIZE);
} else if (direction == Direction.LEFT) {
newHead = new Block(head.getX() - BLOCK_SIZE, head.getY());
} else if (direction == Direction.RIGHT) {
newHead = new Block(head.getX() + BLOCK_SIZE, head.getY());
}
blocks.add(newHead);
blocks.remove(0);
}
public void grow() {
Block tail = blocks.get(0);
Block newTail = null;
if (direction == Direction.UP) {
newTail = new Block(tail.getX(), tail.getY() + BLOCK_SIZE);
} else if (direction == Direction.DOWN) {
newTail = new Block(tail.getX(), tail.getY() - BLOCK_SIZE);
} else if (direction == Direction.LEFT) {
newTail = new Block(tail.getX() + BLOCK_SIZE, tail.getY());
} else if (direction == Direction.RIGHT) {
newTail = new Block(tail.getX() - BLOCK_SIZE, tail.getY());
}
blocks.add(0, newTail);
}
public boolean checkCollision(Block block) {
for (Block b : blocks) {
if (b.getX() == block.getX() && b.getY() == block.getY()) {
return true;
}
}
return false;
}
public boolean checkSelfCollision() {
Block head = blocks.get(blocks.size() - 1);
for (int i = 0; i < blocks.size() - 1; i++) {
Block b = blocks.get(i);
if (b.getX() == head.getX() && b.getY() == head.getY()) {
return true;
}
}
return false;
}
public void setDirection(Direction direction) {
if (this.direction == Direction.UP && direction == Direction.DOWN) {
return;
} else if (this.direction == Direction.DOWN && direction == Direction.UP) {
return;
} else if (this.direction == Direction.LEFT && direction == Direction.RIGHT) {
return;
} else if (this.direction == Direction.RIGHT && direction == Direction.LEFT) {
return;
}
this.direction = direction;
}
public void draw(GraphicsContext gc) {
gc.setFill(Color.GREEN);
for (Block block : blocks) {
gc.fillRect(block.getX(), block.getY(), BLOCK_SIZE, BLOCK_SIZE);
}
}
}
private class Block {
private int x;
private int y;
public Block(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
private class Food {
private int x;
private int y;
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
public void draw(GraphicsContext gc) {
gc.setFill(Color.RED);
gc.fillOval(x, y, BLOCK_SIZE, BLOCK_SIZE);
}
}
private class Wall {
private int x;
private int y;
public Wall(int x, int y) {
this.x = x;
this.y = y;
}
public boolean checkCollision(Block block) {
return block.getX() == x && block.getY() == y;
}
public void draw(GraphicsContext gc) {
gc.setFill(Color.DARKGRAY);
gc.fillRect(x, y, BLOCK_SIZE, BLOCK_SIZE);
}
}
public static void main(String[] args) {
launch(args);
}
}
```
在这个实现中,我们使用了JavaFX来创建窗口和画布,并且用一个AnimationTimer来控制游戏的帧率。Snake类表示贪吃蛇本身,其中包含了一个由Block对象组成的列表,每个Block对象代表一个蛇节。Food类表示食物,Wall类表示障碍物。在Snake类中,我们使用Direction枚举类型来表示贪吃蛇的方向,以及一些方法来移动和增长贪吃蛇,检查碰撞等。在主应用程序中,我们创建了一个Snake对象、一个Food对象和一些Wall对象,并且在AnimationTimer中不断更新它们的位置和状态。如果检测到碰撞,则游戏结束。