Javafx 贪吃蛇哦
最近无聊又用JavaFx实现了一遍贪吃蛇,现在发出来给萌新参考。
思路:主要分为控制器、视图、任务线程三部分。控制器就是控制蛇的,视图就是用来展示蛇的,然后任务线程就是用来一直维持蛇的运动。
文件结构:

首先是一些常量:
package constant;import entity.SnakeCell;import java.util.LinkedList;public interface Const {LinkedList SNAKE_CELL_LIST = new LinkedList<>();double cellLen = 20;
}package constant;public interface Direction {int L = 0;int R = 1;int U = 2;int D = 3;
}
控制器:
package controller;import constant.Const;
import constant.Direction;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import test.Client;public class SnakeActionController implements EventHandler {@Overridepublic void handle(KeyEvent event) {if (event.getEventType().equals(KeyEvent.KEY_PRESSED)) {if (event.getCode().getName().equals(KeyCode.LEFT.getName()) && Client.current_direction != Direction.R) {Client.current_direction = Direction.L;} else if (event.getCode().getName().equals(KeyCode.RIGHT.getName()) && Client.current_direction != Direction.L) {Client.current_direction = Direction.R;} else if (event.getCode().getName().equals(KeyCode.UP.getName()) && Client.current_direction != Direction.D) {Client.current_direction = Direction.U;} else if (event.getCode().getName().equals(KeyCode.DOWN.getName()) && Client.current_direction != Direction.U) {Client.current_direction = Direction.D;}}}
}
蛇的实体类:
package entity;import javafx.scene.paint.Color;public class SnakeCell {private double x;private double y;private double cellLen;private Color color;private String shade;public SnakeCell(int x, int y, double cellLen, Color color, String shade){this.x = x;this.y = y;this.cellLen = cellLen;this.color = color;this.shade = shade;}public double getX() {return x;}public void setX(double x) {this.x = x;}public double getY() {return y;}public void setY(double y) {this.y = y;}public double getCellLen() {return cellLen;}public void setCellLen(double cellLen) {this.cellLen = cellLen;}public Color getColor() {return color;}public void setColor(Color color) {this.color = color;}public String getShade() {return shade;}public void setShade(String shade) {this.shade = shade;}@Overridepublic String toString() {return "SnakeCell{" +"x=" + x +", y=" + y +", cellLen=" + cellLen +", color=" + color +", shade='" + shade + '\'' +'}';}
}
视图:
package view;import constant.Const;
import entity.SnakeCell;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;import java.util.List;public class SnakePane extends Pane {private SnakeCell food;private Canvas canvas;private GraphicsContext context;private List cells = Const.SNAKE_CELL_LIST;private int score = 0;private int speed = 200;public void setSpeed(int speed) {this.speed = speed;}public int getSpeed() {return speed;}public SnakePane() {canvas = new Canvas(800, 800);context = canvas.getGraphicsContext2D();context.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());context.setStroke(Color.BLACK);context.strokeRect(50, 50, canvas.getWidth() - 60, canvas.getHeight() - 60);context.strokeText("当前分数为:" + score + " 分",20, 20, 100);context.strokeText("speed:" + speed + "ms/次",100, 20, 50);getChildren().add(canvas);}public void drawCell(){cells.forEach(cell->{context.setFill(cell.getColor());context.fillOval(cell.getX(), cell.getY(), cell.getCellLen(), cell.getCellLen());});}public void repaint(){context.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());context.setStroke(Color.BLACK);context.strokeRect(50, 50, canvas.getWidth() - 60, canvas.getHeight() - 60);context.strokeText("当前分数为:" + score + " 分",50, 20, 200);context.strokeText("当前speed:" + speed + " ms/次",200, 20, 200);cells.forEach(cell->{context.setFill(cell.getColor());context.fillOval(cell.getX(), cell.getY(), cell.getCellLen(), cell.getCellLen());});context.setFill(food.getColor());context.fillRect(food.getX(), food.getY(), food.getCellLen(), food.getCellLen());}public void setScore(int score){this.score = score;}public int getScore(){return score;}public void setFood(SnakeCell food){this.food = food;}public SnakeCell getFood(){return food;}
}
任务线程::
package task;import constant.Const;
import constant.Direction;
import entity.SnakeCell;
import javafx.concurrent.Task;
import javafx.scene.paint.Color;
import test.Client;
import view.SnakePane;import java.util.Random;public class MoveTask extends Task {private SnakePane pane;private Random random = new Random();public MoveTask(SnakePane pane) {this.pane = pane;}public volatile static boolean isForceCancel = false;public volatile static boolean isOverBound = false;public volatile static boolean isEatItSelf = false;private int currentSize = 0;public static void reDetect() {isOverBound = false;isEatItSelf = false;}private boolean isEat(SnakeCell cell) {if (cell.getX() == pane.getFood().getX() && cell.getY() == pane.getFood().getY()) {pane.setScore(pane.getScore() + 1);return true;}return false;}private boolean isEatItSelf() {SnakeCell first = Const.SNAKE_CELL_LIST.getFirst();for (int i = 1; i < Const.SNAKE_CELL_LIST.size(); i++) {if (first.getX() == Const.SNAKE_CELL_LIST.get(i).getX() && first.getY() == Const.SNAKE_CELL_LIST.get(i).getY()) {return true;}}return false;}@Overrideprotected Integer call() throws Exception {while (!isCancelled()) {if (Const.SNAKE_CELL_LIST.getFirst().getX() < 50 || Const.SNAKE_CELL_LIST.getFirst().getY() < 50 ||Const.SNAKE_CELL_LIST.getFirst().getX() > 770 || Const.SNAKE_CELL_LIST.getFirst().getY() > 770) {isOverBound = true;continue;}if (Const.SNAKE_CELL_LIST.size() > 3 && isEatItSelf()) {isEatItSelf = true;continue;}SnakeCell cell;switch (Client.current_direction) {case Direction.L:cell = Const.SNAKE_CELL_LIST.removeLast();cell.setX(Const.SNAKE_CELL_LIST.getFirst().getX() - 20);cell.setY(Const.SNAKE_CELL_LIST.getFirst().getY());Const.SNAKE_CELL_LIST.addFirst(cell);if (isEat(cell)) {controlFood(Direction.L);}break;case Direction.R:cell = Const.SNAKE_CELL_LIST.removeLast();cell.setX(Const.SNAKE_CELL_LIST.getFirst().getX() + 20);cell.setY(Const.SNAKE_CELL_LIST.getFirst().getY());Const.SNAKE_CELL_LIST.addFirst(cell);if (isEat(cell)) {controlFood(Direction.R);}break;case Direction.U:cell = Const.SNAKE_CELL_LIST.removeLast();cell.setY(Const.SNAKE_CELL_LIST.getFirst().getY() - 20);cell.setX(Const.SNAKE_CELL_LIST.getFirst().getX());Const.SNAKE_CELL_LIST.addFirst(cell);if (isEat(cell)) {controlFood(Direction.U);}break;case Direction.D:cell = Const.SNAKE_CELL_LIST.removeLast();cell.setY(Const.SNAKE_CELL_LIST.getFirst().getY() + 20);cell.setX(Const.SNAKE_CELL_LIST.getFirst().getX());Const.SNAKE_CELL_LIST.addFirst(cell);if (isEat(cell)) {controlFood(Direction.D);}break;}if (Const.SNAKE_CELL_LIST.size() != currentSize && Const.SNAKE_CELL_LIST.size() % 6 == 0){currentSize = Const.SNAKE_CELL_LIST.size();pane.setSpeed(pane.getSpeed() - 20);}pane.repaint();Thread.sleep(pane.getSpeed());}return null;}private void controlFood(int dir) {SnakeCell food = pane.getFood();switch (dir) {case Direction.L:food.setX(Const.SNAKE_CELL_LIST.getFirst().getX() + 20);break;case Direction.R:food.setX(Const.SNAKE_CELL_LIST.getFirst().getX() - 20);break;case Direction.D:food.setY(Const.SNAKE_CELL_LIST.getFirst().getY() - 20);break;case Direction.U:food.setY(Const.SNAKE_CELL_LIST.getFirst().getY() + 20);break;}food.setColor(Color.BLACK);Const.SNAKE_CELL_LIST.addLast(food);// 食物SnakeCell food1 = createFood();while (checkIsOnSnakeBody(food1)) {food1 = createFood();}pane.setFood(food1);}private boolean checkIsOnSnakeBody(SnakeCell food) {for (SnakeCell cell : Const.SNAKE_CELL_LIST) {if (cell.getY() == food.getY() && cell.getX() == food.getX())return true;}return false;}private SnakeCell createFood() {int x = random.nextInt(770);x = x - x % 20;if (x / 10 % 10 % 2 == 0)x = x - 10;if (x < 50)x = 50;int y = random.nextInt(770);y = y - y % 20;if (y / 10 % 10 % 2 == 0)y = y - 10;if (y < 50)y = 50;return new SnakeCell(x, y, Const.cellLen, Color.GREEN, "rectangle");}}
这是测试类,也就是主函数所在:
package test;import constant.Const;
import constant.Direction;
import controller.SnakeActionController;
import entity.SnakeCell;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import task.MoveTask;
import view.SnakePane;import java.util.Optional;public class Client extends Application {public static int current_direction = Direction.R;private volatile static boolean isRequestClose = false;public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage primaryStage) throws Exception {primaryStage.setTitle("贪吃蛇大作战");SnakePane pane = new SnakePane();pane.drawCell();action(primaryStage, pane);Scene scene = new Scene(pane, 850, 800);scene.setOnKeyPressed(new SnakeActionController());primaryStage.setScene(scene);primaryStage.show();}private void action(Stage primaryStage, SnakePane pane){preStart(pane);SnakeCell food = new SnakeCell(190, 150, 20, Color.GREEN, "rectangle");pane.setFood(food);MoveTask task = new MoveTask(pane);task.setOnCancelled(event -> {// 在关闭主窗口会回调这里if (MoveTask.isForceCancel) {String msg = "";if (MoveTask.isOverBound)msg = "您已出界!!";if (MoveTask.isEatItSelf)msg = "您已经不小心把自己给吃了!!";Alert alert = new Alert(Alert.AlertType.NONE, msg + "\n是否重新开局???",new ButtonType("重新开局", ButtonBar.ButtonData.YES), new ButtonType("退出游戏", ButtonBar.ButtonData.NO));alert.setTitle("提示");Optional buttonType = alert.showAndWait();if (buttonType.isPresent()) {if (buttonType.get().getButtonData().equals(ButtonBar.ButtonData.YES)) {//todo 重新开局MoveTask.isForceCancel = false;MoveTask.reDetect();action(primaryStage, pane);} else {//todo 退出exit(task);Platform.exit();}}}});new Thread(task).start();Task task1 = new Task() {@Overrideprotected Integer call() throws Exception {while (!isRequestClose) {if (MoveTask.isEatItSelf || MoveTask.isOverBound) {task.cancel(true);MoveTask.isForceCancel = true;break;}}return null;}};new Thread(task1).start();primaryStage.setOnCloseRequest(new EventHandler() {@Overridepublic void handle(WindowEvent event) {exit(task);}});}private synchronized void preStart(SnakePane pane) {Const.SNAKE_CELL_LIST.clear();SnakeCell cell = new SnakeCell(50, 50, 20, Color.BLACK, "rectangle");SnakeCell cell1 = new SnakeCell(70, 50, 20, Color.BLACK, "rectangle");SnakeCell cell2 = new SnakeCell(90, 50, 20, Color.BLACK, "rectangle");Const.SNAKE_CELL_LIST.add(cell);Const.SNAKE_CELL_LIST.add(cell1);Const.SNAKE_CELL_LIST.add(cell2);pane.setScore(0);current_direction = Direction.R;pane.setSpeed(200);}private void exit(MoveTask task) {isRequestClose = true;task.cancel();}
}
因为较为简单,相信自己看看就懂了,,,
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
