Files
tianrunCRM/Assets/CoolapeFrame/AIPath/Scripts/CLSeeker.cs
2020-07-04 14:41:25 +08:00

407 lines
14 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Coolape
{
public class CLSeeker : MonoBehaviour
{
public CLAStarPathSearch mAStarPathSearch;
public Transform target;
public Vector3 targetPos;
//移动速度
public float speed = 1;
//转向速度(当为负=硬转向)
public float turningSpeed = 5;
//离目标多远就停止移动
public float endReachedDistance = 0.2f;
public bool canSearchPath = true;
public bool canMove = false;
public bool autoMoveOnFinishSeek = true;
public MovingBy movingBy = MovingBy.Update;
public bool unscaledTime = false;
public bool showPath = true;
[System.NonSerialized]
public List<Vector3> pathList = new List<Vector3>();
public object onFinishSeekCallback;
public object onMovingCallback;
public object onArrivedCallback;
[HideInInspector]
public bool isSeekTargetLoop = false;
public float seekTargetLoopIntvalSec = 1;
public float nextSeekTargetTime = 0;
Transform _mTransform;
public Transform mTransform
{
get
{
if (_mTransform == null)
{
_mTransform = gameObject.transform;
}
return _mTransform;
}
}
// Use this for initialization
public virtual void Start()
{
if (mAStarPathSearch == null)
{
mAStarPathSearch = CLAStarPathSearch.current;
}
}
public virtual float cellSize
{
get
{
return mAStarPathSearch.cellSize;
}
}
/// <summary>
/// Init the specified onFinishSeekCallback, onMovingCallback and onArrivedCallback.
/// </summary>
/// <param name="onFinishSeekCallback">On finish seek callback.完成寻路后的回(其实是同步模式)</param>
/// <param name="onMovingCallback">On moving callback.移动时的回调</param>
/// <param name="onArrivedCallback">On arrived callback.到达目的地的回调</param>
public virtual void init(object onFinishSeekCallback, object onMovingCallback, object onArrivedCallback)
{
this.onFinishSeekCallback = onFinishSeekCallback;
this.onMovingCallback = onMovingCallback;
this.onArrivedCallback = onArrivedCallback;
}
public virtual List<Vector3> seekTarget(Transform target)
{
return seekTarget(target, 1);
}
/// <summary>
/// Seeks the target.寻找目标对
/// </summary>
/// <returns>The target.</returns>
/// <param name="target">Target.目标对象</param>
/// <param name="searchIntvalSec">Search intval sec.每隔xx秒重新寻路</param>
public virtual List<Vector3> seekTarget(Transform target, float searchIntvalSec)
{
if (target == null) return null;
this.target = target;
canSearchPath = true;
//fixedInvoke((Callback)seekTargetLoop, searchIntvalSec, searchIntvalSec);
seekTargetLoopIntvalSec = searchIntvalSec;
isSeekTargetLoop = true;
nextSeekTargetTime = Time.realtimeSinceStartup + seekTargetLoopIntvalSec;
return seek(target.position);
}
/// <summary>
/// Cancels the seek target.取消对目标的寻路
/// </summary>
public virtual void cancelSeekTarget()
{
isSeekTargetLoop = false;
//cancelFixedInvoke4Lua((Callback)seekTargetLoop);
}
void seekTargetLoop()
{
if (!canSearchPath || target == null)
{
return;
}
//float searchIntvalSec = (float)(objs[0]);
seek(target.position);
nextSeekTargetTime = Time.realtimeSinceStartup + seekTargetLoopIntvalSec;
//fixedInvoke((Callback)seekTargetLoop, searchIntvalSec, searchIntvalSec);
}
public virtual void seekAsyn(Vector3 toPos)
{
targetPos = toPos;
canMove = false;
stopMove();
//pathList.Clear();
mAStarPathSearch.searchPathAsyn(mTransform.position, toPos, (Callback)onSeekAsynCallback);
}
void onSeekAsynCallback(params object[] objs)
{
bool canReach = (bool)(objs[0]);
pathList = objs[1] as List<Vector3>;
//回调的第一个参数是路径,第二个参数是能否到达目标点
Utl.doCallback(onFinishSeekCallback, pathList, canReach);
if (autoMoveOnFinishSeek)
{
//开始移动
startMove();
}
}
public virtual List<Vector3> seek(Vector3 toPos, float endReachDis)
{
endReachedDistance = endReachDis;
return seek(toPos);
}
/// <summary>
/// Seek the specified toPos.寻路
/// </summary>
/// <returns>The seek.路径列表</returns>
/// <param name="toPos">To position.</param>
public virtual List<Vector3> seek(Vector3 toPos)
{
targetPos = toPos;
canMove = false;
stopMove();
pathList.Clear();
bool canReach = mAStarPathSearch.searchPath(mTransform.position, toPos, ref pathList);
//回调的第一个参数是路径,第二个参数是能否到达目标点
Utl.doCallback(onFinishSeekCallback, pathList, canReach);
if (autoMoveOnFinishSeek)
{
//开始移动
startMove();
}
return pathList;
}
// Update is called once per frame
public virtual void Update()
{
if(isSeekTargetLoop) {
if(Time.realtimeSinceStartup >= nextSeekTargetTime) {
seekTargetLoop();
}
}
if (canMove && movingBy == MovingBy.Update)
{
if (unscaledTime)
{
moving(Time.unscaledDeltaTime);
}
else
{
moving(Time.deltaTime);
}
}
}
public virtual void FixedUpdate()
{
if (canMove && movingBy == MovingBy.FixedUpdate)
{
if (unscaledTime)
{
moving(Time.fixedUnscaledDeltaTime);
}
else
{
moving(Time.fixedDeltaTime);
}
}
}
int nextPahtIndex = 0;
float movePersent = 0;
bool finishOneSubPath = false;
float offsetSpeed = 0;
Vector3 diff4Moving = Vector3.zero;
Vector3 fromPos4Moving = Vector3.zero;
/// <summary>
/// Begains the move.
/// </summary>
public virtual void startMove()
{
canMove = false;
if (pathList == null || pathList.Count < 2)
{
if (pathList == null)
{
Debug.LogError("pathList == null!");
}
Debug.LogError("Path list error!");
stopMove();
Utl.doCallback(onArrivedCallback);
return;
}
if (Vector3.Distance(mTransform.position, pathList[0]) < 0.001f)
{
//说明是在原点
movePersent = 0;
finishOneSubPath = false;
fromPos4Moving = pathList[0];
diff4Moving = pathList[1] - pathList[0];
offsetSpeed = 1.0f / Vector3.Distance(pathList[0], pathList[1]);
nextPahtIndex = 1;
rotateTowards(diff4Moving, true);
canMove = true;
}
else if (Vector3.Distance(mTransform.position, pathList[pathList.Count - 1]) <= endReachedDistance)
{
//到达目标点
Utl.doCallback(onArrivedCallback);
return;
}
else
{
float dis = 0;
float dis1 = 0;
float dis2 = 0;
for (int i = 1; i < pathList.Count; i++)
{
dis = Vector3.Distance(pathList[i - 1], pathList[i]);
dis1 = Vector3.Distance(mTransform.position, pathList[i - 1]);
dis2 = Vector3.Distance(mTransform.position, pathList[i]);
if (Mathf.Abs(dis - (dis1 + dis2)) < 0.01f)
{
movePersent = dis1 / dis;
finishOneSubPath = false;
nextPahtIndex = i;
fromPos4Moving = pathList[i - 1];
diff4Moving = pathList[i] - pathList[i - 1];
offsetSpeed = 1.0f / Vector3.Distance(pathList[i - 1], pathList[i]);
rotateTowards(diff4Moving, true);
canMove = true;
break;
}
}
if(!canMove)
{
Debug.LogWarning("说明没有找到起点,但是还是强制设置成可以移动");
canMove = true;
}
}
}
public virtual void stopMove()
{
canMove = false;
}
/// <summary>
/// Moving the specified deltaTime.处理移动
/// </summary>
/// <param name="deltaTime">Delta time.会根据不同的情况传入</param>
protected void moving(float deltaTime)
{
if (pathList == null || nextPahtIndex >= pathList.Count)
{
Debug.LogError("moving error");
if (pathList == null)
{
Debug.LogError("pathList == null!");
}
stopMove();
Utl.doCallback(onArrivedCallback);
return;
}
movePersent += (deltaTime * speed * 0.3f * offsetSpeed);
if (movePersent >= 1)
{
movePersent = 1;
finishOneSubPath = true;
}
if (turningSpeed > 0)
{
rotateTowards(diff4Moving, false);
}
mTransform.position = fromPos4Moving + diff4Moving * movePersent;
Utl.doCallback(onMovingCallback);
if (nextPahtIndex == pathList.Count - 1)
{
//最后一段路径,即将要到达目的地
if (finishOneSubPath ||
Vector3.Distance(mTransform.position, pathList[pathList.Count - 1]) <= endReachedDistance)
{
stopMove();
Utl.doCallback(onArrivedCallback);
}
}
else
{
if (finishOneSubPath)
{
//移动完成一段路径,进入下一段路径的准备(一些变量的初始化)
nextPahtIndex++;
movePersent = 0;
finishOneSubPath = false;
fromPos4Moving = pathList[nextPahtIndex - 1];
diff4Moving = pathList[nextPahtIndex] - pathList[nextPahtIndex - 1];
offsetSpeed = 1.0f / Vector3.Distance(pathList[nextPahtIndex - 1], pathList[nextPahtIndex]);
if (turningSpeed <= 0)
{
rotateTowards(diff4Moving, true);
}
}
}
}
/// <summary>
/// Rotates the towards.转向
/// </summary>
/// <param name="dir">Dir.方向</param>
/// <param name="immediately">If set to <c>true</c> immediately.立即转向,否则为慢慢转</param>
protected void rotateTowards(Vector3 dir, bool immediately)
{
if (dir == Vector3.zero) return;
Quaternion rot = mTransform.rotation;
Quaternion toTarget = Quaternion.LookRotation(dir);
if (immediately)
{
rot = toTarget;
}
else
{
rot = Quaternion.Slerp(rot, toTarget, turningSpeed * Time.deltaTime);
}
Vector3 euler = rot.eulerAngles;
euler.z = 0;
euler.x = 0;
rot = Quaternion.Euler(euler);
mTransform.rotation = rot;
}
//====================================================================
//====================================================================
#if UNITY_EDITOR
void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
Gizmos.DrawSphere(targetPos, 0.5f);
Gizmos.color = Color.white;
if (showPath && pathList != null && pathList.Count > 0)
{
for (int i = 0; i < pathList.Count - 1; i++)
{
Debug.DrawLine(pathList[i], pathList[i + 1], Color.green);
}
}
}
#endif
//====================================================================
//====================================================================
public enum MovingBy
{
Update,
FixedUpdate
}
}
}