package autoFindPath;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* 自动寻路示例
* @author tiger
*
* 鼠标点到哪里,则寻路到哪里。
* 点到人物,则清理掉路径。
* 红色方块为行动路径。绿色方块为人物。
* 灰色方块可通行。黑色方块不可通行。
*
*/
public class FindPathTest extends JPanel implements MouseListener{
private int size = 20;
private int row, column;
/**
* 0为可通过点, 1为不可通过点
*/
private int[][] map = {
{0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,1,0,0,0,0,0},
{0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0},
{0,0,0,0,0,0,0,0,0,0,0},
{0,0,1,0,0,0,0,0,1,0,0},
{0,0,1,0,0,0,0,0,1,0,0}
};
/**
* 人物位置
*/
private int playerX, playerY = 2;
/**
* 目标位置
*/
private int targetX, targetY;
public FindPathTest() {
row = map.length;
column = map[0].length;
this.setPreferredSize(new Dimension(column * size, row * size));
this.setFocusable(true);
this.addMouseListener(this);
}
@Override
public void paint(Graphics g) {
super.paint(g);
//地图
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[i].length; j++) {
if(map[i][j] == 0)
{
g.setColor(Color.gray);
}
else if(map[i][j] == 1)
{
g.setColor(Color.black);
}
g.fillRect(j * size, i * size, size, size);
}
}
//演示路径
g.setColor(Color.red);
for (int i = 0; i < pathList.size(); i++) {
int[] obj = (int[]) pathList.get(i);
g.fillRect(obj[0] * size, obj[1] * size, size, size);
}
//人物
g.setColor(Color.green);
g.fillRect(playerX * size, playerY * size, size, size);
}
@Override
public void mousePressed(MouseEvent e) {
targetX = e.getX() / size;
targetY = e.getY() / size ;
try {
openlist.clear();
closelist.clear();
pathList.clear();
if(targetX == playerX && targetY == playerY) //点击为当前位置,不做处理
{
this.repaint();
return;
}
playerMove(); //人物运动到目标点
repaint();
} catch (Exception e2) {
e2.printStackTrace();
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
/**
* 人物运动
*/
@SuppressWarnings("unchecked")
private void playerMove() {
int[] dirs = findPath();
}
@SuppressWarnings("unchecked")
private int[] findPath()
{
int[] dirs = null;
int x = playerX, y = playerY;
while (true) {
List aroundPos = this.getAroundPos(x, y);
if(aroundPos.isEmpty()) //说明从x,y处无法到达终点
{
this.removeList(openlist, x, y); //openlist中删除位置为x, y的元素
this.removeList(closelist, x, y); //openlist中删除位置为x, y的元素
}else{
openlist.addAll(aroundPos);
}
int[] nearestPos = getNearPos();
if(nearestPos == null)
{
System.out.println("找不到路径!");
return null;
}
closelist.add(nearestPos);
//到达了终点
if(nearestPos[0] == targetX && nearestPos[1] == targetY)
{
break;
}
else //没有到终点,继续寻找
{
x = nearestPos[0];
y = nearestPos[1];
}
}
//打印一下
for (int i = 0; i < closelist.size(); i++) {
int[] data = (int[]) closelist.get(i);
System.out.println(data[0] + ", " + data[1] + ", " + data[2]);
}
System.out.println();
//得到最终的路径
int[] temp = (int[]) closelist.get(closelist.size() - 1);
pathList.add(temp);
while(temp[0] != playerX || temp[1] != playerY)
{
temp = getPrePos(temp);
int[] data;
for (int i = 0; i < closelist.size(); i++) {
data = (int[]) closelist.get(i);
if(data[0] == temp[0] && data[1] == temp[1])
{
temp = data;
pathList.add(temp);
break;
}
}
}
//打印一下
for (int i = 0; i < pathList.size(); i++) {
int[] data = (int[]) pathList.get(i);
System.out.println(data[0] + ", " + data[1] + ", " + data[2]);
}
playerX = targetX;
playerY = targetY;
return dirs;
}
private List pathList = new LinkedList();
private List openlist = new LinkedList();
private List closelist = new LinkedList();
private void removeList(List list, int x, int y) {
for (int i = 0; i < list.size(); i++) {
int[] listData = (int[]) list.get(i);
if(listData[0] == x && listData[1] == y)
{
list.remove(i);
return;
}
}
}
/**
* 得到上一步的位置
* @param temp
* @return
*/
private int[] getPrePos(int[] temp) {
switch(temp[2])
{
case LEFT:
return new int[]{temp[0] + 1, temp[1], temp[2]};
case RIGHT:
return new int[]{temp[0] - 1, temp[1], temp[2]};
case UP:
return new int[]{temp[0], temp[1] + 1, temp[2]};
case DOWN:
return new int[]{temp[0], temp[1] - 1, temp[2]};
}
return null;
}
private int[] getNearPos() {
int distance = Integer.MAX_VALUE;
int[] result = null;
for (int i = 0; i < openlist.size(); i++) {
int[] obj = (int[]) openlist.get(i);
int temp = this.getDistance(obj[0], obj[1], targetX, targetY);
if(temp < distance)
{
distance = temp;
result = obj;
}
}
return result;
}
/**
* 得到x,y位置周围的位置(这些位置不在openlist和closelist中且可以通过)
* @return
*/
private List getAroundPos(int x, int y)
{
List list = new ArrayList();
//左边
if(x > 0 && map[y][x - 1] != 1)
{
int[] obj = new int[3];
obj[0] = x - 1;
obj[1] = y;
obj[2] = LEFT;
if(this.isExistAtList(openlist, obj) == false && this.isExistAtList(closelist, obj) == false)
{
list.add(obj);
}
}
//右边
if(x < column - 1 && map[y][x + 1] != 1)
{
int[] obj = new int[3];
obj[0] = x + 1;
obj[1] = y;
obj[2] = RIGHT;
if(this.isExistAtList(openlist, obj) == false && this.isExistAtList(closelist, obj) == false)
{
list.add(obj);
}
}
//上边
if(y > 0 && map[y - 1][x] != 1)
{
int[] obj = new int[3];
obj[0] = x;
obj[1] = y - 1;
obj[2] = UP;
if(this.isExistAtList(openlist, obj) == false && this.isExistAtList(closelist, obj) == false)
{
list.add(obj);
}
}
//下边
if(y < row - 1 && map[y + 1][x] != 1)
{
int[] obj = new int[3];
obj[0] = x;
obj[1] = y + 1;
obj[2] = DOWN;
if(this.isExistAtList(openlist, obj) == false && this.isExistAtList(closelist, obj) == false)
{
list.add(obj);
}
}
return list;
}
private final int LEFT = -1, RIGHT = 1, UP = -2, DOWN = 2;
/**
* 判断list中是否已有了obj位置
* @return
*/
private boolean isExistAtList(List list, int[] obj)
{
for (int i = 0; i < list.size(); i++) {
int[] listData = (int[]) list.get(i);
if(listData[0] == obj[0] && listData[1] == obj[1])
{
return true;
}
}
return false;
}
private int getDistance(int x1, int y1, int x2, int y2)
{
int a = (x1 - x2) * (x1 - x2);
int b = (y1 - y2) * (y1 - y2);
return (int) Math.sqrt(a + b);
}
public static void main(String[] args) {
JFrame frame = new JFrame("A星寻路示例");
JPanel panel = new FindPathTest();
frame.getContentPane().add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}