AI运动层的一套基于加速度的基本移动方案


移动组件:

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;

    }




}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值