Adding ship firing was supposed to be easy: Just instantiate a bullet prefab at the location of the gun, set the direction to match the gun’s rotation, and then apply a force. But something was bothering me – the bullet looked like it was flying off at an angle every time. It turns out if your camera is set up to follow an object, anything that moves in a straight direction from that object will appear to fly off at an angle as long as the object is moving.

The solution? Add the moving object (gun) momentum to the bullet.

The Setup

I have a ship object with several child objects. One of these is the spaceship sprite, and another is an empty game object whose transform is positioned on the ship’s gun.

Attached to the PlayerShip parent object is a FireProjectile class, which is attached to every object in the game that could fire a projectile:

using UnityEngine; using System.Collections; public class FireProjectile : MonoBehaviour { // Where the projectile should spawn from. [SerializeField] Transform gunMount; // The projectile prefab. [SerializeField] Rigidbody2D projectile; // The parent transform for the projectiles. [SerializeField] Transform ProjectilesParent; [SerializeField] bool debugRay = false; public void Fire(float speed , Vector3 direction) { Rigidbody2D shot; shot = (Rigidbody2D)Instantiate(projectile, gunMount.position, gunMount.rotation); shot.AddForce((gunMount.up + direction) * speed); // Set shot parent if (ProjectilesParent != null) shot.transform.parent = ProjectilesParent; // Debug raycasting if (debugRay) Debug.DrawRay(transform.position, (gunMount.up + direction) * speed, Color.red, 5.0f); } }

Each object that fires bullets has its own ProjectilesParent object:

Each object that is a ProjectilesParent has a FollowTarget script that forces the parent object to match the target’s transform position, which makes the bullet appear to fly in a straight line instead of at an angle due to the camera being centered on an object that is moving.

The FollowTarget script:

using UnityEngine; using System.Collections; // Follows target position public class FollowTarget : MonoBehaviour { // Control parameters [SerializeField] Transform target; // Executed each physics simulation frame void FixedUpdate () { transform.position = target.position; } }

In a nutshell, here is what is happening:

Projectiles are being instantiated like normal.

Projectiles, upon instantiation, are parented to an empty game object.

The empty game object’s transform is set to match the ship’s transform every FixedUpdate(), which causes projectiles to match the ship’s momentum instead of ignoring it.

As you may have noticed, this is not ideal for all weapons – only for those that need to also have the firing object’s momentum, which generally includes all projectiles.

The Result