lgw2003
3/4/2020 - 3:06 AM

Unity移动及方向

移动 转向 抛物线 附件 BaseProp.cs 道具基类 配合抛物线实现掉落效果

//面向前方移动 需类外配合转向
private void Move()
{
  // 方向*输入轴*速度*单位时间=移动距离
  Vector3 movement = transform.forward * m_MovementInput * m_Speed * Time.deltaTime;
  // 刚体位置+单位时间移动距离 实现位置前进
  m_Rigidbody.MovePosition(m_Rigidbody.position + movement);
}

//全向移动 不考虑面向的方向 
void Move(float h,float v)
{
  float h = Input.GetAxis("Horizontal");
  float v = Input.GetAxis("Vertical");
  Vector3 movement;
  movement.Set(h,0f,v);
  //防止斜方向向量大于1,使用normalized使向量归1
  movement = movement.normalized * speed * Time.deltaTime;
  playerRigidbody.MovePosition(transform.position+movement);
}

//射线检测 实现角色面向鼠标指向
void Turning()
{
    Ray camRay = Camera.main.ScreenPointToRay(Input.mousePosition);
    //声明变量 用于从射线投射获取信息的结构
    RaycastHit floorHit;
    //检测射线是否碰撞,参数1射线位置与方向,参数2包含有碰撞体的信息输出到floorHit,参数3射线长度,参数4用于忽略其他碰撞的遮罩层
    if (Physics.Raycast(camRay, out floorHit, camRayLength, floorMask))
    {
        //计算射线击中的点与角色之间的向量
        Vector3 playerToMouse = floorHit.point - transform.position;
        //保证y坐标为0,角色不会飘起来
        playerToMouse.y = 0f;
        //角色注视的位置转为射线击中的点
        Quaternion newRotation = Quaternion.LookRotation(playerToMouse);
        //角色刚体面向新方向
        playerRigidbody.MoveRotation(newRotation);
    }
}
//刚体转向
    private void Turn()
    {
        // 输入轴*速度*单位时间 = 转向率
        float turn = m_TurnInput * m_TurnSpeed * Time.deltaTime;
        // 返回一个Y轴转向度
        Quaternion inputRotation = Quaternion.Euler(0f, turn, 0f);
        // 刚体方向移动到当前方向*转向度 实现转向
        m_Rigidbody.MoveRotation(m_Rigidbody.rotation * inputRotation);
    }

//应用旋转 方向*速度*单位时间 世界坐标 或 本地坐标
transform.Rotate(Vector3.left * 10 * Time.deltaTime,Space.World);
//面向一个方向
Vector3 relativePos = target.position - transform.position;
Quaternion rotation = Quaternion.LookRotation(relativePos);
transform.rotation = rotation;
//以轴进行旋转 一定角度 Y轴旋转30°
rotation = Quaternion.Euler(new Vector3(0, 30, 0));
//从一个角度过度到另一角度 timeCount 0-1之间
transform.rotation = Quaternion.Slerp(from.rotation, to.rotation, timeCount);
//直接旋转 例 正方体上面向前转到正前面
transform.rotation = Quaternion.FromToRotation(Vector3.up, transform.forward);
using UnityEngine;

    /// <summary>
    /// 抛物线运动轨迹
    /// ZhangYu 2019-04-28
    /// <param>blog:https://segmentfault.com/a/1190000018336439</param>
    /// </summary>
    public class ParabolaPath {

        /// <summary> 是否夹紧起点和终点 </summary>
        public bool isClampStartEnd;
        private Vector3 m_start;
        private Vector3 m_end;
        private float m_height;
        private float m_gravity;
        private float m_upTime;
        private float m_downTime;
        private float m_totalTime;
        private Vector3 m_velocityStart;
        private Vector3 m_position;
        private float m_time;

        /// <summary> 初始化抛物线运动轨迹 </summary>
        /// <param name="start">起点</param>
        /// <param name="end">终点</param>
        /// <param name="height">高度(相对于两个点的最高位置 高出多少)</param>
        /// <param name="gravity">重力加速度(负数)</param>
        /// <returns></returns>
        public ParabolaPath(Vector3 start, Vector3 end, float height = 10, float gravity = -9.8f) {
            Init(start, end, height, gravity);
        }

        /// <summary> 初始化抛物线运动轨迹 </summary>
        /// <param name="start">起点</param>
        /// <param name="end">终点</param>
        /// <param name="height">高度(相对于两个点的最高位置 高出多少)</param>
        /// <param name="gravity">重力加速度(负数)</param>
        /// <returns></returns>
        public void Init(Vector3 start, Vector3 end, float height = 10, float gravity = -9.8f) {
            float topY = Mathf.Max(start.y, end.y) + height;
            float d1 = topY - start.y;
            float d2 = topY - end.y;
            float g2 = 2 / -gravity;
            float t1 = Mathf.Sqrt(g2 * d1);
            float t2 = Mathf.Sqrt(g2 * d2);
            float t = t1 + t2;
            float vX = (end.x - start.x) / t;
            float vZ = (end.z - start.z) / t;
            float vY = -gravity * t1;
            m_start = start;
            m_end = end;
            m_height = height;
            m_gravity = gravity;
            m_upTime = t1;
            m_downTime = t2;
            m_totalTime = t;
            m_velocityStart = new Vector3(vX, vY, vZ);
            m_position = m_start;
            m_time = 0;
        }

        /// <summary> 起点 </summary>
        public Vector3 start { get { return m_start; } }
        /// <summary> 终点 </summary>
        public Vector3 end { get { return m_end; } }
        /// <summary> 目标高度 </summary>
        public float height { get { return m_height; } }
        /// <summary> 重力加速度 </summary>
        public float gravity { get { return m_gravity; } }
        /// <summary> 上升时间 </summary>
        public float upTime { get { return m_upTime; } }
        /// <summary> 下降时间 </summary>
        public float downTime { get { return m_downTime; } }
        /// <summary> 总运动时间 </summary>
        public float totalTime { get { return m_totalTime; } }
        /// <summary> 顶点 </summary>
        public Vector3 top { get { return GetPosition(m_upTime); } }
        /// <summary> 初始速度 </summary>
        public Vector3 velocityStart { get { return m_velocityStart; } }
        /// <summary> 当前位置 </summary>
        public Vector3 position { get { return m_position; } }
        /// <summary> 当前速度 </summary>
        public Vector3 velocity { get { return GetVelocity(m_time); } }

        /// <summary> 当前时间 </summary>
        public float time {
            get { return m_time; }
            set {
                if (isClampStartEnd) value = Mathf.Clamp(value, 0, m_totalTime);
                m_time = value;
                m_position = GetPosition(value);
            }
        }

        /// <summary> 获取某个时间点的位置 </summary>
        public Vector3 GetPosition(float time) {
            if (time == 0) return m_start;
            if (time == m_totalTime) return m_end;
            float dY = 0.5f * m_gravity * time * time;
            return m_start + m_velocityStart * time + new Vector3(0, dY, 0);
        }

        /// <summary> 获取某个时间点的速度 </summary>
        public Vector3 GetVelocity(float time) {
            if (time == 0) return m_velocityStart;
            return m_velocityStart + new Vector3(0, m_velocityStart.y + m_gravity * time, 0);
        }

    }
using UnityEngine;

/// <summary>
/// 抛物线导弹
/// <para>计算弹道和转向</para>
/// <para>ZhangYu 2019-02-27</para>
/// </summary>
public class Missile : MonoBehaviour {

    public Transform target;        // 目标
    public float height = 16f;      // 高度
    public float gravity = -9.8f;   // 重力加速度
    private ParabolaPath path;      // 抛物线运动轨迹

    private void Start() {
        path = new ParabolaPath(transform.position, target.position, height, gravity);
        path.isClampStartEnd = true;
        transform.LookAt(path.GetPosition(path.time + Time.deltaTime));
    }

    private void Update() {
        // 计算位移
        float t = Time.deltaTime;
        path.time += t;
        transform.position = path.position;

        // 计算转向
        transform.LookAt(path.GetPosition(path.time + t));

        // 简单模拟一下碰撞检测
        if (path.time >= path.totalTime) enabled = false;
    }