使用LED矩阵玩贪吃蛇小游戏

本文必看

1、请小伙伴先完成通过MAX7219模块驱动矩阵屏
2、由于精力有限,Python版本暂不提供了,对应逻辑可以参考如下代码即可。
3、首先需要启用树莓派的SPI接口

所需材料

  • 树莓派
  • MAX7219芯片
  • 若干Led(最低不少于64个)/ 整体矩阵屏
  • 万能板(焊接Led)
  • 轻触开关5个

实现方案

通过控制电路,点亮/熄灭Led灯实现,Led矩阵地图如下

0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  

模拟贪吃蛇动画

  • 0:空白地图
  • 1:蛇的身体(点亮Led灯)
  • 2:食物(点亮Led灯)
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  1  0  0  0  
0  0  0  0  1  0  0  0  
0  0  0  0  1  0  0  0  
0  0  0  0  0  0  0  0  
0  2  0  0  0  0  0  0  

向上走一步

0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  1  0  0  0  
0  0  0  0  1  0  0  0  
0  0  0  0  1  0  0  0  
0  0  0  0  0  0  0  0  
0  0  0  0  0  0  0  0  
0  2  0  0  0  0  0  0  

电路连接图

树莓派、轻触开关、MAX7219芯片连接图

none

游戏程序

坐标类,标记蛇的身体,与食物的坐标系。

public class Coordinate {
    int x;
    int y;

    public Coordinate(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return "Coordinate{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}

贪吃蛇类,目前游戏规则蛇碰到右侧墙壁,头从左侧出来,如果设置碰到墙直接游戏结束,可以修改下面if (newX > 7){游戏结束}处代码, 并且此类可以不需要矩阵屏单独运行调试,通过不停的调用debugPrintMap()方法, 在控制台打印游戏动画。

public class Snake {

    /**
     * 初始化地图
     */
    public int[][] map = new int[8][8];

    /**
     * 当前食物位置
     */
    public Coordinate food;

    /**
     * x y 蛇的身体  模拟被点亮的灯坐标
     */
    public List<Coordinate> body = new LinkedList<>();

    /**
     * 爬行速度
     */
    public int walkingSpeed;

    /**
     * 当前行走方向
     */
    public volatile int direction = 1;

    /**
     * 0 正在爬行  1 蛇已经死亡  2 蛇完成挑战
     */
    public volatile int status = 0;

    public Snake(int walkingSpeed, int direction) {
        this.walkingSpeed = walkingSpeed;
        this.direction = direction;

        // 初始化身体
        body.add(new Coordinate(4, 4));
        body.add(new Coordinate(4, 5));
        body.add(new Coordinate(4, 6));
        // 初始化食物
        food = this.randomFood();
    }

    public synchronized void upper() {
        if (direction == 2) {
            // 不可回头
            return;
        }
        direction = 1;
    }

    public synchronized void lower() {
        if (direction == 1) {
            return;
        }
        direction = 2;
    }

    public synchronized void right() {
        if (direction == 3) {
            return;
        }
        direction = 4;
    }

    public synchronized void left() {
        if (direction == 4) {
            return;
        }
        direction = 3;
    }

    public synchronized void move() {
        // 获取头部坐标
        Coordinate st = this.body.get(0);
        int newY = st.y;
        int newX = st.x;
        switch (direction) {
            case 1:
                // 上
                newY = st.y - 1;
                break;
            case 2:
                // 下
                newY = st.y + 1;
                break;
            case 3:
                // 左
                newX = st.x - 1;
                break;
            case 4:
                // 右
                newX = st.x + 1;
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + direction);
        }
        // 碰到右侧墙壁,头从左侧出来
        if (newX > 7) {
            newX = 0;
        }
        // 碰到左侧侧墙壁,头从右侧出来
        if (newX < 0) {
            newX = 7;
        }
        if (newY > 7) {
            newY = 0;
        }
        if (newY < 0) {
            newY = 7;
        }
        // 是否吃到了自己
        boolean hitSelf = this.hitSelf(newX, newY);
        if (hitSelf) {
            System.out.println("吃到自己,游戏结束");
            this.status = 1;
            return;
        }
        // 可以走
        this.body.add(0, new Coordinate(newX, newY));
        // 是否吃到了食物
        if (food.x == newX && food.y == newY) {
            // 吃到了食物,食物的位置重新随机
            food = this.randomFood();
        } else {
            this.body.remove(this.body.size() - 1);
        }
        if (this.body.size() >= 55) {
            System.out.println("你赢了");
            this.status = 2;
        }
    }

    /**
     * 坐标是否为自己身体某一部分
     *
     * @param x x
     * @param y y
     * @return true 是
     */
    public boolean hitSelf(int x, int y) {
        for (Coordinate s : body) {
            if (s.x == x && s.y == y) {
                return true;
            }
        }
        return false;
    }


    /**
     * 随机一个食物
     */
    public Coordinate randomFood() {
        List<Coordinate> foods = new ArrayList<>();
        for (int y = 0; y < map.length; y++) {
            for (int x = 0; x < map[y].length; x++) {
                // 排除掉自己,不会在自己身上出现食物
                if (this.hitSelf(x, y)) {
                    continue;
                }
                foods.add(new Coordinate(x, y));
            }
        }
        return foods.remove(ThreadLocalRandom.current().nextInt(0, foods.size()));
    }


    /**
     * debug
     */
    public void debugPrintMap() {
        System.out.println();
        System.out.println();
        for (int y = 0; y < map.length; y++) {
            for (int x = 0; x < map[y].length; x++) {
                // 食物坐标
                if (food.x == x && food.y == y) {
                    System.out.print("2  ");
                    continue;
                }
                // 蛇身体
                if (this.hitSelf(x, y)) {
                    System.out.print("1  ");
                    continue;
                }
                System.out.print("0  ");
            }
            System.out.println();
        }
    }

}

完整代码见:pi4j-demoopen in new window

更新日期:
作者: qwding