Made for: ARU 1st Year – Semester 2
Duration: 3 Months
Engine: Unity 2017.3.1f1
Language: C#
Position: Solo
Brief:
“Create a game in unity without using standard rigidbody physics and other specified functions.”
For this project I was marked on the amount of physics concepts I could implement in Unity. Since the game itself needed to showcase the use of these concepts as best as possible, I opted to make a simulation of flying a plane. From there I could use that system the generate gameplay in a way that both incorporated more concepts and tested my knowledge of Unity.
The Plane
Using input from a controller, forces are applied to calculate the acceleration of the plane. This attribute consists of linear and angular components which are converted to velocities that are then limited by drag. These values are fed to the rigidbody itself to make it move. To clarify, we weren’t allowed to have the rigidbody do its thing by itself by adding forces directly, we had to calculate the value of velocity and assign it instead.

There are 10 forces in total acting on the plane, half of which are calculated from input. The rest (excluding gravity) are used to make the flying feel more fun by giving the plane more momentum in certain situations. This input and application of forces can be seen in the code below:
// Recieve joystick input
InputVector = new Vector2(Input.GetAxis("Horizontal"), (Input.GetAxis("Vertical")));
// Apply left and right roll forces based on horizontal input
AddForce(transform.rotation * LeftLift * -InputVector.x, Position + transform.rotation * new Vector3(-2, 0));
AddForce(transform.rotation * RightLift * InputVector.x, Position + transform.rotation * new Vector3(2, 0));
// Apply pitch force based on vertical input
AddForce(transform.rotation * BackLift * -InputVector.y, Position + transform.rotation * new Vector3(0, 0, -2));
// Apply left and right yaw forces based on bumper inputs
if (Input.GetKey("joystick 1 button 4"))
AddForce(transform.rotation * -RudderLift, Position + transform.rotation * new Vector3(0, 0, -5));
if (Input.GetKey("joystick 1 button 5"))
AddForce(transform.rotation * RudderLift, Position + transform.rotation * new Vector3(0, 0, -5));
// Apply lift
AddForce(transform.rotation * CentreLift, Position + transform.rotation * new Vector3(0, 0, 2));
// Adjust yaw by roll
AddForce(ForceByRoll * -Roll, Position + new Vector3(0, 0, -1));
// Appy thrust
AddForce(transform.forward * Thrust, Position);
// Apply gravity
AddForce(GravityVector * GravityScale, Position + transform.rotation * new Vector3(0, 0, -0.05f));
// Evaluate and apply extra momentum to make flight feel more weighted
if (Pitch > 0)
{
ExtraMomentum.y -= Pitch * 1f * Time.deltaTime;
}
else if (Pitch < 0)
{
if (ExtraMomentum.y < 0)
{
ExtraMomentum.y += Pitch * 2f * Time.deltaTime;
}
}
ExtraMomentum.y = Mathf.Clamp(ExtraMomentum.y, -15f, 5f);
AddForce(ExtraMomentum, Position);
// Calculate acceleration (a = f/m), reset force to be recalulated on next tick
Acceleration = Force / Mass;
Force = Vector3.zero;
// Apply linear velocity and drag
LinearVelocity += Acceleration * Time.deltaTime;
LinearVelocity *= 1 / (1 + LinearDrag * Time.deltaTime);
// Set the velocity of the rigidbody to the calculated linear velocity
RBComponent.velocity = LinearVelocity;
// Apply angular velocity and drag
AngularVelocity += Torque / Mass;
AngularVelocity *= 1 / (1 + (AngularDrag + (AngularDragBySpeed * LinearVelocity.magnitude)) * Time.deltaTime);
// Set the angular of the rigidbody to the calculated angular velocity, reset torque to be recalulated on next tick
RBComponent.angularVelocity = AngularVelocity;
Torque = Vector3.zero;
The Game
To generate some gameplay from the plane movement I added weapons, enemies and a lighthouse that the player has to defend. The enemies spawn endlessly from the air and sea, slowly approaching the lighthouse. The player gains points by destroying enemies since this way an element we were marked on. Once is lighthouse is destroyed, the game ends.

Enemies
With the same basic template that the plane employs, the enemies use forces to navigate the environment. If a target is within range, they will slow down and try to face perpendicular to it. Three enemies exist in the game: the warship, airship and bulwark.







Each enemy is decked out with cannons that fire unique ordinance designed to destroy their target.

Once all of these turrets are destroyed, the parent enemy dies and drops a pickup for health or ammo.

The bulwark acts a bit differently by having a gravity cannon that can only be destroyed by shooting canisters located on the body of the ship in addition to its many other basic cannons. It launches a homing projectile that spawns many gravity wells on detonation. Each well attracts and damages the player if they get close.

When this enemy gets destroyed, it explodes and consumes itself.
More Physics
In total I implemented 12 concepts, 10 of which were defined in the specification:
- Distance
- Displacement
- Velocity
- Acceleration
- Gravity
- Drag
- Simple harmonic motion
- Projectile motion
- Uniform circular motion
- Buoyancy
- Gravitational / Attraction forces
Most objects that use physics have the same velocity calculation component that the plane uses. Half the concepts are already covered in this process, the others are simply adding custom forces before the calculation.
Object Pooling
Bullets, enemies, missiles, explosions and many more objects were pooled in order to keep the frame-rate up. Instantiating was fine for earlier projects in Unity since the objects being spawned were relatively simple and few in number. In this case, hundreds of bullets could be on screen at any one time and enemies consisting of multiple individually aiming turrets each with their own effects had to be constantly created. I used a system that activates and deactivates these objects instead and queued up expensive objects at the beginning so they would never need to be instantiated.
UI
In game UI was intentionally kept simple to provide all the information the player would need – score, ammo, plane health, lighthouse health.

I also gave the mini-map a go since its not something I had tried before. The hardest part of getting it to work was adding indicators to the borders if enemies were outside of it. I made it a lot harder for myself by designing the mini-map to be square and rotate its contents relative to the player.

A simple main menu and pause menu are included as specified in the marking criteria.


All the 3D assets were created using Pro-Builder. I initially made all the turrets out of basic Unity shapes (cubes, cylinders, etc.) but that got way too expensive once I started putting them on enemies due to the number of objects making up each turret. Getting to grips with Pro-Builder allowed me to reduce that number to about 5-12 each.
I also used the official V2 post processing stack provided on the asset store. Anti-Aliasing and motion blur made a huge improvement to how the game looked with little effort on my behalf.
Vector graphics were made in Inkscape and pixel art in Aseprite.