说在前面
- Unity版本:2017.4.37
- 资源下载:这个资源是官方自带的资源,若没有,见这里
- 说明:该项目为官方自带的项目,这里仅记录从零开始的搭建过程
系列目录
- 【Unity/Tutorial】官方AircraftJetAI(一)导入资源与创建Camera
- 【Unity/Tutorial】官方AircraftJetAI(二)创建固定地形
- 【Unity/Tutorial】官方AircraftJetAI(三)创建喷射机
- 【Unity/Tutorial】官方AircraftJetAI(四)喷射机首飞
- 【Unity/Tutorial】官方AircraftJetAI(五)力矩与喷射机转向
相关函数
移动喷射机
- 在之前的章节中,我们创建的喷射机其实有一半是在我们创建的地面之下的,现在,在我们将喷射机组装好之后,我们可以轻易的将喷射机整体上移。
- 只需要调整
AircraftJetAI
的Position
中的y
即可
添加刚体/BoxCollier组件
-
刚体组件
点击Inspector窗口
中的Add Component
搜索RigidBody
并添加
-
Box Collider组件
点击Inspector窗口
中的Add Component
搜索Box Collider
并添加;(若不添加该组件,将无法与创建的地面产生碰撞效果,导致飞机直接掉落)
通过调整Size将飞机刚好包裹住。
控制器脚本
- 创建文件夹
Scripts
- 进入该文件夹,右键创建新的
c#脚本
,命名为AeroplaneController
- 为了描述喷射机的运动,首先需要了解一下俯仰 (pitch) - 偏摆 (yaw) - 翻滚 (roll)这三个角。
- 咱们知道,飞机通过引擎产生向前的推力,让飞机有一定的速度之后,由于飞机机翼的结构,就会产生升力。当升力大于重力时,飞机就能够飞起来了。
网上找的升力计算公式: L = 1 2 ρ v 2 C S L=\dfrac{1}{2}\rho v^2CS L=21ρv2CS
其中 ρ \rho ρ为空气密度, v v v为飞机相对于空气的速度, C C C为升力系数, S S S为机翼投影面积。
在我们的实验中,将上面这个公式简化: L = v 2 l L=v^2 l L=v2l
其中 l l l为一个飞行时产生升力的系数(m_Lift
);同时使用了一个叫m_ZeroLiftSpeed
的参数,使用该参数的原因:The amount of lift drops off as the plane increases speed.(模拟飞行员在起飞后控制飞机的飞行速度,用以保持较低的飞行阻力,当然此时升力也会降低)
上图显示了飞机自身的坐标轴,其中蓝色为z轴,红色为x轴 - 代码
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 Rigidbody m_Rigidbody; // 刚体组件 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(); } 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; // 首先是模拟引擎产生的动力,假定固定为100,方向与飞机自身的z轴(机头指向的方向)相同 forces += 100 * 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); } } }
- 最后将该脚本添加到飞机对象上
直接拖动到AircraftJetAI
或者右边的Inspector窗口
;或者点击Inspector窗口
中的Add Component
按钮并搜索
用户控制脚本
- 使用同样的方法创建脚本
AeroplaneUserControl
- 代码
using System.Collections; using System.Collections.Generic; using UnityEngine; namespace AircraftJetAI { public class AeroplaneUserControl : MonoBehaviour { // 用于访问飞机的控制器 private AeroplaneController m_Aeroplane; // 在脚本对象(即飞机)被实例化的时候调用 private void Awake() { // 获取脚本对象的AeroplaneController组件 m_Aeroplane = GetComponent<AeroplaneController>(); } // 真实时间下,固定时间间隔调用 private void FixedUpdate() { // 获取用户的输入,A/D键控制左右,W/S键控制下上 float roll = Input.GetAxis("Horizontal"); float pitch = Input.GetAxis("Vertical"); // 调用Move函数,此时控制还未激活(无法用wasd控制) m_Aeroplane.Move(roll, pitch, 0); } } }
- 将该脚本添加到飞机对象上
方法同上