信息发布→ 登录 注册 退出

Java实现简单的迷宫游戏详解

发布时间:2026-01-11

点击量:
目录
  • 前言
  • 主要设计
  • 功能截图
  • 代码实现
    • 窗口布局
    • 核心算法
  • 总结

    前言

    人类建造迷宫已有5000年的历史。在世界的不同文化发展时期,这些奇特的建筑物始终吸引人们沿着弯弯曲曲、困难重重的小路吃力地行走,寻找真相。迷宫类小游戏应运而生。在游戏中,迷宫被表现为冒险舞台里,藏有各式各样奇妙与谜题或宝藏的危险区域。型态有洞窟、人工建筑物、怪物巢穴、密林或山路等。迷宫内有恶徒或凶猛的生物(真实存在或想像物体都有)徘徊,其中可能会有陷阱、不明设施、遗迹等。

    《简单迷宫》游戏是用java语言实现,采用了swing技术进行了界面化处理,设计思路用了面向对象思想。

    主要需求

    方向键控制移动,角色走出迷宫,游戏胜利。

    主要设计

    1、构建游戏地图面板

    2、设定迷宫地图,包含可走的通道,不可走的墙体,还有出口位置

    3、键盘的上下左右按键,来控制角色的移动

    4、角色移动的算法,通道可走,遇到墙体不可走

    5、走到终点,有成功通关的提示。

    功能截图

    游戏开始页面

    移动界面

    通关的界面

    代码实现

    窗口布局

    public class MainApp extends JFrame {
        public MainApp(){
            // 设置窗体名称
            setTitle("简易迷宫游戏");
            // 获取自定义的游戏地图面板的实例对象
            MapPanel panel=new MapPanel();
            Container contentPane = getContentPane();
            contentPane.add(panel);
            // 执行并构建窗体设定
            pack();
        }
    
        public static void main(String[] args) {
            MainApp app=new MainApp();
            // 允许窗体关闭操作
            app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            // 显示窗体
            app.setVisible(true);
        }
    }

    核心算法

    public class MapPanel extends JPanel implements KeyListener {
        // 窗体的宽和高
        private static final int WIDTH = 450;
        private static final int HEIGHT = 450;
        // 设定背景方格默认行数和列数
        private static final int ROW = 15;
        private static final int COLUMN = 15;
        // 设置窗体单个图像,采用30x30大小的图形,一行设置15个,即450像素,即窗体默认大小
        private static final int SIZE = 30;
    
        // 设定迷宫地图
        private static final byte FLOOR = 0;// 0表示通道地板
        private static final byte WALL = 1;// 1表示墙
        private static final byte END = 2;// 2表示终点
        private byte[][] map = {
                {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
                {1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1},
                {1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1},
                {1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1},
                {1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1},
                {1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1},
                {1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
                {1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1},
                {1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1},
                {1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1},
                {1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1},
                {1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1},
                {1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1},
                {1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1},
                {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 2, 1}
        };
    
        // 设定显示的图像对象
        private Image floorImage;
        private Image wallImage;
        private Image heroImage;
        private Image endImage;
    
        // 角色坐标
        private int x, y;
    
        // 区分上下左右按键的移动
        private static final byte LEFT = 0;
        private static final byte RIGHT = 1;
        private static final byte UP = 2;
        private static final byte DOWN = 3;
    
        public MapPanel() {
            // 设定面板大小
            setPreferredSize(new Dimension(WIDTH, HEIGHT));
            // 加载图片
            loadImage();
            // 初始化角色坐标
            this.x = 1;
            this.y = 1;
            // 设定焦点在本窗体并且监听键盘事件
            setFocusable(true);
            addKeyListener(this);
        }
    
        /**
         * 画地图和角色
         *
         * @param g 画笔
         */
        public void paintComponent(Graphics g) {
            drawMap(g);
            drawRole(g);
        }
    
        /**
         * 画角色(英雄)
         *
         * @param g 画笔
         */
        private void drawRole(Graphics g) {
            g.drawImage(heroImage, x * SIZE, y * SIZE, SIZE, SIZE, this);
        }
    
        private void loadImage() {
            // 获取当前类对应相对位置image文件夹下的地板图像
            ImageIcon icon = new ImageIcon(getClass().getResource("images/floor.png"));
            // 将地板图像实例赋给floorImage变量
            floorImage = icon.getImage();
            // 获取墙体图像
            icon = new ImageIcon(getClass().getResource("images/wall.gif"));
            wallImage = icon.getImage();
            // 获取英雄图像
            icon = new ImageIcon(getClass().getResource("images/hero.png"));
            heroImage = icon.getImage();
            // 获取终点图像
            icon = new ImageIcon(getClass().getResource("images/end.png"));
            endImage = icon.getImage();
        }
    
        /**
         * 根据map[i][j]中记录的地图信息绘制图案画出地图
         * 标记0为地板,标记1为墙
         *
         * @param g
         */
        private void drawMap(Graphics g) {
            for (int i = 0; i < ROW; i++) {
                for (int j = 0; j < COLUMN; j++) {
                    switch (map[i][j]) {
                        case 0:
                            // 标记为0时画出地板,在指定位置加载图像
                            g.drawImage(floorImage, j * SIZE, i * SIZE, this);
                            break;
                        case 1:
                            // 标记为1时画出城墙
                            g.drawImage(wallImage, j * SIZE, i * SIZE, this);
                            break;
                        case 2:
                            // 标记为2时画出终点
                            g.drawImage(endImage, j * SIZE, i * SIZE, SIZE, SIZE, this);
                        default:
                            break;
                    }
                }
            }
        }
    
        @Override
        public void keyTyped(KeyEvent e) {
    
        }
    
        @Override
        public void keyPressed(KeyEvent e) {
            // 根据按键进行移动
            int keyCode = e.getKeyCode();// 获取按键编码
            switch (keyCode) {
                // 左方向键或'A'键,都可以左移
                case KeyEvent.VK_LEFT:
                    move(LEFT);
                    break;
                case KeyEvent.VK_A:
                    move(LEFT);
                    break;
                // 右方向键或'D'键,都可以右移
                case KeyEvent.VK_RIGHT:
                    move(RIGHT);
                    break;
                case KeyEvent.VK_D:
                    move(RIGHT);
                    break;
                // 上方向键或'W'键,都可以上移
                case KeyEvent.VK_UP:
                    move(UP);
                    break;
                case KeyEvent.VK_W:
                    move(UP);
                    break;
                // 下方向键或'S'键,都可以下移
                case KeyEvent.VK_DOWN:
                    move(DOWN);
                    break;
                case KeyEvent.VK_S:
                    move(DOWN);
                    break;
                default:
                    break;
            }
            // 重新绘制窗体图像
            repaint();
            if (isFinish(x, y)) {
                // 移动到出口
                JOptionPane.showMessageDialog(this, "恭喜通关!");
            }
        }
    
        @Override
        public void keyReleased(KeyEvent e) {
    
        }
    
        /**
         * 判断是否允许移动,如果传入的坐标不是墙则可以移动
         *
         * @param x
         * @param y
         * @return 允许移动则返回true,否则返回false
         */
        private boolean isAllowMove(int x, int y) {
            // 以判断(x,y)是WALL还是FLOOR来作为是否能移动的根据
            // 1表示墙,不能移动;0表示地板,可以移动
            if (x < COLUMN && y < ROW) {// 进行参数校验,不能超过数组的长度
                return map[y][x] != 1;
            }
            return false;
        }
    
        /**
         * 移动角色人物
         *
         * @param event 传入移动方向,分别可以是LEFT、RIGHT、UP、DOWN
         */
        private void move(int event) {
            switch (event) {
                case LEFT:// 左移
                    if (isAllowMove(x - 1, y)) {// 判断左移一步后的位置是否允许移动(不是墙就可以移动)
                        x--;
                    }
                    break;
                case RIGHT:// 右移
                    if (isAllowMove(x + 1, y)) {
                        x++;
                    }
                    break;
                case UP:// 上移
                    if (isAllowMove(x, y - 1)) {
                        y--;
                    }
                    break;
                case DOWN:// 下移
                    if (isAllowMove(x, y + 1)) {
                        y++;
                    }
                default:
                    break;
            }
        }
    
        /**
         * 传入人物的坐标来判断是否到达终点
         *
         * @param x
         * @param y
         * @return
         */
        private boolean isFinish(int x, int y) {
            // 2表示终点图像
            // 注意:x坐标表示第几列,y坐标表示第几行,所以是map[y][x]而不是map[x][y]
            return map[y][x] == END;
        }
    }

    总结

    通过此次的《简易迷宫》游戏实现,让我对swing的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。

    java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。

    在线客服
    服务热线

    服务热线

    4008888355

    微信咨询
    二维码
    返回顶部
    ×二维码

    截屏,微信识别二维码

    打开微信

    微信号已复制,请打开微信添加咨询详情!