Java迷宫小游戏,老程序员花一天时间完成,你可以吗?_java小游戏

最后

作为过来人,小编是整理了很多进阶架构视频资料、面试文档以及PDF的学习资料,针对上面一套系统大纲小编也有对应的相关进阶架构视频资料


本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

	jmi2.addActionListener(this);
	jmi3.addActionListener(this);
	jmi4.addActionListener(this);
	//设置指令
	jmi1.setActionCommand("restart");
	jmi2.setActionCommand("exit");
	jmi3.setActionCommand("help");
	jmi4.setActionCommand("win");
}
@Override
public void actionPerformed(ActionEvent e) {
	String command = e.getActionCommand();
	System.out.println(command);
	UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
	UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("思源宋体", Font.ITALIC, 18)));
	if ("exit".equals(command)) {
		Object[] options = { "确定", "取消" };
		int response = JOptionPane.showOptionDialog(this, "您确认要退出吗", "",
				JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,
				options, options[0]);
		if (response == 0) {
			System.exit(0);
		} 
	}else if("restart".equals(command)){
		restart();
	}else if("help".equals(command)){
		JOptionPane.showMessageDialog(null, "通过键盘的上下左右来移动",
				"提示!", JOptionPane.INFORMATION_MESSAGE);
	}else if("win".equals(command)){
		JOptionPane.showMessageDialog(null, "移动到终点获得胜利",
				"提示!", JOptionPane.INFORMATION_MESSAGE);
	}	
}

void restart(){
	
}

}


**运行它**  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/4b038930a6d44e44ac91efce7f61d75c.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RrbTEyMzQ1Ng==,size_16,color_FFFFFF,t_70)


### 绘制迷宫的每个单元


1. 初始化相关参数



public final int ROWS=20;//行
public final int COLS=20;//列
public final int H=20;//每一块的宽高
Block[][] blocks = null;//存储每个单元的二维数组


2. 创建迷宫单元类(如果对坐标计算不明白,可以往上翻,有图示说明解释)



import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
/*
* 迷宫单元类
*/
public class Block {
private GamePanel panel = null;
private int i=0;//二维数组的下标i
private int j=0;//二维数组的下标j
private int h=0;//宽高
private int start=6;//偏移像素
//4个顶点坐标
private int x1=0;//x1坐标
private int y1=0;//y1坐标
private int x2=0;//x2坐标
private int y2=0;//y2坐标
private int x3=0;//x3坐标
private int y3=0;//y3坐标
private int x4=0;//x4坐标
private int y4=0;//y4坐标
//上下左右4个墙是否显示,true:显示,false:隐藏
boolean[] walls=new boolean[4];

private boolean visited=false;//是否被访问
//构造
public Block(int i,int j,int h,GamePanel panel){
	this.i=i;
	this.j=j;
	this.h=h;
	this.panel=panel;
	//计算4个顶点的坐标
	init();
}

//计算4个顶点的坐标
private void init() {
	//i代表行 j代表列
	//左上角坐标
	this.x1=start+j\*h;
	this.y1=start+i\*h;
	//右上角坐标
	this.x2=start+(j+1)\*h;
	this.y2=start+i\*h;
	//右下角坐标
	this.x3=start+(j+1)\*h;
	this.y3=start+(i+1)\*h;
	//左下角坐标
	this.x4=start+j\*h;
	this.y4=start+(i+1)\*h;	
	//默认上下左右4个墙都显示
	walls[0]=true;
	walls[1]=true;
	walls[2]=true;
	walls[3]=true;
}

//绘制指示器的方法
public void draw(Graphics g) {
	//绘制迷宫块
	drawBlock(g);
}
//绘制迷宫块
private void drawBlock(Graphics g) {
	//判断上、右、下、左 的墙,true的话墙就会有,否则墙就没有
	boolean top    = walls[0];
	boolean right  = walls[1];
	boolean bottom = walls[2];
	boolean left   = walls[3];
	if(top){//绘制上墙
		g.drawLine(x1, y1, x2, y2);
	}
	if(right){//绘制右墙
		g.drawLine(x2, y2, x3, y3);	
	}
	if(bottom){//绘制下墙
		g.drawLine(x3, y3, x4, y4);	
	}
	if(left){//绘制左墙
		g.drawLine(x4, y4, x1, y1);	
	}
}

}


3. 在GamePanel类中创建方法createBlocks



//创建数组内容
private void createBlocks() {
blocks = new Block[ROWS][COLS];
Block block ;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
block = new Block(i, j,H,this);
blocks[i][j]=block;
}
}
}


4. 在构造函数中调用此方法



//构造方法
public GamePanel(GameFrame mainFrame){
this.setLayout(null);
this.setOpaque(false);
this.mainFrame=mainFrame;
this.panel =this;
//创建菜单
createMenu();
//创建数组内容
createBlocks();
}


5. 在GamePanel中重新paint方法,绘制这些方块



public void paint(Graphics g) {
super.paint(g);
//绘制网格
drawBlock(g);
}

//绘制迷宫块
private void drawBlock(Graphics g) {
Block block ;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
block = blocks[i][j];
if(block!=null){
block.draw(g);
}
}
}
}


运行可以看到一个个的方形绘制出来了  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/5a8a65604c0d423a9ae50853cf915d34.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RrbTEyMzQ1Ng==,size_16,color_FFFFFF,t_70)


### 计算并打通迷宫


1. 给每个单元都增加邻居查找方法(Block类中)



//查找当前单元是否有未被访问的邻居单元
public List findNeighbors() {
//邻居分为上下左右
List res= new ArrayList();//返回的数组

Block top    = this.getNeighbor(0,false);
Block right  = this.getNeighbor(1,false);
Block bottom = this.getNeighbor(2,false);
Block left   = this.getNeighbor(3,false);

if(top!=null){
	res.add(top);
}
if(right!=null){
	res.add(right);
}
if(bottom!=null){
	res.add(bottom);
}
if(left!=null){
	res.add(left);
}
return res;//返回邻居数组

}
//根据方向,获得邻居
public Block getNeighbor(int type,boolean lose_visited) {
Block neighbor;
int ti=0,tj=0;
if(type0){
ti = this.i-1;
tj = this.j;
}else if(type
1){
ti = this.i;
tj = this.j+1;
}else if(type2){
ti = this.i+1;
tj = this.j;
}else if(type
3){
ti = this.i;
tj = this.j-1;
}

Block[][] blocks = panel.blocks;

if(ti<0 || tj<0 || ti>=panel.ROWS || tj>=panel.COLS){//超出边界了
	neighbor = null;
}else{
	//首先找到这个邻居
	neighbor = blocks[ti][tj];
	//判断是否被访问,如果被访问了返回null
	if(neighbor.visited && !lose_visited){//lose\_visited等于true表示忽略访问
		neighbor = null;
	}
}
return neighbor;

}


2. 计算  
 跟着算法来写的代码,唯一要注意的是我设置了一个值unVisitedCount,初始值为所有单元的数量,每当一个单元被标记为已访问后,这个值就递减1,当值为0后就终止循环,结束算法。



//线路的计算处理
private void computed(){
/*
1.将起点作为当前迷宫单元并标记为已访问
2.当还存在未标记的迷宫单元,进行循环
1).如果当前迷宫单元有未被访问过的的相邻的迷宫单元
(1).随机选择一个未访问的相邻迷宫单元
(2).将当前迷宫单元入栈
(3).移除当前迷宫单元与相邻迷宫单元的墙
(4).标记相邻迷宫单元并用它作为当前迷宫单元
2).如果当前迷宫单元不存在未访问的相邻迷宫单元,并且栈不空
(1).栈顶的迷宫单元出栈
(2).令其成为当前迷宫单元
*/
Random random = new Random();
Stack stack = new Stack();//栈
Block current = blocks[0][0];//取第一个为当前单元
current.setVisited(true);//标记为已访问

int unVisitedCount=ROWS\*COLS-1;//因为第一个已经设置为访问了
List<Block> neighbors ;//定义邻居
Block next;
while(unVisitedCount>0){
	neighbors = current.findNeighbors();//查找邻居集合(未被访问的)
	if(neighbors.size()>0){//如果当前迷宫单元有未被访问过的的相邻的迷宫单元
		//随机选择一个未访问的相邻迷宫单元
		int index = random.nextInt(neighbors.size()); 
		next = neighbors.get(index);
		//将当前迷宫单元入栈
		stack.push(current);
		//移除当前迷宫单元与相邻迷宫单元的墙
		this.removeWall(current,next);
		//标记相邻迷宫单元并用它作为当前迷宫单元
		next.setVisited(true);
		//标记一个为访问,则计数器递减1
		unVisitedCount--;//递减
		current = next;
	}else if(!stack.isEmpty()){//如果当前迷宫单元不存在未访问的相邻迷宫单元,并且栈不空
		/\*

1.栈顶的迷宫单元出栈
2.令其成为当前迷宫单元
*/
Block cell = stack.pop();
current = cell;
}
}
}


3. 移除墙



//移除当前迷宫单元与相邻迷宫单元的墙
private void removeWall(Block current, Block next) {
if(current.getI()==next.getI()){//横向邻居
if(current.getJ()>next.getJ()){//匹配到的是左边邻居
//左边邻居的话,要移除自己的左墙和邻居的右墙
current.walls[3]=false;
next.walls[1]=false;
}else{//匹配到的是右边邻居
//右边邻居的话,要移除自己的右墙和邻居的左墙
current.walls[1]=false;
next.walls[3]=false;
}
}else if(current.getJ()==next.getJ()){//纵向邻居
if(current.getI()>next.getI()){//匹配到的是上边邻居
//上边邻居的话,要移除自己的上墙和邻居的下墙
current.walls[0]=false;
next.walls[2]=false;
}else{//匹配到的是下边邻居
//下边邻居的话,要移除自己的下墙和邻居的上墙
current.walls[2]=false;
next.walls[0]=false;
}
}
}


4. 在构造函数中调用computed方法



//构造方法
public GamePanel(GameFrame mainFrame){
this.setLayout(null);
this.setOpaque(false);
this.mainFrame=mainFrame;
this.panel =this;
//创建菜单
createMenu();
//创建数组内容
createBlocks();
//计算处理线路
computed();
}


5. 运行效果  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/e77e9f09577c485fa14e3f951218cb2e.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RrbTEyMzQ1Ng==,size_16,color_FFFFFF,t_70)


### 绘制起点终点


1. 创建Rect类



package main;

import java.awt.Color;
import java.awt.Graphics;

//开始结束方块
public class Rect {
private int i=0;//二维数组的下标i
private int j=0;//二维数组的下标j
private int x=0;//x坐标
private int y=0;//y坐标
private int h=0;//宽高
private int start=6;//偏移像素
private String type=“”;//start end

public Rect(int i,int j,int h,String type){
	this.i=i;
	this.j=j;
	this.h=h;
	this.type=type;
	
}
//初始化
private void init() {
	this.x=start+j\*h+2;
	this.y=start+i\*h+2;
}
//绘制
void draw(Graphics g){
	//计算x、y坐标
	init();
	
	Color oColor = g.getColor();
	if("start".equals(type)){//红色
		g.setColor(Color.red);
	}else{
		g.setColor(Color.blue);
	}
	g.fillRect(x, y, h-3, h-3);
	g.setColor(oColor);
}

//移动
public void move(int type, Block[][] blocks,GamePanel panel) {
	//根据当前start方形,获得对应的迷宫单元
	Block cur = blocks[this.i][this.j];
	
	boolean wall = cur.walls[type];//得到对应的那面墙 
	if(!wall){
		//得到移动方块对应的单元
		Block next = cur.getNeighbor(type,true);
		if(next!=null){
			this.i = next.getI();
			this.j = next.getJ();
			panel.repaint();
			//判断如果i,j等于终点的,则表示获得成功
			if(this.i==panel.end.i && this.j==panel.end.j){
				panel.gameWin();
			}
		}
	}
}

public int getI() {
	return i;
}
public void setI(int i) {
	this.i = i;
}
public int getJ() {
	return j;
}
public void setJ(int j) {
	this.j = j;
}

}


2. 在GamePanel类中创建方法,并在构造中调用。



//创建开始结束的方形
private void createRects() {
start = new Rect(0, 0, H, “start”) ;
end = new Rect(ROWS-1, COLS-1, H, “end”) ;
}



//构造方法
public GamePanel(GameFrame mainFrame){
this.setLayout(null);
this.setOpaque(false);
this.mainFrame=mainFrame;
this.panel =this;
//创建菜单
createMenu();
//创建数组内容
createBlocks();
//计算处理线路
computed();
//创建开始结束的方形
createRects();
}


3. 在paint方法中绘制



@Override
public void paint(Graphics g) {
super.paint(g);
//绘制网格
drawBlock(g);
//绘制开始结束方向
drawRect(g);
}
//绘制开始结束方块
private void drawRect(Graphics g) {
end.draw(g);
start.draw(g);
}


4. 运行一下  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2ebf639b07574cf59114a5ad0b750eee.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RrbTEyMzQ1Ng==,size_16,color_FFFFFF,t_70)


### 加入键盘移动监听


1. 创建监听方法



//添加键盘监听
private void createKeyListener() {
KeyAdapter l = new KeyAdapter() {
//按下
@Override
public void keyPressed(KeyEvent e) {
if(!“start”.equals(gameFlag)) return ;
int key = e.getKeyCode();
switch (key) {
//向上
case KeyEvent.VK_UP:
case KeyEvent.VK_W:
if(start!=null) start.move(0,blocks,panel);
break;

			//向右 
			case KeyEvent.VK_RIGHT:
			case KeyEvent.VK_D:
				if(start!=null) start.move(1,blocks,panel);
				break;
				
			//向下
			case KeyEvent.VK_DOWN:
			case KeyEvent.VK_S:
				if(start!=null) start.move(2,blocks,panel);
				break;
				
			//向左
			case KeyEvent.VK_LEFT:
			case KeyEvent.VK_A:
				if(start!=null) start.move(3,blocks,panel);
				break;
		}
	
	}
	//松开
	@Override
	public void keyReleased(KeyEvent e) {
	}
	
};
//给主frame添加键盘监听
mainFrame.addKeyListener(l);

}


2. 在构造中调用



//构造方法
public GamePanel(GameFrame mainFrame){
this.setLayout(null);
this.setOpaque(false);
this.mainFrame=mainFrame;
this.panel =this;
//创建菜单
createMenu();
//创建数组内容
createBlocks();
//计算处理线路
computed();
//创建开始结束的方形
createRects();
//添加键盘事件监听
createKeyListener();
}


3. 运行  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/cc792888dfc74f069350b9fb0b7c1f3a.gif#pic_center)


### 收尾




### 最后

**如果觉得本文对你有帮助的话,不妨给我点个赞,关注一下吧!**

![](https://img-blog.csdnimg.cn/img_convert/cdb61f51f0280189b586a93433b34580.webp?x-oss-process=image/format,png)

![](https://img-blog.csdnimg.cn/img_convert/ae26ca63d9f5d60712ee4340ae3bb03d.webp?x-oss-process=image/format,png)

> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**

**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

Frame;
	this.panel =this;
	//创建菜单
	createMenu();
	//创建数组内容
	createBlocks();
	//计算处理线路
	computed();
	//创建开始结束的方形
	createRects();
	//添加键盘事件监听
	createKeyListener();
}

  1. 运行
    在这里插入图片描述

收尾

最后

如果觉得本文对你有帮助的话,不妨给我点个赞,关注一下吧!

[外链图片转存中…(img-U1KHI16J-1715453342241)]

[外链图片转存中…(img-FWtkLfcW-1715453342242)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值