The question is answered, right answer was accepted
Helicopter Physics C#
Hey there everyone my name is Tz, Recently I got a little stuck on something, this "something" is converting this tutorial from JavaScript to C#. I have almost successfully completed this, I now have no errors, etc, but when the helicopter adds torque (in c#) it won't stop, even when I'm not moving my mouse.
If this is any consolation, here's the code.
using UnityEngine;
using System.Collections;
public class HairyCopter : MonoBehaviour {
public GameObject main_Rotor_GameObject; // gameObject to be animated
public GameObject tail_Rotor_GameObject; // gameObject to be animated
public float max_Rotor_Force = 22241.1081f; // newtons
private float max_Rotor_Velocity = 7200; // degrees per second
private float rotor_Velocity = 0.0f; // value between 0 and 1
private float rotor_Rotation = 0.0f; // degrees... used for animating rotors
public float max_tail_Rotor_Force = 15000.0f; // newtons
public float max_Tail_Rotor_Velocity = 2200.0f; // degrees per second
private float tail_Rotor_Velocity = 0.0f; // value between 0 and 1
private float tail_Rotor_Rotation = 0.0f; // degrees... used for animating rotors
public float forward_Rotor_Torque_Multiplier = 0.5f; // multiplier for control input
public float sideways_Rotor_Torque_Multiplier = 0.5f; // multiplier for control input
private bool main_Rotor_Active = true; // boolean for determining if a prop is active
private bool tail_Rotor_Active = true; // boolean for determining if a prop is active
public Vector3 MyPos;
public Quaternion MyRot;
Vector3 torqueValue;
//Vector3 controlTorque;
// Forces are applied in a fixed update function so that they are consistent no matter what the frame rate of the game is. This is
// important to keeping the helicopter stable in the air. If the forces were applied at an inconsistent rate, the helicopter would behave
// irregularly
float MouseY;
float MouseX;
float H;
float V;
// Forces are applied in a fixed update function so that they are consistent no matter what the frame rate of the game is. This is
// important to keeping the helicopter stable in the air. If the forces were applied at an inconsistent rate, the helicopter would behave
// irregularly.
[RPC]
void SendMouseInputs(float Mx,float My)
{
//controlTorque = Vector3(My * forward_Rotor_Torque_Multiplier,1.0, -Mx * sideways_Rotor_Torque_Multiplier);
MouseY = My * (PlayerPrefs.GetFloat("YSensVeh") /3);
MouseX = -Mx * (PlayerPrefs.GetFloat("XSensVeh") / 8);
}
void FixedUpdate () {
// First we must compute the torque values that are applied to the helicopter by the propellers. The "Control Torque" is used to simulate
// the variable angle of the blades on a helicopter and the "Torque Value" is the final sum of the torque from the engine attached to the
// main rotor, and the torque applied by the tail rotor.
//if(Input.GetAxis("Mouse Y") != 0 || Input.GetAxis("Mouse X") != 0)
// controlTorque = new Vector3(Input.GetAxis("Mouse Y") * forward_Rotor_Torque_Multiplier, 1.0f, -Input.GetAxis("Mouse X") * sideways_Rotor_Torque_Multiplier);
if (GetComponent<VehicleController>().Driver == MultiplayerManager.instance.MyPlayer)
{
if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0)
{
if (Network.isServer)
SendMouseInputs(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
else
networkView.RPC("SendMouseInputs", RPCMode.Server, Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
}
}
Debug.Log("mousex is "+MouseX);
Debug.Log("mousey is "+MouseY);
if (Network.isClient)
return;
Vector3 controlTorque = new Vector3(MouseY, 1.0f, MouseX);
/// networkView.RPC("SyncControlTorque", RPCMode.Server, Input.GetAxis("Mouse Y") * forward_Rotor_Torque_Multiplier, -Input.GetAxis("Mouse X") * sideways_Rotor_Torque_Multiplier);
// Now check if the main rotor is active, if it is, then add it's torque to the "Torque Value", and apply the forces to the body of the
// helicopter.
//if ( main_Rotor_Active == true ) {
torqueValue += (controlTorque * max_Rotor_Force * rotor_Velocity);
// Now the force of the prop is applied. The main rotor applies a force direclty related to the maximum force of the prop and the
// prop velocity (a value from 0 to 1)
rigidbody.AddRelativeForce( Vector3.up * max_Rotor_Force * rotor_Velocity );
// This is simple code to help stabilize the helicopter. It essentially pulls the body back towards neutral when it is at an angle to
// prevent it from tumbling in the air.
if ( Vector3.Angle( Vector3.up, transform.up ) > 110 ) {
transform.rotation = Quaternion.Slerp( transform.rotation, Quaternion.Euler( 0, transform.rotation.eulerAngles.y, 0 ), Time.deltaTime * rotor_Velocity * 2 );
//transform.eulerAngles = Vector3.Lerp(transform.eulerAngles,new Vector3(0,transform.rotation.eulerAngles.y,0),Time.deltaTime * rotor_Velocity * 2);
}
//}
// Now we check to make sure the tail rotor is active, if it is, we add it's force to the "Torque Value"
//if ( tail_Rotor_Active == true ) {
torqueValue -= (Vector3.up * max_tail_Rotor_Force * tail_Rotor_Velocity);
//torqueValue.y -= max_tail_Rotor_Force * tail_Rotor_Velocity;
///}
// And finally, apply the torques to the body of the helicopter.
rigidbody.AddRelativeTorque( torqueValue);
}
[RPC]
void SendKeyInputs(float h,float v){
H = h;
V = v;
}
void Update () {
// This line simply changes the pitch of the attached audio emitter to match the speed of the main rotor.
if (networkView.isMine)
{
MyPos = transform.position;
MyRot = transform.rotation;
}
else
{
transform.position = Vector3.Lerp(transform.position, MyPos, Time.deltaTime * 5);
transform.rotation = Quaternion.Lerp(transform.rotation, MyRot, Time.deltaTime * 5);
}
if (GetComponent<VehicleController>().Driver == MultiplayerManager.instance.MyPlayer)
{
if (Input.GetAxis("Vertical") != 0.0f || Input.GetAxis("Horizontal") != 0.0f)
{
if (Network.isServer)
SendKeyInputs(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
else
networkView.RPC("SendKeyInputs", RPCMode.Server, Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
}
}
if (Network.isClient)
return;
audio.pitch = rotor_Velocity;
// Now we animate the rotors, simply by setting their rotation to an increasing value multiplied by the helicopter body's rotation.
//if ( main_Rotor_Active == true ) {
main_Rotor_GameObject.transform.rotation = transform.rotation * Quaternion.Euler( 0, rotor_Rotation, 0);
//}
//if ( tail_Rotor_Active == true ) {
tail_Rotor_GameObject.transform.rotation = transform.rotation * Quaternion.Euler( -tail_Rotor_Rotation, 0, 0 );
//}
// this just increases the rotation value for the animation of the rotors.
rotor_Rotation += max_Rotor_Velocity * rotor_Velocity * Time.deltaTime;
tail_Rotor_Rotation += max_Tail_Rotor_Velocity * rotor_Velocity * Time.deltaTime;
// here we find the velocity required to keep the helicopter level. With the rotors at this speed, all forces on the helicopter cancel
// each other out and it should hover as-is.
float hover_Rotor_Velocity = (rigidbody.mass * Mathf.Abs( Physics.gravity.y ) / max_Rotor_Force);
float hover_Tail_Rotor_Velocity = (max_Rotor_Force * rotor_Velocity) / max_tail_Rotor_Force;
// Now check if the player is applying any throttle control input, if they are, then increase or decrease the prop velocity, otherwise,
// slowly LERP the rotor speed to the neutral speed. The tail rotor velocity is set to the neutral speed plus the player horizontal input.
// Because the torque applied by the main rotor is directly proportional to the velocity of the main rotor and the velocity of the tail rotor,
// so when the tail rotor velocity decreases, the body of the helicopter rotates.
if ( V != 0.0f ) {
rotor_Velocity += V * 0.001f;
}else{
rotor_Velocity = Mathf.Lerp( rotor_Velocity, hover_Rotor_Velocity, Time.deltaTime * Time.deltaTime * 5 );
}
tail_Rotor_Velocity = hover_Tail_Rotor_Velocity - H;
//Debug.Log(tail_Rotor_Velocity);
// now we set velocity limits. The multiplier for rotor velocity is fixed to a range between 0 and 1. You can limit the tail rotor velocity
// too, but this makes it more difficult to balance the helicopter variables so that the helicopter will fly well.
if ( rotor_Velocity > 1.0f ) {
rotor_Velocity = 1.0f;
}else if ( rotor_Velocity < 0.0f ) {
rotor_Velocity = 0.0f;
}
}
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
if (stream.isWriting)
{
MyPos = transform.position;
MyRot = transform.rotation;
stream.Serialize(ref MyPos);
stream.Serialize(ref MyRot);
stream.Serialize(ref rotor_Velocity);
stream.Serialize(ref rotor_Rotation);
stream.Serialize(ref tail_Rotor_Rotation);
}
else
{
stream.Serialize(ref MyPos);
stream.Serialize(ref MyRot);
stream.Serialize(ref rotor_Velocity);
stream.Serialize(ref rotor_Rotation);
stream.Serialize(ref tail_Rotor_Rotation);
transform.position = Vector3.Lerp(transform.position, MyPos, Time.deltaTime * 5);
transform.rotation = Quaternion.Lerp(transform.rotation, MyRot, Time.deltaTime * 5);
}
}
}
PS : The code is for authoritative server, so if I've done anything wrong there, that will be greatly appreciated too :).
Are you trying to convert it to learn C# or to learn Unity? Doing both at once is a bit daunting, unless you know C++ or Java already (the syntaxes are very close).
neither, i know enough about c# and unity, I'm doing it because the rest of my game is in c#. so i converted it to make my life easier in the long run
I assume this your issue is happening because the code on line 102 is happening every frame of FixedUpdate. The torque must be non-zero every frame if you're getting the result you do. There are some if statements that are comment out in that scope, as well, perhaps those are conditions that nullify your torque / zero-out your torque?
Answer by joeybubble1 · May 02, 2013 at 05:57 PM
Ok everyone, I found the solution, on line 81, where I had "+=" I just needed "=". Thanks for all your help :)
Answer by LtTops · Jul 02, 2015 at 09:10 AM
Joeybubble, your work combined with the tutorial, really helped me to develop my own helicopter/drone script. I found the original tutorial here:
http://andrewgotow.com/unity3d-helicopter-tutorial/
For @blamejane, here is a copy of my code.
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;
}
}
LtTops, I'm trying to create a drone flight sim, any chance you'd share yours? -Valerie
Follow this Question
Related Questions
Forge-like in game editor 0 Answers
Adding Gravity to a game object to make a black hole sucking effect. 1 Answer
Clash of clans networking. 1 Answer
Setting EventTrigger in Unity with JavaScript 0 Answers
Check for collision while animating 0 Answers