Hi so I’m making here a flying behavior for my plane to be controlled by the player. My problem here is that I try to rotate around the localRotation and it works fine on the z-axis. But somehow it won’t work on the x-axis. I can’t find my error in the script I bet it is something complitly rediculous.
Anyway here is my code:
using UnityEngine;
public class FlyingBehavior : MonoBehaviour
{
public float finalVelocity = 1000;
public float turnSpeed = 20;
public float accelerationRate = 100;
public float decelerationRate = 250;
float initialVelocity = 0;
float currentVelocity = 0;
float xRotation;
float zRotation;
void Update()
{
float planeX = Input.GetAxis("Horizontal") * turnSpeed * Time.deltaTime;
float planeZ = Input.GetAxis("Vertical") * turnSpeed * Time.deltaTime;
xRotation -= planeZ;
zRotation -= planeX;
transform.localRotation = Quaternion.Euler(xRotation, 0f, zRotation);
if(Input.GetButton("Fire1"))
{
currentVelocity = currentVelocity + (accelerationRate * Time.deltaTime);
transform.Translate(Vector3.forward * Time.deltaTime * currentVelocity);
}else{
if(currentVelocity > 0)
{
currentVelocity = currentVelocity - (decelerationRate * Time.deltaTime);
transform.Translate(Vector3.forward * Time.deltaTime * currentVelocity);
}
}
currentVelocity = Mathf.Clamp(currentVelocity, initialVelocity, finalVelocity);
}
}
Hmm, this certainly all seems extremely reasonable to me. Perhaps use Debug.Log() to output the values of xRotation
and zRotation
to see if they are both changing how you expect them to?
It’s all as expected but the problem here is that the plane is rotated around the global x-axis instead of the local, which makes no sense to me
Oh I see, you’re hitting .localRotation… if you don’t rotate the whole plane, it will always be from that reference datum, the unrotated parent object, i.e, world space.
Let me dig up my flight controller and post it in a few minutes here…
Here’s the relevant code, part of a much larger project. It uses a loop in Start() with Start defined as a coroutine (totally legal under Unity), although if I wrote it today I probably would not use that construct and just put it in Update().
The FlightModelOriginalParameters stuff is just constants related to how the controls feel.
using UnityEngine;
using System.Collections;
// part of Pilot Kurt app by Kurt Dekker (@kurtdekker)
public class FlightModelOriginal : FlightModel000
{
FlightModelOriginalParameters fmop;
public FlightControlInputs fci { get; private set; }
float MaxAltitude = 100.0f;
public static FlightModelOriginal AttachToStatePlayer ( FlightModelOriginalParameters fmop)
{
FlightModelOriginal fmo = STATE.pf.gameObject.AddComponent<FlightModelOriginal> ();
fmo.fmop = fmop;
return fmo;
}
void Awake()
{
fci = FlightControlInputs.Attach (gameObject);
TimeFilteredOutput = Vector3.zero;
STATE.PlayerFlightSpeed = 10.0f;
}
public void DestroyThyself()
{
fci.DestroyThyself ();
Destroy (this);
}
Vector3 TimeFilteredOutput;
IEnumerator NoseOverAndDown( GameObject player)
{
Quaternion q1 = player.transform.rotation;
Quaternion q2 = Quaternion.Euler (70, 0, 0);
float NoseOverTime = 1.0f;
for (float t = 0; t < NoseOverTime; t += Time.deltaTime)
{
float fr = t / NoseOverTime;
player.transform.rotation = Quaternion.Lerp ( q1, q2, fr);
player.transform.position += player.transform.forward *
STATE.PlayerFlightSpeed * Time.deltaTime;
yield return null;
}
}
IEnumerator Start()
{
GameObject player = STATE.pf.gameObject;
ServiceCeiling sc = FindObjectOfType<ServiceCeiling> ();
if (sc)
{
MaxAltitude = sc.transform.position.y;
}
while(true)
{
STATE.UpdateCountersAndTimers ();
if (GameModeManager.NeedSpeedIncreasing())
{
STATE.PlayerFlightSpeed += Time.deltaTime * 0.1f;
}
Vector3 rawOutput = fci.GetOutputRaw();
rawOutput += new Vector3( Input.GetAxis( "Horizontal"), Input.GetAxis ( "Vertical"));
if (SETTINGS.InvertXControls)
{
rawOutput.x = -rawOutput.x;
}
if (SETTINGS.InvertYControls)
{
rawOutput.y = -rawOutput.y;
}
TimeFilteredOutput = Vector3.Lerp(
TimeFilteredOutput, rawOutput,
fmop.ControlSnappiness * Time.deltaTime);
float Roll = -TimeFilteredOutput.x;
if (player.transform.position.y > MaxAltitude)
{
yield return StartCoroutine( NoseOverAndDown( player));
}
Roll *= fmop.RollMultiplier;
Roll *= Time.deltaTime;
player.transform.Rotate ( new Vector3( 0, 0, Roll));
float Turn = -player.transform.eulerAngles.z;
if (Turn < 180) Turn += 360;
if (Turn > 180) Turn -= 360;
Turn *= fmop.RollToTurnCoupling;
Turn *= Time.deltaTime;
player.transform.Rotate( new Vector3( 0, Turn, 0));
float Pitch = TimeFilteredOutput.y;
Pitch *= fmop.PitchMultiplier;
Pitch *= Time.deltaTime;
if (fmop.LimitPitchEnabled)
{
float xangle = player.transform.eulerAngles.x;
if (xangle > 180) xangle -= 360.0f;
if ((xangle < -fmop.LimitPitchAngle) &&
(Pitch < 0))
{
Pitch = 0;
}
if ((xangle > fmop.LimitPitchAngle) &&
(Pitch > 0))
{
Pitch = 0;
}
}
player.transform.Rotate ( new Vector3( Pitch, 0, 0));
player.transform.position += player.transform.forward *
STATE.PlayerFlightSpeed * Time.deltaTime;
yield return null;
}
}
}
This is the FlightModelOriginalParameters config object:
using UnityEngine;
using System.Collections;
// part of Pilot Kurt app by Kurt Dekker (@kurtdekker)
public class FlightModelOriginalParameters
{
public float ControlSnappiness;
public float RollMultiplier;
public float RollToTurnCoupling;
public float PitchMultiplier;
public bool LimitPitchEnabled;
public float LimitPitchAngle;
// <WIP> New stuff to implement:
// Roll limit
// Pitch limit
public void ConfigureOriginal()
{
ControlSnappiness = 4.0f;
RollMultiplier = 70.0f;
RollToTurnCoupling = 0.5f;
PitchMultiplier = 50.0f;
}
public void ConfigureFTUECanyon()
{
ConfigureOriginal ();
RollMultiplier = 0.0f;
RollToTurnCoupling = 0.0f;
LimitPitchEnabled = true;
LimitPitchAngle = 15.0f;
}
}
You can try the app out on the appstore (iOS or Android… search for Pilot Kurt) and see what kind of controls that gives you.
I’ve tried it out and it is not quit what I need but it gets in that direction. Do you know the flight controls of GTA 5? You can rotate the plane and also seperatly control the velocity. That’s kinda what I’m trying to do. My problem really is that it doesn’t rotate around the local axis
Your line 23 generates world Euler rotations.
Note how my code applies rotations to whatever is present in the orientation right now, first along the roll axis (line 100), then along the turn axis according to roll-to-turn coupling (line 107), and finally along local pitch axis (line 130).
It is applying them to the actual base object in the player hierarchy, then finally it moves it (line 132), so everything is relative to where you are at any given moment.
Thanks I haven’t noticed how the rotation is apllied in line 100. There is just so much to read
but I think that will solve my problem thanks 
Edit I debugged my script and now everything works fine! Here is my code if anyone is interested:
sing UnityEngine;
public class FlyingBehavior : MonoBehaviour
{
public float finalVelocity = 1000;
[Range(0.01f, 1f)]
public float turnSpeed = 0.5f;
public float accelerationRate = 100;
public float decelerationRate = 250;
public float flyingSpeed = 200;
float initialVelocity = 0;
float currentVelocity = 0;
float xRotation;
float zRotation;
void Start()
{
}
void Update()
{
if(currentVelocity >= flyingSpeed)
{
float planeX = Input.GetAxis("Horizontal") * turnSpeed * Time.deltaTime;
float planeZ = Input.GetAxis("Vertical") * turnSpeed * Time.deltaTime;
xRotation += planeZ;
zRotation -= planeX;
transform.Rotate(xRotation, 0f, zRotation);
}
if(Input.GetButton("Fire1"))
{
currentVelocity = currentVelocity + (accelerationRate * Time.deltaTime);
transform.Translate(Vector3.forward * Time.deltaTime * currentVelocity);
}else{
if(currentVelocity > 0)
{
currentVelocity = currentVelocity - (decelerationRate * Time.deltaTime);
transform.Translate(Vector3.forward * Time.deltaTime * currentVelocity);
}
}
currentVelocity = Mathf.Clamp(currentVelocity, initialVelocity, finalVelocity);
}
}
Thanks for the help Kurt-Dekker!
1 Like