實作效果
游戲開始:


游戲結束:顯示得分

準備階段
首先準備Java開發環境以及對應用到的Jar包,
需借助JavaFX的圖形庫,
目錄結構

代碼分析
Point類如下:
package snake;
/**
* @ClassName Point
* @Description :TODO
* @Author Josvin
* @Date 2021/02/04/14:08
*/
public class Point {
public int x;
public int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
具體來看SnakeApp的實作:
- 定義需要的變數(具體見代碼注釋)
// 定義需要的變數
// 定義游戲區域的大小,寬和高各多少格子
private static final int WIDTH = 20;
private static final int HEIGHT = 20;
// 繪制圖形的時候,每個格子所占的像素
private static final int GRID_SIZE = 40;
//畫布的寬和高
private static final int CANVAS_WIDTH = WIDTH * GRID_SIZE;
private static final int CANVAS_HEIGHT = HEIGHT * GRID_SIZE;
// 定義游戲本身
// 🐍的移動速度
// speed : 每秒移動的幀數
// 幀數越高速度越快
private static int speed;
// 定義食物
private static Point food = new Point(-1, -1);
// 定義🐍
// 🐍的長度最長就是沾滿整個畫布,=長*寬
private static Point[] snake = new Point[WIDTH * HEIGHT];
//現在🐍的身體有多少節
private static int snakeLength = 0;
// 蛇現在的朝向(用列舉的方式列出四個狀態)
enum Direction {
UP, LEFT, DOWN, RIGHT
}
private static Direction direction;
// 構建一個隨機生成器,用于生成食物的位置
private static Random random = new Random();
// 游戲結束標志位
private static boolean gameOver;
// 游戲得分
private static int score;
- 生成食物,也就是生成一個食物的位置,后邊在渲染即可
// 用來在畫布上隨機生成食物
private static void newFood() {
// 1、 不能生成到畫布外邊
// x of [0,WIDTH)
// y of [0,HEIGHT)
// 2、不能和🐍 的身體出現碰撞
int x;
int y;
do {
x = random.nextInt(WIDTH);///x 的范圍一定是 [0, WIDTH)
y = random.nextInt(HEIGHT);///y 的范圍一定是 [0,HEIGHT)
} while (isCollision(x, y));
// isCollision (x,y)回傳true ,代表和🐍的身體有碰撞
// 賦值
food.x = x;
food.y = y;
}
- 實作
isCollision (x,y)回傳true ,代表和🐍的身體有碰撞
private static boolean isCollision(int x, int y) {
for (int i = 0; i < snakeLength; i++) {
Point point = snake[i];
if (point.x == x && point.y == y) {
// 說明有沖突,則需要重新生成食物位置
return true;
}
}
return false;
}
-
蛇的移動也就是給
snake陣列賦值,標記蛇的位置(有一下情況)- 蛇走到了畫布邊界----游戲結束
- 蛇碰到自己-----游戲結束
- 蛇吃到食物----長度加1,速度提高,并且得分
// 下來處理每一幀,要做的事情
private static void frame() {
// 移動蛇 -- 移動身體
// 注意從后往前,后邊的總放在前邊的一個位置
for (int i = snakeLength - 1; i >= 1; i--) {
snake[i].x = snake[i - 1].x;
snake[i].y = snake[i - 1].y;
}
// 移動蛇 -- 移動蛇頭
Point head = snake[0];
switch (direction) {
case UP:
head.y--;
break;
case LEFT:
head.x--;
break;
case DOWN:
head.y++;
break;
case RIGHT:
head.x++;
break;
}
// 判斷蛇是否走出游戲邊界,走出的游戲結束!
if (head.x < 0 || head.x >= WIDTH || head.y < 0 || head.y >= HEIGHT) {
gameOver = true;
return;
}
// 判斷蛇有沒有碰到自己的身體其他位置 —— 碰到了,游戲結束
for (int i = 1; i < snakeLength; i++) {
Point point = snake[i];
if (head.x == point.x && head.y == point.y) {
gameOver = true;
return;
}
}
// 判斷有沒有吃到食物
if (head.x == food.x && head.y == food.y) {
// 如果吃到了食物
// 1. 蛇的身體增加一節
// 坐標隨便,只要不影響繪圖,因為隨著下一幀到來,蛇移動之后,坐標就正確了
snake[snakeLength++] = new Point(-1, -1);
// 根據速度大小得分
score = score + speed * 2;
// 2. 重新生成新的食物
newFood();
// 3. 讓速度增加
speed++;
}
}
- 渲染界面(每次需要對游戲界面擦除在渲染,其中蛇頭需要單獨渲染,并對游戲是否結束進行判斷,如果結束渲染結束界面)
// 每一幀要做的繪制作業 -- render(渲染)
private static void render(GraphicsContext gc) {
// 1. 通過重新繪制背景,擦除游戲界面
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
// 2. 進行蛇的繪制 —— 每一塊是一個矩形
// 蛇頭單獨渲染
gc.setFill(Color.DARKVIOLET);
// 矩形大小是 GRID_SIZE - 2;上下左右各控一個像素
gc.fillRect(snake[0].x * GRID_SIZE + 1, snake[0].y * GRID_SIZE + 1, GRID_SIZE - 2, GRID_SIZE - 2);
for (int i = 1; i < snakeLength; i++) {
Point point = snake[i];
gc.setFill(Color.GREEN);
// 矩形大小是 GRID_SIZE - 2;上下左右各控一個像素
gc.fillRect(point.x * GRID_SIZE + 1, point.y * GRID_SIZE + 1, GRID_SIZE - 2, GRID_SIZE - 2);
}
// 3. 進行食物的繪制 —— 圓形
gc.setFill(Color.YELLOW);
gc.fillOval(food.x * GRID_SIZE, food.y * GRID_SIZE, GRID_SIZE, GRID_SIZE);
// 4. 進行游戲結束的繪制
if (gameOver) {
gc.setFill(Color.BLACK);
gc.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
gc.setFill(Color.CORNSILK);
// 矩形大小是 GRID_SIZE - 2;上下左右各控一個像素
gc.fillRect(WIDTH*GRID_SIZE/2 - 30*5, HEIGHT*GRID_SIZE/4, 300, 80);
gc.setFill(Color.RED);
gc.setFont(new Font(20));
gc.fillText("最終游戲得分: "+score, WIDTH * GRID_SIZE / 2 - 30 * 3, HEIGHT * GRID_SIZE / 4 + 30);
gc.fillText("游戲結束,再接再厲!", WIDTH * GRID_SIZE / 2 - 30 * 3, HEIGHT * GRID_SIZE / 4 + 60);
}
}
- 重寫start,完成游戲初始化,啟動定時器,系結鍵盤按下事件
@Override
public void start(Stage primaryStage) throws Exception {
// 進行游戲初始化
newGame();
// 面板物件
Pane pane = new Pane();
// 畫布物件
Canvas canvas = new Canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
pane.getChildren().add(canvas);
// 場景物件
Scene scene = new Scene(pane);
// 在畫布上進行圖形繪制
final GraphicsContext gc = canvas.getGraphicsContext2D();
AnimationTimer timer = new AnimationTimer() {
long lastTick;
@Override
public void handle(long now) {
// now :以納秒為單位,本次呼叫handle的時間
if (gameOver) {
return;
}
if (lastTick == 0 || now - lastTick > 1e9 / speed) {
lastTick = now;
frame();
render(gc);
}
}
};
// 呼叫 start(),啟動定時器
timer.start();
// 為 scene 系結鍵盤按下事件
// 每當鍵盤上有 鍵 按下時,怎么辦
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case W:
case UP:
if (direction != Direction.DOWN) {
direction = Direction.UP;
}
break;
case A:
case LEFT:
if (direction != Direction.RIGHT) {
direction = Direction.LEFT;
}
break;
case S:
case DOWN:
if (direction != Direction.UP) {
direction = Direction.DOWN;
}
break;
case D:
case RIGHT:
if (direction != Direction.LEFT) {
direction = Direction.RIGHT;
}
break;
case R:
if (gameOver) {
newGame();
}
break;
}
}
});
primaryStage.setScene(scene);
primaryStage.setTitle("貪吃蛇小游戲 by Josvin");
primaryStage.setResizable(false);
primaryStage.sizeToScene();
primaryStage.show();
}
- main方法:
public static void main(String[] args) {
// launch: 引導;加載
//Application.launch(SnakeApp.class, args);
launch(args);
}
Github倉庫地址:貪吃蛇游戲代碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/256694.html
標籤:其他
上一篇:用Unity3d仿制前幾日爆紅的“合成大西瓜”小游戲原始碼
下一篇:簡易計算器
