package maze2;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
@SuppressWarnings("serial")
public class Canvas extends JPanel{
private int rows;
private int cols ;
private Box[][] box;
private int width;
private int height;
private EtchedBorder border = new EtchedBorder(EtchedBorder.RAISED); //阳刻浮雕化类型
private int start_y,start_x;
private int end_x,end_y;
private int move_row,move_col;
private boolean[][] visite ;
private boolean gameOver;
private int[] keyRow = new int[850];
private int[] keyCol = new int[850];
private boolean searchSuccess;
private int searchCount;
public Canvas(int rows,int cols)
{
initKeyPath(); //初始化路径
this.rows = rows;
this.cols = cols;
box = new Box[rows][cols]; //新建二维地图格子
visite = new boolean[rows][cols]; //新建二维boolean矩阵,各格子是否可以访问
this.setFocusable(true); //将控件设置成可获取焦点状态,默认是无法获取焦点的,只有设置成true,才能获取控件的点击事件
setBorder(border); //设置一个边界把控件包围
//对每个格子new Box(),使他们具有Box的属性
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
box[i][j] = new Box();
}
}
setBackground(Color.white); //设置背景颜色
createMap(); //创建地图
this.addKeyListener(new ControlKeyListener());
gameOver = false;
}
public void initKeyPath()
{
for(int i=0;i<810;i++)
{
keyRow[i] = -1;
keyCol[i] = -1;
}
}
public void initBox()
{
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
box[i][j].setVisited(false); //先设置为不可移动
}
}
for(int i=1;i<searchCount;i++)
{
box[keyRow[i]][keyCol[i]].setKeyBox(false);
}
searchSuccess = false;
gameOver = false;
}
/*画图*/
public void createMap()
{
dfs(start_y,start_x);
}
public void dfs(int y,int x)
{
boolean flag = true; //格子是否遍历的标志
int direction;
visite[y][x] = true; //初始(0,0)点设置已被访问,后调用设置该格子已被访问
/*当所有格子都遍历,即都用于生成地图后,退出循环*/
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
if(visite[i][j]==false)
{
flag = false;
break;
}
}
}
/*当还有flag为true,返回继续循环*/
if(flag==true)
{
return;
}
direction = (int)(4*Math.random()); // 4× 随机生成(0,1)之间的整数
for(int i=0;i<4;i++)
{
direction=(direction+1)%4; //4个方向生成地图
switch(direction)
{
case 0:
if(y-1>=0&&visite[y-1][x]==false) //条件,不超过边界且访问visite标志 为false时,没有被访问时
{
flag = false; //表示该格子已用
box[y][x].setUpWall(false); //此处设置无墙
box[y-1][x].setDownWall(false); //此处设置无墙
dfs(y-1,x); //在下一格重新随机画图
}
break;
case 1:
if(y+1<rows&&visite[y+1][x]==false)
{
flag = false;
box[y][x].setDownWall(false);
box[y+1][x].setUpWall(false);
dfs(y+1,x);
}
break;
case 2:
if(x-1>=0&&visite[y][x-1]==false)
{
flag =false;
box[y][x].setLeftWall(false);
box[y][x-1].setRightWall(false);
dfs(y,x-1);
}
break;
case 3:
if(x+1<cols&&visite[y][x+1]==false)
{
flag=false;
box[y][x].setRightWall(false);
box[y][x+1].setLeftWall(false);
dfs(y,x+1);
}
break;
}
}
}
public void setStartPos()
{
//随机设置起始点
start_y = (int)(rows*Math.random());
start_x = (int)(cols*Math.random());
//初始化移动点
move_row = start_y;
move_col = start_x;
}
public void setEndPos()
{
//随机设置终点,但与起始点之间保持矩阵要小于10
do
{
end_y = (int)(rows*Math.random());
end_x = (int)(cols*Math.random());
}while(Math.sqrt(Math.pow(Math.abs(end_x-start_x),2)+Math.pow(Math.abs(end_y-start_y),2))<10);
}
private class ControlKeyListener extends KeyAdapter
{
/*按键监听*/
public void keyPressed(KeyEvent ke)
{
//当游戏没结束时
if(!gameOver)
{
switch(ke.getKeyCode())
{
//按下按键,分别向各方向移动
case KeyEvent.VK_UP:
//System.out.println("上");
moveUp();
break;
case KeyEvent.VK_DOWN:
//System.out.println("下");
moveDown();
break;
case KeyEvent.VK_LEFT:
//System.out.println("左");
moveLeft();
break;
case KeyEvent.VK_RIGHT:
//System.out.println("右");
moveRight();
break;
default:
break;
}
}
}
}
public int getRows()
{
return rows;
}
public int getCols()
{
return cols;
}
public int getMove_row()
{
return move_row;
}
public int getMove_col()
{
return move_col;
}
//向上移动
public void moveUp()
{
//条件:向上移动, 在边界内同时向上的方向没有墙,isUpWall为false
if(move_row-1>=0&&!box[move_row][move_col].isUpWall())
{
move_row-=1; //移动数-1
//如果等于终点
if(move_row==end_y && move_col==end_x )
{
gameOver = true;//游戏结束
JOptionPane.showMessageDialog(null,"恭喜你找到出口",null,JOptionPane.INFORMATION_MESSAGE);
}
//每移动一步重新画图
repaint();
}
}
//下面解释同上
public void moveDown()
{
if(move_row+1<rows&&!box[move_row][move_col].isDownWall())
{
move_row+=1;
if(move_row==end_y && move_col==end_x )
{
gameOver = true;
JOptionPane.showMessageDialog(null,"恭喜你找到出口",null,JOptionPane.INFORMATION_MESSAGE);
}
repaint();
}
}
public void moveLeft()
{
if(move_col-1>=0&&!box[move_row][move_col].isLeftWall())
{
move_col-=1;
if(move_row==end_y && move_col==end_x )
{
gameOver = true;
JOptionPane.showMessageDialog(null,"恭喜你找到出口",null,JOptionPane.INFORMATION_MESSAGE);
}
repaint();
}
}
public void moveRight()
{
if(move_col+1<cols&&!box[move_row][move_col].isRightWall())
{
move_col+=1;
if(move_row==end_y && move_col==end_x )
{
gameOver = true;
JOptionPane.showMessageDialog(null,"恭喜你找到出口",null,JOptionPane.INFORMATION_MESSAGE);
}
repaint();
}
}
//正确路径
public void keyPath()
{
searchPath(move_row,move_col,0); //调用寻找路径方法
//将关键路径的格子设置为true,searchCount为步数
for(int i=1;i<searchCount;i++)
{
box[keyRow[i]][keyCol[i]].setKeyBox(true);
}
}
public void searchPath(int y,int x,int step)
{
if(step!=0)
{
keyRow[step]=y;
keyCol[step]=x;
}
box[y][x].setVisited(true); //格子设置已经被访问
//当为终点时,返回
if(y==end_y&&x==end_x)
{
searchSuccess = true;
searchCount = step;
return;
}
//条件: 向上寻找,如果游戏没结束,上面没有墙,在边界内,且该格子还没被访问时,向上寻找 下同:
//注:这里visit和上面的box的visit不同,上面用于遍历每个格子创建全图,这里用于遍历每个格子寻找正确路径
if((!searchSuccess)&&(!box[y][x].isUpWall())&&(y-1>=0)&&(!box[y-1][x].isVisited()))
{
searchPath(y-1,x,step+1);
}
if((!searchSuccess)&&(!box[y][x].isDownWall())&&(y+1<rows)&&(!box[y+1][x].isVisited()))
{
searchPath(y+1,x,step+1);
}
if((!searchSuccess)&&(!box[y][x].isLeftWall())&&(x-1>=0)&&(!box[y][x-1].isVisited()))
{
searchPath(y,x-1,step+1);
}
if((!searchSuccess)&&(!box[y][x].isRightWall())&&(x+1<cols)&&(!box[y][x+1].isVisited()))
{
searchPath(y,x+1,step+1);
}
}
//画出地图 paint
public void paintComponent(Graphics g)
{
super.paintComponent(g);
width = getSize().width/rows; //平均每格长度,用来�