移动组件:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MoveComponent : MonoBehaviour
{
#region 字段
public float maxSpeed = 10; // 最大速度
public float maxForce = 100; // 最大推力
public float mass = 1; // 对象质量
public Vector3 velocity; // 速度向量
public float damping = 0.9f; // 旋转速率
public float computeInteval = 0.2f; // 计算间隔
public float completeDisatnce = 3f; // 到达距离
private Vector3 acceleration; // 加速度
private float timer = 0; // 计时器
private Vector3 steeringForce = Vector3.zero; // 推力
private Dictionary<MoveType, MoveBase> moveDic = new Dictionary<MoveType, MoveBase>(); // 移动字典
public List<MoveType> arriveRemove = new List<MoveType>(); // 移动完成需要删除的移动
#endregion
void Awake()
{
moveDic[MoveType.Seek] = null;
moveDic[MoveType.Arrive] = null;
moveDic[MoveType.Flee] = null;
moveDic[MoveType.FollowPath] = null;
moveDic[MoveType.Pursuit] = null;
moveDic[MoveType.CollisionAvoidance] = null;
}
void Update()
{
timer += Time.deltaTime;
if(timer > computeInteval)
{
//得到当前帧的推力
steeringForce = Vector3.zero;
//遍历当前激活的移动并添加推力*权重
foreach(var v in moveDic)
{
if(v.Value != null)
{
steeringForce += v.Value.Force() * v.Value.Weight;
}
}
//移除完成的移动
foreach (var v in arriveRemove)
{
moveDic[v] = null;
}
arriveRemove.Clear();
//限制最大力
steeringForce = Vector3.ClampMagnitude(steeringForce, maxForce);
//加速度=推力/质量
acceleration = steeringForce / mass;
timer = 0;
}
}
void FixedUpdate()
{
//增加加速度
velocity += acceleration * Time.fixedDeltaTime;
//控制最大速度
if (velocity.sqrMagnitude > maxSpeed * maxSpeed)
velocity = velocity.normalized * maxSpeed;
//移动
transform.position += velocity * Time.fixedDeltaTime;
//插值旋转
if(velocity.sqrMagnitude > 0.01f)
{
//计算当前前方到目标方向的插值
Vector3 newForward = Vector3.Slerp(transform.forward, velocity, damping * Time.fixedDeltaTime);
transform.forward = newForward;
}
}
#region 接口
public void SeekTo(Transform target)
{
if(moveDic[MoveType.Seek] != null)
{
if ((moveDic[MoveType.Seek] as MoveSeek).target == target)
return;
}
moveDic[MoveType.Seek] = new MoveSeek(this, target);
}
public void ArriveTo(Transform target, float slowDistance)
{
if (moveDic[MoveType.Arrive] != null)
{
if ((moveDic[MoveType.Arrive] as MoveArrive).target == target)
return;
}
moveDic[MoveType.Arrive] = new MoveArrive(this, target, slowDistance);
}
public void FleeTo(Transform target,float fearDistance)
{
if (moveDic[MoveType.Flee] != null)
{
if ((moveDic[MoveType.Flee] as MoveFlee).target == target)
return;
}
moveDic[MoveType.Flee] = new MoveFlee(this, target, fearDistance);
}
public void PursuitTo(Transform target)
{
if(moveDic[MoveType.Pursuit] != null)
{
if ((moveDic[MoveType.Pursuit] as MovePursuit).target == target)
return;
}
moveDic[MoveType.Pursuit] = new MovePursuit(this, target);
}
public void FollowPath(List<Transform> path)
{
if(moveDic[MoveType.FollowPath] != null)
{
if ((moveDic[MoveType.FollowPath] as MoveFllowPath).path == path)
return;
}
moveDic[MoveType.FollowPath] = new MoveFllowPath(this, path);
}
public void OpenCollisionAvoidance(float seeAheadDistance)
{
moveDic[MoveType.CollisionAvoidance] = new MoveCollisionAvoidance(this, seeAheadDistance);
}
#endregion
}
public enum MoveType
{
Seek,
Arrive,
Flee,
Pursuit,
FollowPath,
CollisionAvoidance
}
移动方式基类:
using UnityEngine;
using System.Collections;
public class MoveBase {
public float Weight = 1; //移动优先级
protected Vector3 disiredVelocity; //目标速度
protected MoveComponent move; //移动脚本
public MoveBase(MoveComponent move)
{
this.move = move;
}
public virtual Vector3 Force()
{
return Vector3.zero;
}
}
靠近:
using UnityEngine;
using System.Collections;
public class MoveSeek : MoveBase {
public Transform target;
public MoveSeek(MoveComponent move, Transform target) : base(move) { this.target = target; }
public override Vector3 Force()
{
//完成目标移除
if (Vector3.Distance(target.transform.position, move.transform.position) < move.completeDisatnce)
{
move.arriveRemove.Add(MoveType.Seek);
move.velocity = Vector3.zero;
return Vector3.zero;
}
//要到达的速度
disiredVelocity = (target.transform.position - move.transform.position).normalized * move.maxSpeed;
//加速度:当速度=要到达的速度,加速度为0
return disiredVelocity - move.velocity;
}
}
缓速到达:
using UnityEngine;
using System.Collections;
public class MoveArrive : MoveBase {
public Transform target;
//减速范围
float slowDistance;
public MoveArrive(MoveComponent move, Transform target, float slowDistance) : base(move) { this.target = target; this.slowDistance = slowDistance; }
public override Vector3 Force()
{
if (Vector3.Distance(target.transform.position, move.transform.position) > move.completeDisatnce)
{
Vector3 toTarget = target.transform.position - move.transform.position;
Vector3 returnForce;
float distance = toTarget.magnitude;
if (distance > slowDistance)
{
//目标速度
disiredVelocity = toTarget * move.maxSpeed;
//加速度:当速度=要到达的速度,加速度为0
returnForce = disiredVelocity - move.velocity;
}
else
{
//当进入减速范围时 目标速度 = 长度向量-速度向量 逐渐缩小
disiredVelocity = toTarget - move.velocity;
returnForce = disiredVelocity - move.velocity;
}
return returnForce;
}
else
{
//完成目标移除
move.arriveRemove.Add(MoveType.Arrive);
move.velocity = Vector3.zero;
return Vector3.zero;
}
}
}
逃离:
using UnityEngine;
using System.Collections;
public class MoveFlee : MoveBase {
public Transform target;
float fearDistance;
public MoveFlee(MoveComponent move, Transform target, float fearDistance) : base(move) { this.target = target; this.fearDistance = fearDistance; }
public override Vector3 Force()
{
if(Vector3.Distance(move.transform.position,target.position) > fearDistance)
{
//完成目标移除
move.arriveRemove.Add(MoveType.Flee);
move.velocity = Vector3.zero;
return Vector3.zero;
}
//反方向加速度向量
disiredVelocity = (move.transform.position - target.position).normalized * move.maxSpeed;
return disiredVelocity - move.velocity;
}
}
路径移动:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MoveFllowPath : MoveBase {
public List<Transform> path = new List<Transform>();
private float slowDistance = 5f;
private Transform target;
private int index = 0;
public MoveFllowPath(MoveComponent move, List<Transform> path) : base(move) { this.path = path; target = path[index]; }
public override Vector3 Force()
{
Vector3 returnForce = Vector3.zero;
Vector3 distance = target.position - move.transform.position;
//最后一点
if (index == path.Count - 1)
{
if (Vector3.Distance(target.position, move.transform.position) < move.completeDisatnce)
{
//完成目标移除
move.arriveRemove.Add(MoveType.FollowPath);
move.velocity = Vector3.zero;
return Vector3.zero;
}
if (distance.magnitude > slowDistance)
{
disiredVelocity = distance.normalized * move.maxSpeed;
}
else
{
disiredVelocity = distance - move.velocity;
}
returnForce = disiredVelocity - move.velocity;
}
else
{
if(Vector3.Distance(target.position,move.transform.position) < move.completeDisatnce)
{
index++;
target = path[index].transform;
}
disiredVelocity = distance.normalized * move.maxSpeed;
returnForce = disiredVelocity - move.velocity;
}
return returnForce;
}
}
拦截:
using UnityEngine;
using System.Collections;
public class MovePursuit : MoveBase {
public Transform target;
public MovePursuit(MoveComponent move, Transform target) : base(move) { this.target = target; }
public override Vector3 Force()
{
if(target.GetComponent<MoveComponent>()==null)
{
move.arriveRemove.Add(MoveType.Pursuit);
return Vector3.zero;
}
if (Vector3.Distance(target.transform.position, move.transform.position) > move.completeDisatnce)
{
Vector3 toTarget = target.transform.position - move.transform.position;
//两个对象的前方向量夹角
float relativeDirection = Vector3.Dot(move.transform.forward, target.transform.forward);
//追踪向量和对象前方向量的夹角>0并且两个对象前方夹角<18
if(Vector3.Dot(toTarget,move.transform.forward) > 0 && relativeDirection < -0.95f)
{
//差不多在一直线上
disiredVelocity = (target.transform.position - move.transform.position).normalized * move.maxSpeed;
return disiredVelocity - move.velocity;
}
//预期到达目标的前方位置的时间
float lookheadTime = toTarget.magnitude / (move.maxSpeed + target.GetComponent<MoveComponent>().velocity.magnitude);
//预期目标位置 = 目标位置 + 目标速度*预期到达时间
disiredVelocity = (target.transform.position + target.GetComponent<MoveComponent>().velocity * lookheadTime - move.transform.position).normalized * move.maxSpeed;
return disiredVelocity - move.velocity;
}
else
{
//完成目标移除
move.arriveRemove.Add(MoveType.Pursuit);
move.velocity = Vector3.zero;
return Vector3.zero;
}
}
}
避障:
using UnityEngine;
using System.Collections;
public class MoveCollisionAvoidance : MoveBase {
private float maxSeeAhead = 2.0f;
public MoveCollisionAvoidance(MoveComponent move, float maxSeeAhead) : base(move) { this.maxSeeAhead = maxSeeAhead; }
public override Vector3 Force()
{
RaycastHit hit;
Vector3 returnForce = Vector3.zero;
//方向:速度向量 距离:视线 * 时间
if(Physics.Raycast(move.transform.position,move.velocity,out hit,maxSeeAhead * move.velocity.magnitude /move.maxSpeed))
{
//发生碰撞的视线前方向量
Vector3 ahead = move.transform.position + move.velocity * maxSeeAhead * (move.velocity.magnitude /move.maxSpeed);
//用视线向量-碰撞物体的中心点 得到 碰撞物体中心指向视线向量的向量 用这个向量来偏移
returnForce = ahead - hit.collider.transform.position;
returnForce *= move.maxForce;
returnForce.y = 0;
}
return returnForce;
}
}