Java实现简单的迷宫游戏详解
作者:小虚竹and掘金 发布时间:2022-11-22 05:00:52
标签: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;
}
}
来源:https://juejin.cn/post/7058582271413977095
0
投稿
猜你喜欢
- SpringBoot 如何进行参数校验在日常的接口开发中,为了防止非法参数对业务造成影响,经常需要对接口的参数做校验,例如登录的时候需要校验
- 初次安装Android Studio,遇到了不少问题,这是其中的一个,分享如下,同时求各位dalao关注一下啦((*^__^*) )使用不同
- 注:若是为了解决问题,可直接查看第二部分。1.安装与启动在下载安装前,请安装好JDK并配置好环境变量。ActiveMQ可到官网下载。点击进入
- 方式一:if语句控制// 例如:Column( mainAxisAlig
- 总体实现思路是启动一个生产者项目注册, 将所含服务注册到zookeeper的注册中心, 然后在启动一个消费者项目,将所需服务向zookeep
- 基本介绍数据回显:模型数据导向视图(模型数据 ---> Controller ---> 视图)说明:SpringMVC在调用方法
- 前言在使用Java开发接口请求中,我们需要对请求进行进行统一返回值,这时候我们自己封装一个统一的Result返回类,下面就介绍下我用的这种的
- 先看看代码再说:package com.b510.note; import java.math.BigInteger;
- PS:本文包含了大部分strings函数的说明,并附带举例说明。本来想自己整理一下的,发现已经有前辈整理过了,就转了过来。修改了原文一些源码
- 第一次进入应用的时候,都会有一个引导页面,引导页面的实现起来也很简单,实现的方式也有很多,下面是自己写的一个引导页面的效果,大致的实现思路为
- 这几天做项目,有些地方的图片需要用到圆形图片,所以百度了一下,在github上找到一个开源项目,处理很简单,效果如下:使用起来特别简单,一共
- 这篇文章主要介绍了spring boot如何实现切割分片上传,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- SpringMVC * 介绍springMVC 中的 * 用于拦截控制器方法的执行。先创建出前置需要的一些条件:<a th:href=
- Mybatis Plus流式查询mybatis plus 中自定义如下接口,就可以实现流式查询,mybatis 中同样适用。@Select(
- 对于大文件的处理,无论是用户端还是服务端,如果一次性进行读取发送、接收都是不可取,很容易导致内存问题。所以对于大文件上传,采用切块分段上传,
- 概念Java中的集合就是一种容器,可以容纳不同种类的数据,这些容纳是建立在未知的基础上。优点1.可以动态保存任意多个对象,使用比较方便。2.
- 本文实例为大家分享了java仿windows记事本小程序的具体代码,供大家参考,具体内容如下import java.awt.Checkbox
- 前言不积跬步无以至千里,不积小流,无以成江海在公司一般来说,都只会接触一些CRUD的业务,很多时候可能你想设计很多的代码结构,但是时间不允许
- 一、javaBeanjavaBean:一种类的规格编写规范javaBean在MVC设计模型中是model,又称模型层,在一般的程序中,我们称
- 现在有一张订单表t_stockorder,其拥有id、code、client_id、merchandise_id、merchandise_n