热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

A星寻路,在Unity上用C#代码实现。

A星寻路原理:略,网上可搜到通过理解A星寻路的原理可以设计出以下流程图:流程图通过processon制作UnityC#脚本实现代码:各个坐标节点为单独的gameObject,并自带

A星寻路原理:

略,网上可搜到

通过理解A星寻路的原理可以设计出以下流程图:

流程图
流程图通过processon制作

Unity C#脚本实现代码:

各个坐标节点为单独的gameObject,并自带脚本:

using UnityEngine;
using System.Collections;

public class AStarNodeSC : MonoBehaviour {

public bool obstacle=false;
public float CostG=0;
public float CostH=0;
public float CostF
{
get
{
return this.CostG + this.CostH;
}
}

public GameObject previousNode=null;




// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {




}
}

场景控制脚本,各个成员,包括根据流程图写出的寻路方法:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class AStarNew : MonoBehaviour {

public Ray AStarRay;
public RaycastHit AStarHit;
public RaycastHit AStarHit2;

public float CostG;
public float CostH;

public GameObject AStarNode;

public GameObject start;
public static GameObject end;
public int SDflag=0;
public float timespan=0;

public static List OpenList=new List();
public static List ClostList=new List();

public static GameObject minnode;
public static List adjpoints = new List ();
public static GameObject routestart;
public static int minnodeint;

public GameObject AStarSearch(float x1,float y1,float x2,float y2,GameObject currentnode){

adjpoints.Add (new Vector3 (x1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1, y1 + 1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1 + 1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1 + 1,1f));

foreach (Vector3 temp in adjpoints) {

if (Physics.Linecast (new Vector3(temp.x,temp.y,-10), temp, out AStarHit2)) { //if the node is within the map

if (ClostList.Contains(AStarHit2.transform.gameObject)) {
continue;
}

if (AStarHit2.transform.gameObject.GetComponent ().obstacle) {
continue;
}

if (OpenList.Contains (AStarHit2.transform.gameObject)) {

this.CostG=Mathf.Abs (AStarHit2.transform.position.x - currentnode.transform.position.x) + Mathf.Abs (AStarHit2.transform.position.y - currentnode.transform.position.y);

if (this.CostG <= 1.1f&&this.CostG>=0.9f) {
this.CostG = currentnode.GetComponent ().CostG + 10f;
}

if (this.CostG<=2.1f&&this.CostG>=1.9f) {
this.CostG = currentnode.GetComponent ().CostG + 14f;
}

if (AStarHit2.transform.gameObject.GetComponent ().CostG > this.CostG) {
AStarHit2.transform.gameObject.GetComponent ().previousNode = currentnode;
AStarHit2.transform.gameObject.GetComponent ().CostG = this.CostG;
}
continue;
}


if (!OpenList.Contains (AStarHit2.transform.gameObject) && !ClostList.Contains (AStarHit2.transform.gameObject)) {

this.CostG=Mathf.Abs (AStarHit2.transform.position.x - currentnode.transform.position.x) + Mathf.Abs (AStarHit2.transform.position.y - currentnode.transform.position.y);

if (this.CostG <= 1.1f&&this.CostG>=0.9f) {
this.CostG = currentnode.GetComponent ().CostG + 10f;
}

if (this.CostG<=2.1f&&this.CostG>=1.9f) {
this.CostG = currentnode.GetComponent ().CostG + 14f;
}

AStarHit2.transform.gameObject.GetComponent ().previousNode = currentnode;
AStarHit2.transform.gameObject.GetComponent ().CostG = this.CostG;
AStarHit2.transform.gameObject.GetComponent ().CostH = Mathf.Abs (AStarHit2.transform.position.x - x2) + Mathf.Abs (AStarHit2.transform.position.y - y2);

if (AStarHit2.transform.gameObject.GetComponent ().CostH >= -0.00001&&AStarHit2.transform.gameObject.GetComponent ().CostH <= 0.00001) {
return AStarHit2.transform.gameObject;
}

OpenList.Add (AStarHit2.transform.gameObject);
AStarHit2.transform.gameObject.GetComponent().material.color=Color.yellow;
continue;
}
}

else{
continue;
}


}

adjpoints.RemoveRange (0, adjpoints.Count);

OpenList.Remove (currentnode);
ClostList.Add (currentnode);
currentnode.GetComponent ().material.color = Color.gray;

if (OpenList.Count == 0) {
return null;
}


minnode = OpenList [0];
minnodeint = 0;
for(int i=0;i
if (minnode.GetComponent ().CostF > OpenList[i].GetComponent ().CostF) {
minnode = OpenList[i];
minnodeint=i;
}
}
return OpenList [minnodeint];
}

场景控制脚本,在Start里对场景进行初始设置,以及在Update内通过鼠标设置障碍,起始点,终点并调用寻路方法:

    void Start () {

int column = 50;
int line = 50;

for(int i=0;i
for(int j=0;j
GameObject aStarNodeClOne=Instantiate(AStarNode,new Vector2(i,j),AStarNode.transform.rotation)as GameObject;
}
}

Camera.main.transform.position = new Vector3 (column/2, line/2,-15);
}

// Update is called once per frame
void Update () {

if (Input.GetMouseButton (0) && SDflag == 0){
AStarRay= Camera.main.ScreenPointToRay (Input.mousePosition);
if(Physics.Raycast (AStarRay, out AStarHit, 1000.3f)){
AStarHit.transform.gameObject.GetComponent ().material.color = Color.red;
AStarHit.transform.gameObject.GetComponent ().obstacle = true;
}
}

if (Input.GetMouseButton (1) && SDflag == 0) {
AStarRay = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (AStarRay, out AStarHit, 1000.3f)) {
print ("hit");
SDflag = 1;
start = AStarHit.transform.gameObject;
AStarHit.transform.gameObject.GetComponent ().material.color = Color.blue;
}
}

if(SDflag==1){
timespan+=Time.deltaTime;
}

if (Input.GetMouseButton (1) && SDflag == 1 && timespan > 1) {
AStarRay = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (AStarRay, out AStarHit, 1000.3f)) {
print ("hit");
timespan = 0;
SDflag = 2;
end = AStarHit.transform.gameObject;
AStarHit.transform.gameObject.GetComponent ().material.color = Color.yellow;
}
}

if (SDflag == 2) {

start.GetComponent().CostH=Mathf.Abs (start.transform.position.x-end.transform.position.x) + Mathf.Abs (start.transform.position.y-end.transform.position.y);
OpenList.Add(start);
routestart=AStarSearch(start.transform.position.x,start.transform.position.y,end.transform.position.x,end.transform.position.y,start);

for(int i=0;routestart.GetComponent().CostH>=0.1f;i++)
{
routestart=AStarSearch(routestart.transform.position.x,routestart.transform.position.y,end.transform.position.x,end.transform.position.y,routestart);
}
SDflag=3;

for(int i=0;routestart.GetComponent().previousNode!=null;i++){
routestart.transform.gameObject.GetComponent().material.color=Color.green;
routestart=routestart.GetComponent().previousNode;
}
}
}
}

结合Unity Linecast方法与A星寻路算法做出以下效果,红色点为障碍物,灰色表示在关闭列表内,黄色在开放列表内,绿色为最捷路径:

这里写图片描述
这里写图片描述


除了利用for循环调用寻路方法,也可以将此方法改为递归,但是在节点数过多时会出现堆栈溢出异常:

    public GameObject AStarSearch(float x1,float y1,float x2,float y2,GameObject currentnode){

adjpoints.Add (new Vector3 (x1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1, y1 + 1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1,1f));
adjpoints.Add (new Vector3 (x1 + 1, y1 + 1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1 - 1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1,1f));
adjpoints.Add (new Vector3 (x1 - 1, y1 + 1,1f));

foreach (Vector3 temp in adjpoints) {

if(!Physics.Linecast (new Vector3(temp.x,temp.y,-10), temp, out AStarHit2)){
continue;
}

if (Physics.Linecast (new Vector3(temp.x,temp.y,-10), temp, out AStarHit2)) { //if the node is within the map

if (ClostList.Contains(AStarHit2.transform.gameObject)) {
continue;
}

if (AStarHit2.transform.gameObject.GetComponent ().obstacle) {
continue;
}

if (OpenList.Contains (AStarHit2.transform.gameObject)) {

this.CostG=Mathf.Abs (AStarHit2.transform.position.x - currentnode.transform.position.x) + Mathf.Abs (AStarHit2.transform.position.y - currentnode.transform.position.y);

if (this.CostG <= 1.1f&&this.CostG>=0.9f) {
this.CostG = currentnode.GetComponent ().CostG + 10f;
}

if (this.CostG<=2.1f&&this.CostG>=1.9f) {
this.CostG = currentnode.GetComponent ().CostG + 14f;
}

if (AStarHit2.transform.gameObject.GetComponent ().CostG > this.CostG) {
AStarHit2.transform.gameObject.GetComponent ().previousNode = currentnode;
AStarHit2.transform.gameObject.GetComponent ().CostG = this.CostG;
}
continue;
}


if (!OpenList.Contains (AStarHit2.transform.gameObject) && !ClostList.Contains (AStarHit2.transform.gameObject)) {

this.CostG=Mathf.Abs (AStarHit2.transform.position.x - currentnode.transform.position.x) + Mathf.Abs (AStarHit2.transform.position.y - currentnode.transform.position.y);

if (this.CostG <= 1.1f&&this.CostG>=0.9f) {
this.CostG = currentnode.GetComponent ().CostG + 10f;
}

if (this.CostG<=2.1f&&this.CostG>=1.9f) {
this.CostG = currentnode.GetComponent ().CostG + 14f;
}

AStarHit2.transform.gameObject.GetComponent ().previousNode = currentnode;
AStarHit2.transform.gameObject.GetComponent ().CostG = this.CostG;
AStarHit2.transform.gameObject.GetComponent ().CostH = Mathf.Abs (AStarHit2.transform.position.x - x2) + Mathf.Abs (AStarHit2.transform.position.y - y2);

if (AStarHit2.transform.gameObject.GetComponent ().CostH >= -0.00001&&AStarHit2.transform.gameObject.GetComponent ().CostH <= 0.00001) {
return AStarHit2.transform.gameObject;
}


OpenList.Add (AStarHit2.transform.gameObject);
continue;
}
}
}

adjpoints.RemoveRange (0, adjpoints.Count);

OpenList.Remove (currentnode);
ClostList.Add (currentnode);

if (OpenList.Count == 0) {
return null;
}


minnode = OpenList [0]; //not sure
minnodeint = 0;
for(int i=0;i
if (minnode.GetComponent ().CostF > OpenList[i].GetComponent ().CostF) {
minnode = OpenList[i];
minnodeint=i;
}
}
return AStarSearch (OpenList[minnodeint].transform.position.x, OpenList[minnodeint].transform.position.y, end.transform.position.x, end.transform.position.y, OpenList[minnodeint]);
}

另外,以上代码虽然实现了A星寻路的思想但是不够优化,在节点数超过10000时搜寻速度不甚理想,因此只为展示思路。


推荐阅读
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • 探索偶数次幂二项式系数的求和方法及其数学意义 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • QT框架中事件循环机制及事件分发类详解
    在QT框架中,QCoreApplication类作为事件循环的核心组件,为应用程序提供了基础的事件处理机制。该类继承自QObject,负责管理和调度各种事件,确保程序能够响应用户操作和其他系统事件。通过事件循环,QCoreApplication实现了高效的事件分发和处理,使得应用程序能够保持流畅的运行状态。此外,QCoreApplication还提供了多种方法和信号槽机制,方便开发者进行事件的定制和扩展。 ... [详细]
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
  • 深入理解 Java 控制结构的全面指南 ... [详细]
  • 数组容量的动态调整与优化策略
    在探讨数组容量动态调整与优化策略时,本文分析了两种常见的方法。首先,通过使用for循环逐个复制元素实现扩容,但这种方法存在计算索引的复杂性问题。其次,利用System.arraycopy()方法进行高效复制,显著提升了性能和代码可读性。此外,文章还讨论了动态数组在不同应用场景下的优化策略,包括预分配容量和按需扩展等技术,以提高程序的整体效率。 ... [详细]
  • 题目要求将数字字符串转换为对应的字母组合,例如“111”可以转化为“AAA”、“KA”或“AK”。本文通过深入解析暴力递归方法,详细探讨了这一问题的解法,并结合真实的 Facebook 面试题目,提供了从左至右尝试模型的具体实现和优化策略。 ... [详细]
  • 探索聚类分析中的K-Means与DBSCAN算法及其应用
    聚类分析是一种用于解决样本或特征分类问题的统计分析方法,也是数据挖掘领域的重要算法之一。本文主要探讨了K-Means和DBSCAN两种聚类算法的原理及其应用场景。K-Means算法通过迭代优化簇中心来实现数据点的划分,适用于球形分布的数据集;而DBSCAN算法则基于密度进行聚类,能够有效识别任意形状的簇,并且对噪声数据具有较好的鲁棒性。通过对这两种算法的对比分析,本文旨在为实际应用中选择合适的聚类方法提供参考。 ... [详细]
  • Java 模式原型在游戏服务器架构中的应用与优化 ... [详细]
  • 深入解析C#中app.config文件的配置与修改方法
    在C#开发过程中,经常需要对系统的配置文件进行读写操作,如系统初始化参数的修改或运行时参数的更新。本文将详细介绍如何在C#中正确配置和修改app.config文件,包括其结构、常见用法以及最佳实践。此外,还将探讨exe.config文件的生成机制及其在不同环境下的应用,帮助开发者更好地管理和维护应用程序的配置信息。 ... [详细]
  • 作为软件工程专业的学生,我深知课堂上教师讲解速度之快,很多时候需要课后自行消化和巩固。因此,撰写这篇Java Web开发入门教程,旨在帮助初学者更好地理解和掌握基础知识。通过详细记录学习过程,希望能为更多像我一样在基础方面还有待提升的学员提供有益的参考。 ... [详细]
  • 本文详细介绍了在C#编程环境中绘制正方形图像的技术和实现方法,通过具体示例代码帮助读者理解和掌握相关技巧。内容涵盖从基础概念到实际应用的各个方面,适合初学者和有一定经验的开发者参考。希望对您的C#学习之旅有所帮助,并激发您进一步探索的兴趣。 ... [详细]
  • 通过使用CIFAR-10数据集,本文详细介绍了如何快速掌握Mixup数据增强技术,并展示了该方法在图像分类任务中的显著效果。实验结果表明,Mixup能够有效提高模型的泛化能力和分类精度,为图像识别领域的研究提供了有价值的参考。 ... [详细]
author-avatar
luhd88112010_254
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有