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

作者:小虚竹and掘金 时间:2022-11-22 05:00:52 

前言

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

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

主要需求

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

主要设计

1、构建游戏地图面板

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

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

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

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

功能截图

游戏开始页面

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

移动界面

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

通关的界面

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

代码实现

窗口布局


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;
   }
}

来源:https://juejin.cn/post/7058582271413977095

标签:Java,迷宫,游戏
0
投稿

猜你喜欢

  • 使用Java实现串口通信

    2023-02-13 05:45:02
  • Java 关于String字符串原理上的问题

    2021-05-26 12:48:44
  • MybatisPlus实现对象嵌套关联查询一对多List集合查询

    2022-04-27 16:00:12
  • android自定义View圆圈拖动

    2023-09-14 01:02:55
  • Android编程使用GestureDetector实现简单手势监听与处理的方法

    2021-11-18 17:07:43
  • Spring Boot 2.7.6整合redis与低版本的区别

    2023-11-11 19:44:56
  • Android10.0实现本地音乐播放(附源码下载)

    2022-12-05 20:29:40
  • spring mvc url匹配禁用后缀访问操作

    2021-11-19 23:57:34
  • android 中 SQLiteOpenHelper的封装使用详解

    2022-11-09 12:36:57
  • 全面解析Android应用开发中Activity类的用法

    2022-03-11 00:48:53
  • Java properties 和 yml 的区别解析

    2023-04-01 22:28:09
  • DWR异常情况处理常见方法解析

    2022-10-14 02:10:50
  • Java打印出所有的水仙花数的实现代码

    2023-03-06 17:24:22
  • Eclipse查看开发包jar里源代码的方法

    2023-08-01 14:47:57
  • java虚拟机学习笔记进阶篇

    2022-01-07 04:53:06
  • Android使用Matrix旋转图片模拟碟片加载过程

    2022-08-22 21:07:32
  • Java 获取Web项目相对webapp地址的实例

    2022-07-03 17:46:00
  • C#中Winform窗体Form的关闭按钮变灰色的方法

    2023-06-06 09:11:34
  • 深入浅出重构Mybatis与Spring集成的SqlSessionFactoryBean(上)

    2021-12-01 18:27:49
  • Java中Map的遍历方法及性能测试

    2023-07-14 08:54:15
  • asp之家 软件编程 m.aspxhome.com