os.Ballistics Quick Start
This page serves as a quick start reference document regarding os.Ballistics - a physics-based bullet ballistics system for Unity.
os.Ballistics is organized into three namespaces:
Runtime is the primary namespace that you will interact with. You can reference the Demo namespace to understand usage patterns. You likely won’t need to interact with the Editor namespace.
Major Data Types
os.Ballistics also includes three primary classes of data that you will want to familiarize yourself with:
Projectiles, Environment, and SimulationConfigs can all be created as Scriptable Object assets by designers ahead of time, or they can be created or modified in code during gameplay.
Projectile describes a ballistics projectile, including characteristics such as Origin, Direction, Muzzle Velocity, Initial Kinetic Energy, Mass, etc. When you instantiate a projectile, you will likely want to call Projectile.SetOriginAndDirection(Vector3 origin, Vector3 direction) to initialize these fields before passing along to the simulation. Some of these characteristics are calculated automatically (e.g., Initial Kinetic Energy), but most are expected as inputs.
Environment describes a set of Environment Conditions, including characteristics such as Gravity, Atmospheric Pressure, Humidity, Temperature, Air Density, etc. Some of these characteristics are calculated automatically (e.g., Air Density), and others are expected as inputs (e.g., Humidity, Temperature)
SimulationConfig describes the nature of the simulation that should be executed, including characteristics such as Maximum Simulation Distance and Simulation Timestep.
Primary Usage Details
Runtime contains one public static method you may want to interact with:
Usage: When called, this method will execute an instantaneous simulation of the projectile and return back a BallisticsPrediction. Expect BallisticsPrediction to return null if the Prediction was unable to run. If the BallisticsPrediction is not null, you can check the BallisticsPrediction.BallisticsHitData.DidHit boolean to understand whether the ballistics system determined that a collision would occur. Expect BallisticsPrediction.HitInfo to be populated only when DidHit is true.
The BallisticsCore.Predict method should generally be called by the artillery piece itself rather than the projectile. It can be used to estimate approximate point of impact or to draw trajectories before actually shooting. Note that the prediction is calculated using the physics simulation in place at the time of the prediction. However, the bullet would take real time to travel, but the global physics simulation is not interpolated forward in any way.
What does this mean? In short, you cannot use the BallisticsCore.Predict method to determine whether a moving enemy would be hit along this trajectory in the future.
You will also want to set particular Game Objects as BallisticsProjectiles. You will use class inheritance for this. On your bullet prefab, open your primary handling script. Change the inheritance from MonoBehaviour to BallisticsProjectile.
The BallisticsProjectile base class includes the Simulate(); method, which is the realtime version of the BallisticsCore.Predict() method mentioned above. You want to iniherit from BallisticsProjectile and call the Simulate(); method for projectiles that should have join the realtime ballistics simulation.
protected IEnumerator Simulate();
Simulate uses fields in the BallisticsProjectile class to execute the simulation. Explore the BallisticsProjectile base class to understand these fields in more detail. At a high level, these are:
- protected System.Action<BallisticsHitData> onBallisticsComplete;
- protected System.Action<Kinematics> onBallisticsUpdate;
- protected ProjectileSO projectileSO;
- protected EnvironmentSO environmentSO;
- protected SimulationConfigSO simulationStateSO;
- public Projectile Projectile;
- public Environment Environment;
- public SimulationConfig SimulationConfig;
Generally, the Projectile, Environment, and SimulationConfig will be automatically set based on the Scriptable Objects set in the inspector for the projectileSO, environmentSO, and simulationSO fields. However, you can manually override these values with runtime ones by simply setting them.
Simulate runs as a Coroutine. Data from this coroutine can be passed back via callbacks to methods using the onBallisticsUpdate and onBallisticsComplete actions.
onBallisticsUpdate will trigger a callback every execution of the coroutine except for the final one.
onBallisticsComplete will trigger a callback on the final frame of execution of the coroutine.
- Create a new empty Game Object. Call it Bullet.
- Create a script and attach it to your Bullet. Call this script BulletManager.
- Write a using declaration at the top of the script, using OccaSoftware.Ballistics.Runtime.
- Change the inheritance for BulletManager from MonoBehaviour to BallisticsProjectile.
- In your Start method, call the Projectile.SetPositionAndDirection(Vector3 position, Vector3 direction) method, passing in the transform.position and transform.forward for the Bullet game object.
- Create a new method, call it private void GetSimResults(BallisticsHitData ballisticsHitData).
- From the Start method, subscribe your GetSimResults method to the onBallisticsComplete callback by writing onBallisticsComplete += GetSimResults.
- Also, call your coroutine with StartCoroutine(Simulate());
- Finally, clean up after yourself in your GetSimResults method by unsubscribing from the callback and discarding the game object.
- You need to create Projectile, Environment, and SimulationConfig assets, and then drag and drop these assets into the corresponding fields in the Bullet inspector window.
- You can create these assets by right clicking in project window, then going to
- Create -> Ballistics -> Projectile,
- Create -> Ballistics -> Environment, and
- Create -> Ballistics -> SimulationConfig
Here’s an example of the final class.
When instantiated, the bullet’s transform will follow the path of the simulated trajectory and will write a debug log when it hits a collider in the path. See the gist below for an example of this class.