Many helicopter games exist today. The mere mention of helicopters can intimidate people. Issues like heavy physics controls can scare game developers. Actually, it's not that difficult, but this depends on the features and realism of the helicopter control system you want to create.
If you want to create a realistic helicopter system, you need to dedicate a significant amount of time. However, creating a system that is not realistic but has basic helicopter features is quite easy. Basic helicopter systems are generally not physics-based.
About This Tutorial
I will explain to you, valuable developers, step-by-step, as best as I can, how to create a basic helicopter control system. In the helicopter control system we will create, the helicopter's movements will be based on physics using Unity's Rigidbody component.
Basic Helicopter Features
Let's start by explaining the basic features a helicopter should have. These basic movements are actually similar to basic character control features:
- Ascend
- Descend
- Forward
- Backward
- Turn right
- Turn left
- Move right
- Move left
Control Mapping
In the helicopter control system we will build, the properties assigned to each feature are as follows:
| Action | Key Binding |
|---|---|
| Ascend ⬆️ | Left Shift |
| Descend ⬇️ | Left Alt |
| Forward ⬆️ | W |
| Backward ⬇️ | S |
| Turn Right ↪️ | Q |
| Turn Left ↩️ | E |
| Move Right ➡️ | A |
| Move Left ⬅️ | D |
I wanted to use the old Unity Input system for this. However, our system will work completely smoothly with the new Input system as well.
Understanding Helicopter Physics
When helicopters move, they normally tilt in that direction. For example:
- When moving forward, they make a 15-degree clockwise tilt
- When moving backward, they make a 15-degree counterclockwise tilt
- Similarly, when turning right and left, they make a 15-degree turn
Of course, when turning, the helicopter no longer stays at 15 degrees. When the movement is finished, it needs to return to its original rotation value. This is the basic logic of a helicopter.
Setting Up the Component
First, let's add our Rigidbody component to our helicopter object. I want to do this code-wise,
not through the Inspector. I'm using the RequireComponent attribute for this:
[RequireComponent(typeof(Rigidbody))]
public class Helicopter : MonoBehaviour
{
// Class code here
}
This way, our Rigidbody object will be automatically added to every object containing our
Helicopter.cs code. Also, when you download an object from GitHub, the Rigidbody
will be added directly.
Defining Variables
I wanted to divide the variables into four groups: Force, Rotation Speed, Angle, and Propeller.
I used [SerializeField] for better organization and to make the code more readable:
// Force Variables
[Header("Forces")]
[SerializeField] private float engineForce = 10f;
[SerializeField] private float altitudeChangeForce = 5f;
// Rotation Speed Variables
[Header("Rotation Speeds")]
[SerializeField] private float rotateSpeed = 50f;
[SerializeField] private float anglesSpeed = 2f;
// Angle Variables
[Header("Tilt Angles")]
[SerializeField] private float maxTiltAngle = 30f;
// Propeller Variables
[Header("Propellers")]
[SerializeField] private Transform propeller;
[SerializeField] private Transform propellerTail;
[SerializeField] private float propellerSpeed = 500f;
// Rigidbody
private Rigidbody rb;
Variable Explanations:
engineForceandaltitudeChangeForce- Determine the speed of movementrotateSpeedandanglesSpeed- Control rotation speedsmaxTiltAngle- Maximum angle for maneuvers (I set it to 30 degrees)propellerandpropellerTail- References to propeller transformsrb- Reference to the Rigidbody component
Actually, the presence or absence of propellers doesn't affect the operation of our system, but what truly makes a helicopter a helicopter, different from airplanes, is its propellers!
Initialization
We didn't write much code in the Start method. We only used it to access our Rigidbody component and disable gravity:
void Start()
{
rb = GetComponent();
rb.useGravity = false;
}
We're turning off the force of gravity to keep the helicopter airborne. Otherwise, the helicopter would fall if we release our fingers from the keys.
Physics Update Loop
We use FixedUpdate instead of Update because Unity recommends using
FixedUpdate for physics operations. First, let's gather our inputs:
void FixedUpdate()
{
// Get inputs
float verticalInput = Input.GetAxis("Vertical"); // W/S
float horizontalInput = Input.GetAxis("Horizontal"); // A/D
float altitudeInput = Input.GetAxis("Altitude"); // Left Shift/Alt
float rotationInput = Input.GetAxis("Rotation"); // Q/E
// Process movement and rotation
Move(verticalInput, horizontalInput, altitudeInput);
Rotate(rotationInput);
Tilt(verticalInput, horizontalInput);
RotatePropellers();
}
Input Manager Setup
For altitudeInput and rotationInput, special settings need to be
made in Unity → Edit → Project Settings → Input Manager:
Altitude Input:
- Name: "Altitude"
- Negative Button: "left alt"
- Positive Button: "left shift"
Rotation Input:
- Name: "Rotation"
- Negative Button: "e"
- Positive Button: "q"
Movement Implementation
Now let's define our movement vectors and apply forces:
void Move(float vertical, float horizontal, float altitude)
{
// Forward/Backward movement
Vector3 forwardForce = transform.forward * vertical * engineForce * Time.deltaTime;
// Right/Left movement
Vector3 sidewaysForce = transform.right * horizontal * engineForce * Time.deltaTime;
// Altitude control
Vector3 altitudeForce = transform.up * altitude * altitudeChangeForce * Time.deltaTime;
// Apply all forces
rb.AddForce(altitudeForce);
rb.AddForce(forwardForce + sidewaysForce);
}
Rotation and Tilting
Now we come to the turns that will make our helicopter resemble a real helicopter. The tilting creates realistic-looking movement:
void Rotate(float rotationInput)
{
// Rotate helicopter around Y-axis
float rotation = rotationInput * rotateSpeed * Time.deltaTime;
transform.Rotate(Vector3.up, rotation);
}
void Tilt(float vertical, float horizontal)
{
// Calculate tilt angles based on input
float WS_TiltAngle = -vertical * maxTiltAngle; // Forward/back tilt
float AD_TiltAngle = horizontal * maxTiltAngle; // Side tilt
// Create target rotation
Quaternion targetRotation = Quaternion.Euler(WS_TiltAngle, transform.eulerAngles.y, AD_TiltAngle);
// Smoothly interpolate to target rotation
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, anglesSpeed * Time.deltaTime);
}
How Tilting Works:
- Calculate the desired tilt angle based on input (multiplied by
maxTiltAngle) - Create a target rotation quaternion
- Use
Quaternion.Lerpto smoothly transition to the target rotation - When input stops, the helicopter naturally returns to level position
Propeller Rotation
With these two lines of code, we can rotate our main rotor and tail rotor:
void RotatePropellers()
{
if (propeller != null)
propeller.Rotate(Vector3.up * propellerSpeed * Time.deltaTime);
if (propellerTail != null)
propellerTail.Rotate(Vector3.right * propellerSpeed * Time.deltaTime);
}
Actually, you could also rotate them with animation, although it wouldn't be very efficient in my opinion.
Complete Code
Full Implementation
Here's the complete helicopter control script ready to use:
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class Helicopter : MonoBehaviour
{
[Header("Forces")]
[SerializeField] private float engineForce = 10f;
[SerializeField] private float altitudeChangeForce = 5f;
[Header("Rotation Speeds")]
[SerializeField] private float rotateSpeed = 50f;
[SerializeField] private float anglesSpeed = 2f;
[Header("Tilt Angles")]
[SerializeField] private float maxTiltAngle = 30f;
[Header("Propellers")]
[SerializeField] private Transform propeller;
[SerializeField] private Transform propellerTail;
[SerializeField] private float propellerSpeed = 500f;
private Rigidbody rb;
void Start()
{
rb = GetComponent();
rb.useGravity = false;
}
void FixedUpdate()
{
float verticalInput = Input.GetAxis("Vertical");
float horizontalInput = Input.GetAxis("Horizontal");
float altitudeInput = Input.GetAxis("Altitude");
float rotationInput = Input.GetAxis("Rotation");
Move(verticalInput, horizontalInput, altitudeInput);
Rotate(rotationInput);
Tilt(verticalInput, horizontalInput);
RotatePropellers();
}
void Move(float vertical, float horizontal, float altitude)
{
Vector3 forwardForce = transform.forward * vertical * engineForce * Time.deltaTime;
Vector3 sidewaysForce = transform.right * horizontal * engineForce * Time.deltaTime;
Vector3 altitudeForce = transform.up * altitude * altitudeChangeForce * Time.deltaTime;
rb.AddForce(altitudeForce);
rb.AddForce(forwardForce + sidewaysForce);
}
void Rotate(float rotationInput)
{
float rotation = rotationInput * rotateSpeed * Time.deltaTime;
transform.Rotate(Vector3.up, rotation);
}
void Tilt(float vertical, float horizontal)
{
float WS_TiltAngle = -vertical * maxTiltAngle;
float AD_TiltAngle = horizontal * maxTiltAngle;
Quaternion targetRotation = Quaternion.Euler(WS_TiltAngle, transform.eulerAngles.y, AD_TiltAngle);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, anglesSpeed * Time.deltaTime);
}
void RotatePropellers()
{
if (propeller != null)
propeller.Rotate(Vector3.up * propellerSpeed * Time.deltaTime);
if (propellerTail != null)
propellerTail.Rotate(Vector3.right * propellerSpeed * Time.deltaTime);
}
}
Tips and Customization
Enhancement Ideas
- Add drag: Set Rigidbody drag values for more realistic deceleration
- Camera shake: Add screen shake when the helicopter moves
- Sound effects: Include propeller and engine sounds
- Particle effects: Add dust or smoke when near the ground
- Damage system: Implement health and collision damage
- Fuel system: Add limited fuel requiring refueling
Conclusion
Congratulations! You now have a basic helicopter control system. This is a foundation that you can build upon and customize to suit your own game's needs.
I want to tell you, valuable developers, that this is a basic helicopter control system I've created. You can add or remove features to it to suit your own system. I just wanted to explain the basic logic.
If you want to download the complete project, you can check my GitHub. Happy coding!