目录

  • 说在前面
  • 系列目录
  • 力矩
  • Banked Turn
  • 代码
  • 飞行录像

力矩

  • Wikipedia
  • 如下图,力矩是在垂直方向上变化的箭头,力unity3d 风场_unity3d 风场是作用在小球上变化的箭头,红色箭头是转动轴到着力点的距离矢量unity3d 风场_ci_02。力unity3d 风场_unity3d 风场与距离矢量unity3d 风场_ci_02的叉积结果即力矩。
  • 在Unity中,我们可以直接将力矩(而不是力)添加在刚体上。 如下图,若想要让飞机俯仰转动,那么就需要在x轴(红轴)上添加力矩

Banked Turn

  • 译作“倾斜转弯”? 想象一下影视作品中的飞机转弯的情形
  • Wikipedia
  • unity3d 风场_System_05

  • 如上图,绿色为升力,蓝色为重力,黄色为向心力。向心力影响了飞机的偏摆,即“转弯”。

代码

  • AeroplaneUserControl.cs不变
  • AeroplaneController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace AircraftJetAI
{
    public class AeroplaneController : MonoBehaviour
    {
        private float m_Lift = 0.002f;                      // 飞机飞行时产生的升力单位,简化
        private float m_ZeroLiftSpeed = 300;                // 飞机飞行速度达到这个值时,不再有升力
        private float m_RollEffect = 1f;                    // 翻滚角输入的强度单位,这个值越大,在按键的时候越容易翻滚
        private float m_PitchEffect = 1f;                   // 俯仰角输入的强度单位
        private float m_YawEffect = 0.2f;                   // 偏摆角输入的强度单位
        private float m_BankedTurnEffect = 0.5f;            // 倾斜转弯的量,越大,越容易转弯

        private Rigidbody m_Rigidbody;                      // 刚体组件
        private float m_BankedTurnAmount;

        public float RollInput { get; private set; }        // 翻滚角输入
        public float PitchInput { get; private set; }       // 俯仰角输入
        public float YawInput { get; private set; }         // 偏摆角输入
        public float RollAngle { get; private set; }        // 翻滚角
        public float PitchAngle { get; private set; }       // 俯仰角
        public float ForwardSpeed { get; private set; }     // 飞机飞行的速度
        // 在脚本对象的第一帧时调用
        void Start()
        {
            m_Rigidbody = GetComponent<Rigidbody>();        // 获取刚体组件
        }
        // 移动函数
        public void Move(float rollInput, float pitchInput, float yawInput)                                  
        {
            RollInput = rollInput;
            PitchInput = pitchInput;
            YawInput = yawInput;
            
            ClampInputs();

            CalculateRollAndPitchAngles();

            CalculateForwardSpeed();

            CalculateLinearForces();

            CalculateTorque();
        }
        private void ClampInputs()
        {
            // 将角度输入限制在[-1,1]
            RollInput = Mathf.Clamp(RollInput, -1, 1);
            PitchInput = Mathf.Clamp(PitchInput, -1, 1);
            YawInput = Mathf.Clamp(YawInput, -1, 1);
        }
        private void CalculateRollAndPitchAngles()
        {
            // 计算当前的翻滚角以及俯仰角
            var flatForward = transform.forward;
            flatForward.y = 0;
            // 
            if (flatForward.sqrMagnitude > 0)
            {
                flatForward.Normalize();
                // 计算当前的俯仰角
                var localFlatForward = transform.InverseTransformDirection(flatForward);
                // 角度使用弧度制
                PitchAngle = Mathf.Atan2(localFlatForward.y, localFlatForward.z);
                // 计算当前的翻滚角
                var flatRight = Vector3.Cross(Vector3.up, flatForward);
                var localFlatRight = transform.InverseTransformDirection(flatRight);
                RollAngle = Mathf.Atan2(localFlatRight.y, localFlatRight.x);
            }
        }
        private void CalculateForwardSpeed()
        {
            // 计算飞机自身的速度,沿自身z轴的方向
            var localVelocity = transform.InverseTransformDirection(m_Rigidbody.velocity);
            ForwardSpeed = Mathf.Max(0, localVelocity.z);
        }
        private void CalculateLinearForces()
        {
            //添加动力
            var forces = Vector3.zero;
            // 首先是模拟引擎产生的动力,假定固定为40,方向与飞机自身的z轴(机头指向的方向)相同
            forces += 40 * transform.forward;
            // 计算升力的方向,这里是用飞机的速度方向与飞机的x轴叉乘的方向
            var liftDirection = Vector3.Cross(m_Rigidbody.velocity, transform.right).normalized;
            // 然后是计算零升力因子,ForwardSpeed=m_ZeroLiftSpeed时,返回0;ForwardSpeed=0,返回1;
            var zeroLiftFactor = Mathf.InverseLerp(m_ZeroLiftSpeed, 0, ForwardSpeed);
            // 计算升力,简化了升力的计算公式
            var liftPower = ForwardSpeed * ForwardSpeed * m_Lift * zeroLiftFactor;
            // 添加升力
            forces += liftPower * liftDirection;
            // 应用力
            m_Rigidbody.AddForce(forces);
        }
        private void CalculateTorque()
        {
            // 计算力矩
            var torque = Vector3.zero;
            // 依据俯仰角输入,计算飞机自身x轴方向上的力矩,此时力的方向应该是垂直于xoz平面的
            torque += PitchInput * m_PitchEffect * transform.right;
            // 依据偏摆角输入,计算飞机自身y轴方向上的力矩
            torque += YawInput * m_YawEffect * transform.up;
            // 依据翻滚角输入,计算飞机自身z轴方向上的力矩
            torque += -RollInput * m_RollEffect * transform.forward;
            // 计算倾斜转弯时的力矩
            m_BankedTurnAmount = Mathf.Sin(RollAngle);
            torque += m_BankedTurnAmount * m_BankedTurnEffect * transform.up;
            // 最终力矩是乘上了飞行速度大小的
            m_Rigidbody.AddTorque(torque * ForwardSpeed);
        }
    }
}

飞行录像

S键向上,W键向下

unity3d 风场_unity3d 风场_06