1.unity3d Astar pathfinding 第一个例子
2017-10-18 22:50
176 查看
1. 场景准备
先建立一个scene添加一个plane,让其坐标处于(0,0,0),并三方向scale都为10
添加一个新的layer,命名为Ground,并将上面建立的plane设置为Ground层
在plane上添加若干个box作为障碍物,添加一个新的layer,命名为Obstacles, 将这些box都归为这个Obstacles层
2.创建一个空的GameObject,命名为A*.
3.从Components–>Pathfinding–>Pathfinder中添加插件脚本AstarPath。可以再AstarPath的观察器中看到它被分为几个部分,其中最重要的区域是Graphs区域和底部的Scan区域,Graphs区域保存了工程中所有的寻路图,最多可以有16个,但是一般1到2个已经足够了。有几类寻路图,其中最主要的有两种:Grid
Pattern Graph和Navmesh Graph.
这次就先添加Grid graph.
就如名字所述一样,Grid graph会产生一系列的网格,大小为width * height,这个网格可以放在场景中的任何地方,也可以进行旋转。节点尺寸设置了节点所占空间的大小,在这里设置为1;右侧有一个5个点组成的小选取控制,选择左下角的那个点,将其坐标设置为(-50, 0.1, -50), 其中y方向设置为0.1是为了避免产生浮点错误,因为地面plane的y向坐标是0,如果导航网格也是y向为0的话,在进行高度检测的raycast的时候,会产生问题。
高度测试:
为了把寻路的node放置到场景中的正确位置,一般使用从node向下发射一个射线来进行检测,寻路node会被放置到碰撞点的位置。我们将mask设置为Ground,因为只希望寻路节点与Ground进行检测。
碰撞测试:
当寻路节点被放置之后,它就会被用来检测是否可行走,一般可以使用sphere,capsule或ray来进行碰撞检测。一般Capsule会使用和AI对象一样的半径和高度来进行碰撞。为了让AI对象和障碍物有一些边缘,这里将Capsule的半径设置为2.另外将碰撞检测的layer设置为Obstacles,因为不想让地面成为障碍。
好了,都准备好了,点击底部的Scan,我们就可以看到grid Graph的生成了,可以再编辑窗口中看到辅助线显示的寻路网格,包括了可寻路的区域和障碍区域。
4. 加入AI
以上是对场景寻路相关的基础设置,接下来要加入AI对象进行寻路。在场景里面添加一个Capsule,并给其添加一个Character Controller组件,从Components–>Pathfinding中添加Seeker脚本。Seeker脚本是一个帮助类的脚本,用来将其他脚本的寻路请求进行处理,它也可以处理Path
modifier(一般是对寻路结果进行圆滑处理的脚本)。A* pathfinding project自带了两个AI脚本用于挂接到对象上进行寻路:AIPah可适用于任何类型的寻路图;而RichAI只适用于NavMesh类型。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
public class AStarPlayer: MonoBehaviour {
//目标位置;
Vector3 targetPosition;
Seeker seeker;
CharacterController characterController;
//计算出来的路线;
Path path;
//移动速度;
float playerMoveSpeed = 20f;
//当前点
int currentWayPoint = 0;
bool stopMove = true;
//Player中心点;
float playerCenterY = 1.0f;
// Use this for initialization
void Start ()
{
//seeker = GetComponent<Seeker>();
//characterController = GetComponent<CharacterController> ();
//playerCenterY = transform.localPosition.y;
}
void Awake()
{
seeker = GetComponent<Seeker>();
characterController = GetComponent<CharacterController> ();
playerCenterY = transform.localPosition.y;
}
//寻路结束;
public void OnPathComplete(Path p)
{
Debug.Log("OnPathComplete error = "+p.error);
if (!p.error)
{
currentWayPoint = 0;
path = p;
stopMove = false;
}
for (int index = 0; index < path.vectorPath.Count; index++)
{
Debug.Log("path.vectorPath["+index+"]="+path.vectorPath[index]);
}
}
// Update is called once per frame
void Update ()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
if (!Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 100))
{
return;
}
if (!hit.transform)
{
return;
}
targetPosition = hit.point;// new Vector3(hit.point.x, transform.localPosition.y, hit.point.z);
Debug.Log("targetPosition=" + targetPosition);
seeker.StartPath(transform.position, targetPosition,OnPathComplete);
}
}
int i=0;
void FixedUpdate()
{
if (path == null || stopMove)
{
return;
}
i++;
Debug.Log ("i="+i);
//根据Player当前位置和 下一个寻路点的位置,计算方向;
Vector3 currentWayPointV = new Vector3(path.vectorPath[currentWayPoint].x, path.vectorPath[currentWayPoint].y + playerCenterY, path.vectorPath[currentWayPoint].z);
//Vector3 currentWayPointV =path.vectorPath[currentWayPoint];
Vector3 dir = (currentWayPointV - transform.position).normalized;
//Debug.Log ("dir1="+dir);
//dir = dir.normalized;
//Debug.Log ("dir2="+dir);
//计算这一帧要朝着 dir方向 移动多少距离;
dir *= playerMoveSpeed * Time.fixedDeltaTime;
//Debug.Log ("dir3="+dir);
//dir *= playerMoveSpeed;
//计算加上这一帧的位移,是不是会超过下一个节点;
//float offset = Vector3.Distance(transform.position, currentWayPointV);
float offset = Vector3.Distance(currentWayPointV,transform.position);
if (offset < 0.1f)
{
Debug.Log ("----------------------------------------------------------------------");
transform.localPosition = currentWayPointV;
currentWayPoint++;
if (currentWayPoint == path.vectorPath.Count)
{
stopMove = true;
currentWayPoint = 0;
path = null;
}
}
else
{
Debug.Log ("dir.magnitude="+dir.magnitude + " " +"offset="+offset );
if (dir.magnitude > offset) // length
{
//Vector3 tmpV3 = dir * (offset / dir.magnitude);
//dir = tmpV3;
currentWayPoint++;
if (currentWayPoint == path.vectorPath.Count)
{
stopMove = true;
currentWayPoint = 0;
path = null;
}
}
transform.localPosition += dir;
//characterController.SimpleMove (dir);
}
}
}
先建立一个scene添加一个plane,让其坐标处于(0,0,0),并三方向scale都为10
添加一个新的layer,命名为Ground,并将上面建立的plane设置为Ground层
在plane上添加若干个box作为障碍物,添加一个新的layer,命名为Obstacles, 将这些box都归为这个Obstacles层
2.创建一个空的GameObject,命名为A*.
3.从Components–>Pathfinding–>Pathfinder中添加插件脚本AstarPath。可以再AstarPath的观察器中看到它被分为几个部分,其中最重要的区域是Graphs区域和底部的Scan区域,Graphs区域保存了工程中所有的寻路图,最多可以有16个,但是一般1到2个已经足够了。有几类寻路图,其中最主要的有两种:Grid
Pattern Graph和Navmesh Graph.
这次就先添加Grid graph.
就如名字所述一样,Grid graph会产生一系列的网格,大小为width * height,这个网格可以放在场景中的任何地方,也可以进行旋转。节点尺寸设置了节点所占空间的大小,在这里设置为1;右侧有一个5个点组成的小选取控制,选择左下角的那个点,将其坐标设置为(-50, 0.1, -50), 其中y方向设置为0.1是为了避免产生浮点错误,因为地面plane的y向坐标是0,如果导航网格也是y向为0的话,在进行高度检测的raycast的时候,会产生问题。
高度测试:
为了把寻路的node放置到场景中的正确位置,一般使用从node向下发射一个射线来进行检测,寻路node会被放置到碰撞点的位置。我们将mask设置为Ground,因为只希望寻路节点与Ground进行检测。
碰撞测试:
当寻路节点被放置之后,它就会被用来检测是否可行走,一般可以使用sphere,capsule或ray来进行碰撞检测。一般Capsule会使用和AI对象一样的半径和高度来进行碰撞。为了让AI对象和障碍物有一些边缘,这里将Capsule的半径设置为2.另外将碰撞检测的layer设置为Obstacles,因为不想让地面成为障碍。
好了,都准备好了,点击底部的Scan,我们就可以看到grid Graph的生成了,可以再编辑窗口中看到辅助线显示的寻路网格,包括了可寻路的区域和障碍区域。
4. 加入AI
以上是对场景寻路相关的基础设置,接下来要加入AI对象进行寻路。在场景里面添加一个Capsule,并给其添加一个Character Controller组件,从Components–>Pathfinding中添加Seeker脚本。Seeker脚本是一个帮助类的脚本,用来将其他脚本的寻路请求进行处理,它也可以处理Path
modifier(一般是对寻路结果进行圆滑处理的脚本)。A* pathfinding project自带了两个AI脚本用于挂接到对象上进行寻路:AIPah可适用于任何类型的寻路图;而RichAI只适用于NavMesh类型。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
public class AStarPlayer: MonoBehaviour {
//目标位置;
Vector3 targetPosition;
Seeker seeker;
CharacterController characterController;
//计算出来的路线;
Path path;
//移动速度;
float playerMoveSpeed = 20f;
//当前点
int currentWayPoint = 0;
bool stopMove = true;
//Player中心点;
float playerCenterY = 1.0f;
// Use this for initialization
void Start ()
{
//seeker = GetComponent<Seeker>();
//characterController = GetComponent<CharacterController> ();
//playerCenterY = transform.localPosition.y;
}
void Awake()
{
seeker = GetComponent<Seeker>();
characterController = GetComponent<CharacterController> ();
playerCenterY = transform.localPosition.y;
}
//寻路结束;
public void OnPathComplete(Path p)
{
Debug.Log("OnPathComplete error = "+p.error);
if (!p.error)
{
currentWayPoint = 0;
path = p;
stopMove = false;
}
for (int index = 0; index < path.vectorPath.Count; index++)
{
Debug.Log("path.vectorPath["+index+"]="+path.vectorPath[index]);
}
}
// Update is called once per frame
void Update ()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
if (!Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 100))
{
return;
}
if (!hit.transform)
{
return;
}
targetPosition = hit.point;// new Vector3(hit.point.x, transform.localPosition.y, hit.point.z);
Debug.Log("targetPosition=" + targetPosition);
seeker.StartPath(transform.position, targetPosition,OnPathComplete);
}
}
int i=0;
void FixedUpdate()
{
if (path == null || stopMove)
{
return;
}
i++;
Debug.Log ("i="+i);
//根据Player当前位置和 下一个寻路点的位置,计算方向;
Vector3 currentWayPointV = new Vector3(path.vectorPath[currentWayPoint].x, path.vectorPath[currentWayPoint].y + playerCenterY, path.vectorPath[currentWayPoint].z);
//Vector3 currentWayPointV =path.vectorPath[currentWayPoint];
Vector3 dir = (currentWayPointV - transform.position).normalized;
//Debug.Log ("dir1="+dir);
//dir = dir.normalized;
//Debug.Log ("dir2="+dir);
//计算这一帧要朝着 dir方向 移动多少距离;
dir *= playerMoveSpeed * Time.fixedDeltaTime;
//Debug.Log ("dir3="+dir);
//dir *= playerMoveSpeed;
//计算加上这一帧的位移,是不是会超过下一个节点;
//float offset = Vector3.Distance(transform.position, currentWayPointV);
float offset = Vector3.Distance(currentWayPointV,transform.position);
if (offset < 0.1f)
{
Debug.Log ("----------------------------------------------------------------------");
transform.localPosition = currentWayPointV;
currentWayPoint++;
if (currentWayPoint == path.vectorPath.Count)
{
stopMove = true;
currentWayPoint = 0;
path = null;
}
}
else
{
Debug.Log ("dir.magnitude="+dir.magnitude + " " +"offset="+offset );
if (dir.magnitude > offset) // length
{
//Vector3 tmpV3 = dir * (offset / dir.magnitude);
//dir = tmpV3;
currentWayPoint++;
if (currentWayPoint == path.vectorPath.Count)
{
stopMove = true;
currentWayPoint = 0;
path = null;
}
}
transform.localPosition += dir;
//characterController.SimpleMove (dir);
}
}
}
相关文章推荐
- A star pathfinding project插件点到点寻路
- A Star Pathfinding for Beginners
- [转]A-Star (A*) Implementation in C# (Path Finding, PathFinder)
- NetLogo A-Star path finding
- pdf转txt第一个小例子(PDFBOX)
- Linux设备驱动的第一个例子:Hello World
- mxnet系列教程之1-第一个例子
- Hibernate第一个例子
- Caffe第一个例子
- 【RocketMQ源码深度解析】整体介绍&IDE编译并启动RocketMQ的第一个例子
- highcharts学习之第一个例子
- 第一个例子:求解泊松方程
- 启发式搜索和A*算法(Heuristics and A* Pathfinding)
- 第一个文件读写的例子
- tensorflow 学习第一个例子
- 我的Firefox插件开发之旅(5)——编译和测试第一个Plugin例子:npruntime
- MyEclipse下的第一个Struts例子
- 问题:为什么opengl超级宝典第一个例子都编译不成功?
- windows下erlang环境搭建和创建第一个简单例子
- Unity3d IOS 64 IL2CPP迁移之 AStarPath JosnFX 错误