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

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

前言

人类建造迷宫已有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最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。

到此这篇关于Java实现简单的迷宫游戏详解的文章就介绍到这了,更多相关Java迷宫游戏内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java递归实现迷宫游戏

    目录 1.问题由来 2.问题的描述 3.思路分析 4.代码实现 5.结果输出 1.问题由来 迷宫实验是取自心理学的一个古典实验.在该实验中,把一只老鼠从一个无顶大盒子的门放入,在盒中设置了许多墙,对行进方向形成了多处阻挡.盒子仅有一个出口,在出口处放置一块奶酪,吸引老鼠在迷宫中寻找道路以到达出口.对同一只老鼠重复进行上述实验,一直到老鼠从入口到出口,而不走错一步.老鼠经多次试验终于得到它学习走迷宫的路线. 2.问题的描述 有一个迷宫地图,有一些可达的位置,也有一些不可达的位置(障碍.墙壁.边界)

  • 老程序员教你一天时间完成Java迷宫小游戏

    目录 效果图 实现思路 迷宫算法(网上参考的) 相关图示说明 代码实现 创建窗口 创建菜单及菜单选项 绘制迷宫的每个单元 计算并打通迷宫 绘制起点终点 加入键盘移动监听 收尾 总结 效果图 实现思路 1.创建运行窗口. 2.创建菜单. 3.绘制迷宫的每个单元. 4.通过算法计算迷宫路径,并打通路径,形成迷宫. 5.绘制起点终点. 6.添加键盘事件控制起点方块移动. 7.收尾. 迷宫算法(网上参考的) 1.将起点作为当前迷宫单元并标记为已访问 2.当还存在未标记的迷宫单元,进行循环 1).如果当前

  • Java实现的迷宫游戏

    完整项目地址: https://github.com/richenyunqi/Maze-game 软件总体框架 该软件主要分为如下三个模块: 参数设置模块 按钮功能模块按钮功能模块 迷宫主界面模块迷宫主界面模块 软件各模块介绍 参数设置模块 1.迷宫大小相关参数: ROWS(即迷宫行数,默认设置为奇数,最小值为11,最大值为99,默认值为11): COLS(即迷宫列数,默认设置为奇数,最小值为11,最大值为99,默认值为11): Lattice's width(即组成迷宫的格子的宽度,迷宫格子默

  • Java实现经典游戏复杂迷宫

    目录 前言 主要设计 功能截图 代码实现 总结 前言 人类建造迷宫已有5000年的历史.在世界的不同文化发展时期,这些奇特的建筑物始终吸引人们沿着弯弯曲曲.困难重重的小路吃力地行走,寻找真相.迷宫类小游戏应运而生.在游戏中,迷宫被表现为冒险舞台里,藏有各式各样奇妙与谜题或宝藏的危险区域.型态有洞窟.人工建筑物.怪物巢穴.密林或山路等.迷宫内有恶徒或凶猛的生物(真实存在或想像物体都有)徘徊,其中可能会有陷阱.不明设施.遗迹等. <复杂迷宫>游戏是用java语言实现,采用了swing技术进行了界面

  • Java小项目之迷宫游戏的实现方法

    项目要求: 一个网格迷宫由n行n列的单元格组成,每个大院个要么是空地(用0表示),要么是障碍物(用1表示),你的任务是找一条从起点到终点的移动序列,其中只能上下左右移动到相邻单元格.任何时候都不能在有障碍物的单元格中,也不能走到迷宫之外,起点为左上角和终点右下角. 项目功能: 解决迷宫路径查找问题,寻找一条从左上角迷宫入口到右下角迷宫出口的一条有效路径,0代表可走,1代表能走,找到请输出最终的迷宫和路径信息,找不到请输出不存在有效路径. 思路: 1.定义一个迷宫节点类型(MazeNode)的二维

  • Java编写迷宫小游戏

    缘起: 去年(大三上学期)比较喜欢写小游戏,于是想试着写个迷宫试一下. 程序效果: 按下空格显示路径: 思考过程: 迷宫由一个一个格子组成,要求从入口到出口只有一条路径. 想了一下各种数据结构,似乎树是比较合适的,从根节点到每一个子节点都只有一条路径.假设入口是根节点,出口是树中某个子节点,那么,从根节点到该子节点的路径肯定是唯一的. 所以如果能构造一棵树把所有的格子都覆盖到,也就能够做出一个迷宫了. 另外还要求树的父节点和子节点必须是界面上相邻的格子. 在界面显示时,父节点和子节点之间共用的边

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

    目录 前言 主要设计 功能截图 代码实现 窗口布局 核心算法 总结 前言 人类建造迷宫已有5000年的历史.在世界的不同文化发展时期,这些奇特的建筑物始终吸引人们沿着弯弯曲曲.困难重重的小路吃力地行走,寻找真相.迷宫类小游戏应运而生.在游戏中,迷宫被表现为冒险舞台里,藏有各式各样奇妙与谜题或宝藏的危险区域.型态有洞窟.人工建筑物.怪物巢穴.密林或山路等.迷宫内有恶徒或凶猛的生物(真实存在或想像物体都有)徘徊,其中可能会有陷阱.不明设施.遗迹等. <简单迷宫>游戏是用java语言实现,采用了sw

  • Java实现年兽大作战游戏详解

    目录 前言 一.玩法介绍 二.代码介绍 2.1 程序入口[Frame] 2.2 构造器[GamePanel] 2.3 游戏逻辑实现[GamePanel] 2.4 游戏的血液[InitProcessor] 2.5 实体类[FireworksDO][FlowersDO] 2.6 图片素材 三.总结 前言 春节要到了,看惯了前端各种小游戏,确实做得很好,很精致.但是我也要为后端程序员稍微做一点贡献,做一款java版本的[年兽大作战]. 这个游戏加上编写文章,上班摸鱼时间加上回家的空闲时间,大概花了三天

  • Java实现猜数字小游戏详解流程

    猜数字游戏 系统自动生成一个随机整数(1-100), 然后由用户输入一个猜测的数字. 如果输入的数字比该随机数小, 提示 "低 了", 如果输入的数字比该随机数大, 提示 "高了" , 如果输入的数字和随机数相等, 则提示 "猜对了 整理思路 1. 我们玩游戏的时候,都有开始游戏和退出游戏 2. 其次,它要生成一个随机数,如果是固定值,哪有什么意思? 3. 再者,我们要输入数字,根据它反馈的情况进行判断和猜测数字的大小 4. 但是我们不可能说一次就判断成功

  • Java实现飞机大战-II游戏详解

    目录 前言 主要设计 功能截图 代码实现 启动类 玩家飞机 总结 前言 <飞机大战-II>是一款融合了街机.竞技等多种元素的经典射击手游.华丽精致的游戏画面,超炫带感的技能特效,超火爆画面让你肾上腺素爆棚,给你带来全方位震撼感受,体验飞行战斗的无限乐趣. 游戏是用java语言实现,采用了swing技术进行了界面化处理,设计思路用了面向对象思想. 主要需求: 玩家控制一台战斗机,以保证自己不被敌机消灭,消灭越多的敌机可以收取能量,补充玩家战斗机数量.玩家战斗机数量为0,则游戏结束. 主要设计 1

  • Java利用深度搜索解决数独游戏详解

    目录 一.问题描述 二.输入和输出 三.输入和输出样例 四.分析 五.算法设计 六.代码 七.测试 一.问题描述 数独是一项非常简单的任务.如下图所示,一张 9 行 9 列的表被分成 9 个 3*3 的小方格.在一些单元格中写上十进制数字 1~9,其他单元格为空.目标是用 1 ~9 的数字填充空单元格,每个单元格一个数字,这样在每行.每列和每个被标记为 3*3 的子正方形内,所有 1~9 的数字都会出现.编写一个程序来解决给定的数独任务. 二.输入和输出 1.输入 对于每个测试用例,后面都跟 9

  • Java使用GUI实现贪吃蛇游戏详解

    最近在学GUI,然后又有读者希望我写一下相关的实战.刚好我又在B站上找到了一个关于GUI的学习视频,然后里面又刚好有这个实战,我便写了下来.注:代码来源为B站的一个up主:狂神. 游戏主启动类: import javax.swing.*; //游戏主启动类 public class startGame { public static void main(String[] args) { JFrame frame=new JFrame(); frame.setBounds(10,10,900,72

  • Java实现广度优先遍历的示例详解

    目录 什么是广度优先 一个简单的例子 程序实现 总结 什么是广度优先 广度就是扩展开,广度优先的意思就是尽量扩展开.所以在算法实现的时候,就是一个循环遍历枚举每一个邻接点.其基本思路就是按层扩展,扩得越广越好. 伪代码如下: for(int i = 0; i < children.size(); i++){ children.get(i); // 调用每一个子节点 } 一个简单的例子 我们以一个简单的迷宫为例,以1代表墙,0代表路径,我们构造一个具有出入口的迷宫. 1 1 0 1 1 1 1 1

  • Java设计模式之原型设计示例详解

    目录 简单说一下(定义) 稍微夸一下(优缺点) 顺便提一下(适用场景) 着重讲一下(深.浅克隆) 多多用一下(结构.代码实现) 简单说一下(定义) 什么是原型模式:原型模式是用于创建重复的对象,同时又能保证性能.用一个已经创建的实例作为原型,通过复制该原型对象来创建一个或者多个和原型相同或者相似的新对象 举例说明:我们都玩过打飞机的游戏,敌军的飞机可谓是数不胜数,但是如果每出一架敌机都要重新实例化的话,那么自然我们的功能很复杂.所以这个时候我们的原型模式就派上用场了,只实例化一架飞机出来,其他的

  • java数据结构算法稀疏数组示例详解

    目录 一.什么是稀疏数组 二.场景用法 1.二维数组转稀疏数组思路 2.稀疏数组转二维数组思路 3.代码实现 一.什么是稀疏数组 当一个数组a中大部分元素为0,或者为同一个值,那么可以用稀疏数组b来保存数组a. 首先,稀疏数组是一个数组,然后以一种特定的方式来保存上述的数组a,具体处理方法: 记录数组a一共有几行几列 记录a中有多少个不同的值 最后记录不同值的元素所在行列,以及具体的值,放在一个小规模的数组里,以缩小程序的规模. 这个小规模的数组,就是稀疏数组. 举个栗子,左侧是一个二维数组,一

  • Java并发编程Semaphore计数信号量详解

    Semaphore 是一个计数信号量,它的本质是一个共享锁.信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量中有可用的许可时,线程能获取该许可:否则线程必须等待,直到有可用的许可为止. 线程可以通过release()来释放它所持有的信号量许可(用完信号量之后必须释放,不然其他线程可能会无法获取信号量). 简单示例: package me.socketthread; import java.util.concurrent.ExecutorService;

随机推荐