Skip to main content

Drone Simulator - Programming Drone Controls

 This one is the first of the posts regarding the development of the drone simulator for Android. In this one we're covering the controls of the drone, that allow the player to move the vehicle around the world using two joysticks, resembling an actual basic drone controller. This system is divided into two parts: the joysticks that capture the input from the player and the code that moves the drone based on the input.

The joysticks

For the joysticks, I first thought of creating them myself. It seemed to be an easy task: design some simple sprites and program the input handling so, why not do it myself? The answer is simple: don't. We are using Unity Engine. This means we have access to the Unity Asset Store with thousands of assets created by the community, many of them free to use. If we don't have the knowledge, the budget or the time to create something, we go to the Asset Store and check if someone else has already figured it out and made it available for everyone. Mobile joysticks are a good example of something you would search for in the Asset Store. If you are an indie developer, unless you have a very good reason to make this sort of things yourself and reinvent the wheel, I strongly recommend to first look in the Asset Store.

In this case it came really handy as I found a free package that worked pretty well and saved me several hours of coding the joysticks, which would have turned out to be worse than the free ones in the Asset Store for sure. In case you are interested, here is the package.

The drone controller

So here is where I wanted to spend some time and create my own solution. You can already find some free drone controls in the Asset Store but with this, I wanted to make my own ad-hoc controls. After all, this is the part that gives sense to the project itself.

This part is coded in a single script that has a basic purpose: translate the input of the joysticks into a vector with the shape (x, y, z) that describes the movement of the GameObject the script is attached to.

For this, I decided to distribute the input this way:
  • The left joystick will provide the horizontal movement. In other words, it will tell us if the drone has to move frontwards, backwards or sideways.
  • The right joystick will provide the vertical movement and the rotation.
With the package I'm using we can read the input of the joystick pretty easily extracting its vertical and horizontal values separately. Therefore we can have the input information structured this way:
  • rightJoystick.Vertical: Move up or down (space Y axis).
  • rightJoystick.Horizontal: Rotate right or left.
  • leftJoystick.Vertical: Move frontwards or backwards (space Z axis).
  • leftJoystick.Horizontal: Move right or left, sideways (space X axis).

In order to be able to control the behaviour of the drone, I will use three variables to define the movement speed. This variables are defined in a Drone Scriptable Object from which I can generate different instances with different properties. Then I just have to reference the instance from this controller script to access its properties:
  • drone.maxHorizontalSpeed: Defines the maximum speed along the X and Z axes.
  • drone.maxVerticalSpeed: Defines the maximum speed along the Y axis.
  • drone.maxRotationSpeed: Defines the maximum rotation speed.
For now, I will leave it so that the speed is constant. In the future, we could add some acceleration/deceleration mechanic for a more realistic control. Therefore, we can summarise the resulting Unity C# code as follows:

Vector3 normalizedInputVector = Normalize(new Vector3(joystickLeft.Horizontal, joystickRight.Vertical, joystickLeft.Vertical));

this.transform.Translate(new Vector3(input.x * drone.maxHorizontalSpeed, input.y * drone.maxVerticalSpeed, input.z * drone.maxHorizontalSpeed) * Time.deltaTime, Space.Self);

this.transform.Rotate(new Vector3(0, joystickRight.Horizontal/5, 0) * drone.maxRotationSpeed * Time.deltaTime, Space.Self);

Also, I am using the function Normalize to transform the inputs between 0 and 5 to values between 0 and 1. That is also why I'm dividing joystickRight.Horizontal by 5 in the rotation. This is just a personal preference for maintainability and logical design.

Vector3 Normalize(Vector3 vector){
        Vector3 result = new Vector3();
        for(int i = 0; i < 3; i++){
            result[i] = vector[i]/5;
        }

        return result;
 }

And this basically works for the basic drone movement around the map. But there is one more simple thing I wanted to add to give the movement a bit more of resemblance to an actual drone. When flying, drones tilt towards the direction they are going, aiming the propulsion in the opposite direction. In order to achieve this in the game, we can adjust the GameObject's rotation property based on the movement input. In this case, the transform.Rotate function won't work. We will use the Quaternion.Slerp function, that smoothly interpolates between the current rotation of an object and a defined target rotation.

public int tiltDelay = 8;
Quaternion inclinationTarget = Quaternion.Euler(normalizedInputVector.z * drone.tilt, transform.localEulerAngles.y, -normalizedInputVector.x * drone.tilt);
droneModel.transform.rotation = Quaternion.Slerp(droneModel.transform.rotation, inclinationTarget, Time.deltaTime * tiltDelay);

For this, we have two additional variables to take into account:
  • drone.tilt: This drone property defines the strength of the inclination, giving us the possibility of defining stronger tilts for faster drones.
  • tiltDelay: Allows us to adjust how fast the drone changes its inclination based on the input. We don't want it to be immediate nor too slow. I played with this value until I achieved a nice result.
And this sums it up for the basics of the drone controls in the game. Remember you can download the released game in Google Play: https://play.google.com/store/apps/details?id=com.JorgeFernandez.DroneSimulator.

Thanks for reading! I hope you enjoyed. See you in the next one!

Comments