Javafx 贪吃蛇哦

最近无聊又用JavaFx实现了一遍贪吃蛇,现在发出来给萌新参考。

思路:主要分为控制器、视图、任务线程三部分。控制器就是控制蛇的,视图就是用来展示蛇的,然后任务线程就是用来一直维持蛇的运动。

文件结构:

首先是一些常量:

package constant;

import entity.SnakeCell;

import java.util.LinkedList;

public interface Const {
    LinkedList<SnakeCell> 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<KeyEvent> {

    @Override
    public 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;
    }


    @Override
    public 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<SnakeCell> 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<Integer> {
    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;
    }

    @Override
    protected 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);
    }

    @Override
    public 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> 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<Integer> task1 = new Task<Integer>() {
            @Override
            protected 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<WindowEvent>() {
            @Override
            public 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();
    }
}

因为较为简单,相信自己看看就懂了,,, 

 

 

  • 6
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值