六边形网格A*寻路算法,JAVA实现源码

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/icemaker88/article/details/80761751

关于A*算法网上一大堆,我就不重复说明了,以下是JAVA实现的类

代码除了A*之外还有如何建立六边形网格,以及绘制六边形



图中红色是不可通过(山脉)

绿色是减速通过(森林)

灰色是加速通过(道路)

蓝色就是实际路径


修改参数结果也会有变化

具体实现看代码

核心工具类:APathfindingHex:

package gpp.util;

import java.util.ArrayList;
import java.util.List;

import gpp.object.Coordinate;

public class APathfindingHex {
	List<Coordinate> allC;
	
	public List<Coordinate> openList;
	public List<Coordinate> closeList;
	
	List<Coordinate> pathC;
	
	
	public APathfindingHex(List<Coordinate> allC){
		this.allC=new ArrayList<>();
		for (Coordinate oldC : allC) {
			Coordinate newC=new Coordinate(oldC.x, oldC.y);
			newC.isBlock=oldC.isBlock;
			newC.speed=oldC.speed;
			this.allC.add(newC);
		}
	}
	
	Coordinate findC(Coordinate inC,List<Coordinate> allC) {
		for (Coordinate coordinate : allC) {
			if (coordinate.equals(inC)) {
				return coordinate; 
			}
		}
		return null;
	}
	
	public List<Coordinate> start(Coordinate oldStartC,Coordinate oldDesC) {
		
		Coordinate startC=findC(oldStartC,allC);
		Coordinate desC=findC(oldDesC,allC);
		if (findC(startC,allC)==null||findC(desC,allC)==null) {
			System.out.println("起点或者终点有误");
			return null;
		}
		if (startC.isBlock||desC.isBlock) {
			System.out.println("起点或者终点无法通过");
			return null;
		}
		openList=new ArrayList<>();
		closeList=new ArrayList<>();
		pathC=new ArrayList<>();
		
		boolean isFind=makeOne(startC,desC);
		long count=0;
		while (isFind==false&&openList.size()>0) {
			count++;
			//System.out.println("第"+count+"次计算:");
			Coordinate minF=findMinFinOpen();
			if (minF!=null) {
				isFind=makeOne(minF,desC);
			}
		}
		System.out.println("计算量:"+count);
		return pathC;
	}
	
	
	boolean makeOne(Coordinate curC,Coordinate desC) {
		closeList.add(curC);
		openList.remove(curC);
		List<Coordinate> nearListC=curC.findNear();
		for (Coordinate coordinate : nearListC) {
			Coordinate temp=findC(coordinate,allC);
			if (temp!=null&&temp.isBlock==false&&!closeList.contains(temp)) {
				int tempG=curC.G+temp.speed;
				if (tempG<temp.G||temp.parent==null) {
					temp.parent=curC;
					temp.G=tempG;
					temp.H=calcuH(temp,desC);
					temp.F=temp.G+temp.H;
				}
				if (!openList.contains(temp)) {
					openList.add(temp);
				}
				if (temp.equals(desC)) {
					//找到目的地
					temp.addToPath(pathC);
					return true;
				}
			}
		}
		return false;
	}
	
	private Coordinate findMinFinOpen() {
		//先找最小值
		int minF=Integer.MAX_VALUE;
		for (int i = 0; i < openList.size(); i++) {
			if (openList.get(i).F<minF) {
				minF=openList.get(i).F;
			}
		}
		for (int i = 0; i < openList.size(); i++) {
			if (openList.get(i).F==minF) {
				return(openList.get(i));
			}
		}
		return null;
	}

	static int calcuH(Coordinate srcC,Coordinate desC) {
		int srcCX=srcC.x*10;
		int srcCY=-srcC.y*10;
		if (srcC.x%2!=0) {
			srcCY-=5;
		}
		int desCX=desC.x*10;
		int desCY=-desC.y*10;
		if (desC.x%2!=0) {
			desCY-=5;
		}
		double _x = Math.abs(srcCX - desCX);
		double _y = Math.abs(srcCY - desCY);
		return (int) Math.sqrt(_x*_x+_y*_y);
	}
	
}

实体类:

Coordinate:

package gpp.object;

import java.util.ArrayList;
import java.util.List;


public class Coordinate {
	public int x;
	public int y;
	public boolean isBlock;
	
	public Coordinate parent;
	public int speed;
	public int F;
	public int G;
	public int H;

	public Coordinate(int x, int y) {
		this.x = x;
		this.y = y;
		isBlock=false;
	}
	
	Coordinate findUp() {
		return new Coordinate(x, y-1);
	}
	
	Coordinate findDown() {
		return new Coordinate(x, y+1);
	}
	
	Coordinate findUpL() {
		if (x%2==0) {
			return new Coordinate(x-1, y-1);
		}else {
			return new Coordinate(x-1, y);
		}
	}
	
	Coordinate findUpR() {
		if (x%2==0) {
			return new Coordinate(x+1, y-1);
		}else {
			return new Coordinate(x+1, y);
		}
	}
	
	Coordinate findDownL() {
		if (x%2==0) {
			return new Coordinate(x-1, y);
		}else {
			return new Coordinate(x-1, y+1);
		}
	}
	
	Coordinate findDownR() {
		if (x%2==0) {
			return new Coordinate(x+1, y);
		}else {
			return new Coordinate(x+1, y+1);
		}
	}
	
	public List<Coordinate> findNear(){
		ArrayList<Coordinate> res=new ArrayList<>();
		res.add(findUp());
		res.add(findUpR());
		res.add(findDownR());
		res.add(findDown());
		res.add(findDownL());
		res.add(findUpL());
		return res;
	}
	
	@Override
	public boolean equals(Object obj) {
		Coordinate inC=(Coordinate)obj;
		if (inC.x==x&&inC.y==y) {
			return true;
		}
		return false;
	}
	
//	public int getPG() {
//		int sum=0;
//		if (parent!=null) {
//			sum=parent.G;
//		}
//		return sum;
//	}

	public void addToPath(List<Coordinate> pathC) {
		pathC.add(this);
		if (parent!=null) {
			parent.addToPath(pathC);
		}
	}

	
}

调用类SWING界面:

HexagonMapGUI:

package gpp.wuxia.world;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;

import com.alibaba.fastjson.JSON;

import gpp.object.Coordinate;
import gpp.util.APathfindingHex;
import gpp.util.RandomUtil;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class HexagonMapGUI {

	private JFrame frame;
	private JPanel canvas;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					HexagonMapGUI window = new HexagonMapGUI();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public HexagonMapGUI() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(100, 100, 800, 800);
		frame.setSize(885, 899);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);

		canvas = new Canvas();
		canvas.setBounds(30, 30, 800, 800);
		canvas.setBackground(new Color(244, 244, 244));
		frame.getContentPane().add(canvas);

		JButton btnNewButton = new JButton("刷新");
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				canvas.repaint();
			}
		});
		btnNewButton.setBounds(10, 10, 93, 23);
		frame.getContentPane().add(btnNewButton);

	}

	public class Canvas extends JPanel {
		double outR = 3;
		double innerR = outR / 2 * Math.sqrt(3);

		public Canvas() {
			// repaint();
		}

		public void paintComponent(Graphics g) {
			Graphics2D g2d = (Graphics2D) g;
			g2d.setColor(new Color(0, 0, 0));// 边线颜色

			List<Coordinate> totalC = new ArrayList<>();

			int sizeX = 150;
			int sizeY = 150;

			for (int i = 0; i < sizeX; i++) {
				for (int j = 0; j < sizeY; j++) {
					Coordinate temp = new Coordinate(i, j);
					temp.speed = 10;
					totalC.add(temp);
				}
			}

			// 画地图
			for (Coordinate coordinate : totalC) {
				drawByIndex(g2d, coordinate, new Color(255, 255, 0));
			}

			// 随机障碍物
			for (Coordinate coordinate : totalC) {
				if (RandomUtil.getFloat() < 0.2) {
					coordinate.isBlock = true;
					drawByIndex(g2d, coordinate, new Color(255, 0, 0));
				}
			}
			
			// 随机森林
			for (Coordinate coordinate : totalC) {
				if (RandomUtil.getFloat() < 0.4) {
					coordinate.speed=15;
					coordinate.isBlock=false;
					drawByIndex(g2d, coordinate, new Color(0, 255, 0));
				}
			}
			
			int rany1=RandomUtil.getIndex(sizeY);
			int rany2=RandomUtil.getIndex(sizeY);
			int rany3=RandomUtil.getIndex(sizeY);
			
			// 随机高速公路
			for (Coordinate coordinate : totalC) {
				if (coordinate.y==rany1||coordinate.x==rany1) {
					coordinate.speed=5;
					coordinate.isBlock=false;
					drawByIndex(g2d, coordinate, new Color(222, 255, 222));
				}
				
				if (coordinate.y==rany2||coordinate.x==rany2) {
					coordinate.speed=5;
					coordinate.isBlock=false;
					drawByIndex(g2d, coordinate, new Color(222, 255, 222));
				}
				
				if (coordinate.y==rany3) {
					coordinate.speed=5;
					coordinate.isBlock=false;
					drawByIndex(g2d, coordinate, new Color(222, 255, 222));
				}
			}

			System.out.println("啦啦啦,画好啦~");
			// Coordinate c=new Coordinate(14, 9);
			// drawByIndex(g2d,c,new Color(0,255,225));
			// List<Coordinate> listC=c.findNear();
			// for (Coordinate tempC : listC) {
			// drawByIndex(g2d,tempC,new Color(0,255,225));
			// }

			APathfindingHex apath = new APathfindingHex(totalC);
			List<Coordinate> path = apath.start(new Coordinate(0, 0), new Coordinate(140, 140));
			if (path != null) {
				// for (Coordinate coordinate : apath.openList) {
				// drawByIndex(g2d,coordinate,new Color(155,233,188));
				// }
//				for (Coordinate coordinate : apath.closeList) {
//					drawByIndex(g2d, coordinate, new Color(123, 70, 188));
//				}
				for (Coordinate coordinate : path) {
					drawByIndex(g2d, coordinate, new Color(100, 50, 255));
				}
			}
		}

		void drawByIndex(Graphics2D g2d, Coordinate coordinate, Color color) {
			double x = outR + coordinate.x * (outR * 1.5);
			double y = outR + coordinate.y * (innerR * 2);
			if (coordinate.x % 2 == 1) {
				y += innerR;
			}
			drawHexSolid(g2d, new Point(x, y), color);
			Font font = new Font("Courier", Font.PLAIN, (int) (outR / 2));
			g2d.setFont(font);
			g2d.drawString("(" + coordinate.x + "," + coordinate.y + ")", (int) (x - outR / 1.5), (int) (y + outR / 4));
			g2d.drawString(coordinate.F + "-" + coordinate.G + "-" + coordinate.H, (int) (x - outR / 1.5),
					(int) (y + outR / 1.5));
		}

		// 画边
		void drawHexSide(Graphics2D g2d, Point mid) {
			Point point1 = new Point(mid.x + (outR / 2), mid.y + innerR);
			Point point2 = new Point(mid.x + outR, mid.y);
			Point point3 = new Point(mid.x + (outR / 2), mid.y - innerR);
			Point point4 = new Point(mid.x - (outR / 2), mid.y - innerR);
			Point point5 = new Point(mid.x - outR, mid.y);
			Point point6 = new Point(mid.x - (outR / 2), mid.y + innerR);

			g2d.drawLine(point1.getIntX(), point1.getIntY(), point2.getIntX(), point2.getIntY());
			g2d.drawLine(point2.getIntX(), point2.getIntY(), point3.getIntX(), point3.getIntY());
			g2d.drawLine(point3.getIntX(), point3.getIntY(), point4.getIntX(), point4.getIntY());
			g2d.drawLine(point4.getIntX(), point4.getIntY(), point5.getIntX(), point5.getIntY());
			g2d.drawLine(point5.getIntX(), point5.getIntY(), point6.getIntX(), point6.getIntY());
			g2d.drawLine(point6.getIntX(), point6.getIntY(), point1.getIntX(), point1.getIntY());

		}

		// 画实心
		void drawHexSolid(Graphics2D g2d, Point mid, Color color) {
			Point point1 = new Point(mid.x + (outR / 2), mid.y + innerR);
			Point point2 = new Point(mid.x + outR, mid.y);
			Point point3 = new Point(mid.x + (outR / 2), mid.y - innerR);
			Point point4 = new Point(mid.x - (outR / 2), mid.y - innerR);
			Point point5 = new Point(mid.x - outR, mid.y);
			Point point6 = new Point(mid.x - (outR / 2), mid.y + innerR);

			GeneralPath gp = new GeneralPath(); // shape的子类,表示一个形状
			gp.append(new Line2D.Double(point1.x, point1.y, point2.x, point2.y), true); // 在形状中添加一条线,即Line2D
			gp.lineTo(point3.x, point3.y); // 添加一个点,并和之前的线段相连
			gp.lineTo(point4.x, point4.y); // 同上
			gp.lineTo(point5.x, point5.y); // 同上
			gp.lineTo(point6.x, point6.y); // 同上
			gp.closePath(); // 关闭形状创建

			Color temp = g2d.getColor();
			g2d.setColor(color);
			g2d.fill(gp);
			g2d.setColor(temp);
			g2d.draw(gp);

		}

	}

	public class Point {
		public double x;
		public double y;

		Point(double x, double y) {
			this.x = x;
			this.y = y;
		}

		public int getIntX() {
			return (int) Math.round(x);
		}

		public int getIntY() {
			return (int) Math.round(y);
		}
	}
}


展开阅读全文

没有更多推荐了,返回首页