Код:
Appendix A Helicopter Script
/* csHelicopter2 written by N. E. Topham 10 Jun 15
* Based on work by:
* Andrew Gotow: http://andrewgotow.com/unity3D-helicopter-tutorial/
* joeybubble1: http://answers.unity3D.com/questions/447776/helicopter-physics-c.html;
* GAPH: https://www.assetstore.unity3D.com/en/#!/content/27229
*
* The script produced a flight model for a helicopter that manoeuvres
* in a similar manner to a drone. It auto-hovers and maintains
* altitude. The main motor and sub motor game objects, should be
* mapped to the rotating blade assembly, and ‘rb’ should link to the
* main rigid body. Adjusting the climbrate changes the vertical
* speeds.
*/
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class csHellicopter2 : MonoBehaviour {
public KeyCode UpKey;
public KeyCode DownKey;
public KeyCode FrontSpin;
public KeyCode BackWardSpin;
public KeyCode LeftTurn;
public KeyCode RightTurn;
public KeyCode LeftSpin;
public KeyCode RightSpin;
public KeyCode EngineOnOffKey;
//Helicopter Big Propeller. Use Y Rotate Value.
public GameObject[] MainMotor;
//Helicopter Small Propeller. User X RotateValue.
public GameObject[] SubMotor;
//Helicopter Engine Sound.
public AudioSource _AudioSource;
public float MainMotorRotateVelocity;
public float SubMotorRotateVelocity;
//Rigidbody variable for controlling drag, high drag needed to retard motion, low drag needed to prevent 'floating' when engine is off.
public Rigidbody rb;
/* Not currently used
* //Text for de-bugging.
* public GUIElement pitchInputValue;
* public GUIElement VertV;
* public GUIElement PitchAngle;
*/
float VerticalVelocity = 0.0f;
float MainMotorRotation = 0.0f;
float SubMotorRotation = 0.0f;
public float ClimbRate;
float AltitudeInput;
//Pitch Values
float Pitch;
float PitchInput;
float forwardSpeed;
// Yaw Variables
float Yaw = 150;
float LeftRightTurn;
// Roll Variables
float Roll;
float LeftRightSpin;
float sideSpeed;
bool EngineOn = false;
float EngineValue = 0.0f;
//Runs when script first called
void start(){
rb = GetComponent<Rigidbody> ();
}
//Runs every physics step, always a fixed interval, best used for rigidbody physics updates.
void FixedUpdate(){
//MotorVelocityContorl(); // Check Helicoptor AltitudeInput State
if (EngineOn) {
//Applies force on the current vertical axis of the Helicopter
GetComponent<Rigidbody>().AddRelativeForce (Vector3.up * ClimbRate * VerticalVelocity);
GetComponent<Rigidbody>().AddRelativeForce (Vector3.right * sideSpeed);
// additional force to counter altitude loss – note can result in climbing if not at full roll or when used with pitch
GetComponent<Rigidbody>().AddForce (Vector3.up *Mathf.Abs (sideSpeed*0.33f));
GetComponent<Rigidbody>().AddRelativeForce (Vector3.forward * forwardSpeed);
GetComponent<Rigidbody>().AddForce (Vector3.up *Mathf.Abs (forwardSpeed*0.33f));
// High drag to damp motion
rb.drag = 2;
//Sets Max Altitude
if (transform.position.y > 500)
//At max altitude reverses keyboard input
GetComponent<Rigidbody>().AddRelativeForce (-Vector3.up * ClimbRate * VerticalVelocity);
AltitudeInput = KeyValue (DownKey, UpKey);
PitchInput = KeyValue (BackWardSpin, FrontSpin);
LeftRightTurn = KeyValue (LeftTurn, RightTurn);
LeftRightSpin = KeyValue (LeftSpin, RightSpin);
//Pitch Value
if (PitchInput != 0) {
Pitch += PitchInput * Time.fixedDeltaTime * 60f;
//Limits the Pitch to a value of 20.
Pitch = Mathf.Clamp (Pitch, -20f, 20f);
//additional forwards force to improve lateral movement, adjusting the integer increases the speed.
forwardSpeed = PitchInput * 7;
//Constant initially 50 adjusted to 7 after rescaling SE.
} else {
Pitch = Mathf.Lerp (Pitch, 0, Time.fixedDeltaTime * 3.0f);
// reset forward speed value
forwardSpeed = 0.0f;
}
//Yaw Value
//Yaw is unlimited allowing 360deg rotation
Yaw += LeftRightTurn * Time.fixedDeltaTime * 60f;
//Roll Value
if (LeftRightSpin != 0) {
Roll += -LeftRightSpin * Time.fixedDeltaTime * 60f;
//Limits the roll to a value of 1.2
Roll = Mathf.Clamp (Roll, -20f, 20f);
//additional sideways force to improve lateral movement
sideSpeed = LeftRightSpin * 7;
//Constant initially 50 adjusted to 7 after rescaling SE.
} else {
//Smooth the Roll back to 0
Roll = Mathf.Lerp (Roll, 0, Time.fixedDeltaTime * 3.0f);
//Reset the sideSpeed value - note, this line may not be required if the sideSpeed were taken outside of the if statement
sideSpeed = 0.0f;
}
//Transforms from current orientation to desired new rotation, indicated by Pitch Yaw and Roll Values with a 1.5 Second smoothing factor
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.Euler (Pitch, Yaw, Roll), Time.fixedDeltaTime * 1.5f);
/* Not Used in main system
//Debugging outputs
PitchAngle.GetComponent<GUIText>().text = "Pitch Angle = " + transform.rotation;
VertV.GetComponent<GUIText>().text = "Vertical Velocity = " + VerticalVelocity;
pitchInputValue.GetComponent<GUIText>().text = "Pitch Input =" + PitchInput;
*/
else {
rb.drag=0;
}
}
// Update fires every Frame, time step dependent upon framerate
void Update (){
SoundControl(); // Check Helicopter Engine Sound
MotorRotateControl(); // Check Motor Rotate State
MotorVelocityContorl(); // Check Helicopter AltitudeInput State
EngineControl(); // Check Engine Turn On/Off
}
//Key input script, originally used to smooth inputs, no longer strictly required, but retained to allow future adjustments, maybe required for gesture controls.
float KeyValue(KeyCode A, KeyCode B){
float Value = 0.0f;
if (Input.GetKey (A))
Value = -1.0f;
else if (Input.GetKey (B))
Value = 1.0f;
else
Value = 0;//As soon as keys are released returns a 0 value
return Value;
}
void MotorVelocityContorl(){
if (EngineOn){
//for maintain altitude.
float Hovering = (Mathf.Abs(GetComponent<Rigidbody>().mass * Physics.gravity.y) / ClimbRate);
if (AltitudeInput != 0.0f)
//if Input Up/Down Axes, increase VerticalVelocity for Increase altitude.
VerticalVelocity += AltitudeInput * 0.1f;
else
//if no input on Vertical Axes revert to Hovering VerticalVelocity = Hovering;
/* Original code included a smoothing function to gradually shift to hovering, when combined with the physics inertial effects this resulted in over-smoothing.
* To resolve this the code line below was replaced with 'Hovering;'
*
* Mathf.Lerp(VerticalVelocity, Hovering, Time.deltaTime);
*
* This resulted in improved vertical handling.
*/
}
CheckVerticalVelocity();
}
//Prevents verticalVelocitiy exceeding 1
void CheckVerticalVelocity(){
if (VerticalVelocity > 1.0f)
VerticalVelocity = 1.0f;
else if (VerticalVelocity < -0.5f)
//When set to zero no reduction in decent speed.
VerticalVelocity = -0.5f;
}
//Spins rotors with smoothed start and stop animation
void MotorRotateControl(){
if (MainMotor.Length > 0){
for (int i = 0; i < MainMotor.Length; i++)
MainMotor[i].transform.Rotate(0, MainMotorRotation, 0);
}
if (SubMotor.Length > 0){
for (int i = 0; i < SubMotor.Length; i++)
SubMotor[i].transform.Rotate(SubMotorRotation, 0, 0);
}
MainMotorRotation = MainMotorRotateVelocity * EngineValue * Time.deltaTime;
SubMotorRotation = SubMotorRotateVelocity * EngineValue * Time.deltaTime;
}
//Engine Control script, turns the engines on and off.
void EngineControl(){
if (Input.GetKeyDown(EngineOnOffKey)){
if (EngineOn)
EngineOn = false;
else
EngineOn = true;
}
if (EngineOn == true){
if (EngineValue < 1)
EngineValue += Time.deltaTime;
if (EngineValue >= 1)
EngineValue = 1;
}
else if (EngineOn == false){
if (EngineValue > 0)
EngineValue -= Time.deltaTime / 2;
if (EngineValue <= 0)
EngineValue = 0;
}
}
//Sound Control script, varies pitch based on engine speed
void SoundControl(){
if (EngineValue > 0){
_AudioSource.mute = false;
_AudioSource.pitch = EngineValue;
}
else
_AudioSource.mute = true;
}
}