A comprehensive, physically-accurate ballistics simulation system for Unity that provides realistic trajectories, ricochets, penetration mechanics, and advanced ballistic effects for games requiring authentic projectile behavior.
✅ Realistic Ballistics Simulation: Accurate trajectories with proper physics for FPS, military, hunting, …
✅ Material Penetration: Realistic projectile behavior through different materials (wood, metal, concrete, etc).
✅ Ricochet Effects: Physically-based bullet deflection off surfaces .
✅ Long-Range Shooting: Precision ballistics for sniper games with environmental factors.
✅ Performance-Critical Games: Optimized for handling thousands of simultaneous projectiles.
❌ FPS Controller: While it includes a SimpleFPS
system, it’s designed for ballistics simulation, not as a FPS character controller.
❌ Visual Effects System: Focuses on physics simulation rather than muzzle flashes, explosions, or other visual effects.
❌ Weapon Animation System: Doesn’t handle weapon animations, reloading animations, or complex weapon mechanics.
❌ Audio System: Doesn’t provide comprehensive audio management beyond basic demo sounds.
❌ Networking Solution: Designed for single-player simulations, not multiplayer networking.
❌ Energy Weapons or Propelled Projectiles: Designed for ballistic projectiles only, doesn’t support laser weapons, plasma guns, or self-propelled projectiles like rockets and missiles.
Requirements:
Installation:
True Ballistics
asset from the Unity Asset Store into your Unity project.The BallisticsManager
component is the central hub of the ballistics system. It manages the lightweight ECS, handles projectile spawning, and coordinates all ballistic systems.
Create an empty GameObject and add the BallisticsManager
component (Fronkon Games → True Ballistics → Ballistics Manager)
Systems are modules that take care of a task. You can add as many as you want in Systems
, this way you will only use the ones you need.
They are ScriptableObjects and therefore files. You can create them from the Project
window (Fronkon Games → True Ballistics → Systems)
All the systems included are discussed in more detail below. The minimum recommended systems are:
Once these three systems are added, you can fire a projectile in this way:
// Get the manager instance
BallisticsManager manager = FindFirstObjectByType<BallisticsManager>();
// Spawn a projectile
int projectileEntity = manager.SpawnProjectile(
weaponData, // WeaponData ScriptableObject
transform.position, // Spawn position
transform.rotation, // Spawn rotation
1.0f, // Dispersion multiplier
true, // Can jam
1.0f // Velocity multiplier
);
// Spawn pellets (for shotguns)
List<int> pellets = manager.SpawnPellets(
weaponData, // WeaponData ScriptableObject
shellData, // ShellData ScriptableObject
transform.position, // Spawn position
transform.rotation // Spawn rotation
);
weaponData
is another ScriptableObject (a file) with all the relevant data of a weapon model. You have more than 380 in the FronkonGames/TrueBallistics/Data/Weapons
folder.
In the case of shotguns, in addition to the corresponding weaponData
, you must add shellData
, the type of cartridge you want to use. You can find several in FronkonGames/TrueBallistics/Data/Ammo
.
You can create new weapons (and shells) from the Project
window (Fronkon Games → True Ballistics → Weapon Data / Fronkon Games → True Ballistics → Shell Data).
True Ballistics
uses a custom lightweight ECS architecture optimized for ballistics simulation:
Handles core ballistics physics including gravity, drag, and atmospheric effects. Without this system the projectiles would not move.
Features:
Configuration:
Gravity
: Gravity vector (default: Earth’s 9.81 m/s²).
Air Density
: Air density in kg/m³ (default value is 1.225 kg/m³ at sea level).
Speed Of Sound
: Speed of sound for Mach calculations (default value is 343 m/s at sea level).
Max Speed
: Maximum projectile velocity in m/s (default value is 299,792,458 m/s, the speed of light in vacuum).If you add Debug System
to the system list, you will be able to see the trajectories of the projectiles in the Scene
window.
The trajectory of the projectile will have these colors:
Color | Initial Velocity |
---|---|
Red | >=75% |
Orange | >=50% |
Yellow | >=25% |
Green | >=10% |
Gray | <10% |
In general, impacts in Green or Gray are not lethal.
Manages projectile lifecycle with configurable termination rules. It is essential to add this system, since it is in charge of recycling projectiles. Without this system, when the maximum number of projectiles is reached (5000 by default), no more can be created.
If any of the following (active) rules are met, the projectile is deactivated.
Deactivates the projectile if its lifetime has exceeded a certain limit.
Deactivates the projectile if its speed is below a certain percentage.
Deactivates the projectile if its coordinates are less than a certain limit.
Deactivates the projectile if its coordinates are greater than a certain limit.
Deactivates the projectile if it has been stationary for a certain amount of time.
Deactivates the projectile if it has traveled a certain linear distance from its point of origin.
Deactivates the projectile after its first collision.
If you use the Ricochet System
, a bouncing projectile does not count for this rule.
Deactivates the projectile if a ricochet occurred with an angle lower than a certain limit.
If true, projectiles are deactivated upon any impact that does not result in a ricochet. This overrides One Collision Rule
if both are true.
Efficient collision detection with adaptive algorithms. Remember that for a projectile to collide with an object on the stage, this object must have some kind of Collider.
Features:
Configuration:
Layer Mask
: Collision layers.High Speed Threshold
: Percentage of the speed of light (default 10%) at which RayCast is used instead of SphereCast (the projectile is considered instantaneous).Once added to the systems, you can subscribe to the OnProjectileHit
events to receive information on each impact.
// Cache all colliders on this object and its children for efficient hit detection
colliders = this.GetComponentsInChildren<Collider>();
// Get the manager instance
BallisticsManager manager = FindFirstObjectByType<BallisticsManager>();
// Subscribe to projectile hit event (don't forget to unsubscribe)
ballisticsManager.OnProjectileHit += OnProjectileHitHandler;
...
private void OnProjectileHitHandler(CollisionInfo info)
{
// Skip processing if collision info is invalid
if (info.collider == null)
return;
// Check if the hit collider belongs to this object (or any of its children)
foreach (Collider c in colliders)
{
if (c != null && info.collider == c)
{
// Doing something
break;
}
}
}
Check these classes in FronkonGames/TrueBallistics/Demos/Scripts
for more examples:
If you add Debug System
to the system list, you will be able to see the impacts of the projectiles (a circle with a diagonal cross) in the Scene
window.
Objects with Colliders and physics (RigidBody) do not receive any physical impulse when hitting a projectile (it is not the goal of this library). However you can consult the RigidBodyManager
class to see an example of how to do it.
Neither create bullet marks or particles at the point of impact, although you can see how this is done in the demo in the HolesManager
and SparksManager
classes. Both solutions are quite rudimentary (enough for the purposes of the demo) so I do not recommend using them in production environments.
Realistic ricochet simulation based on impact angle and material properties.
Features:
Once added to the systems, you can subscribe to the OnProjectileRicochet
events to receive information on each ricochet. If you use Collision System
, an OnProjectileHit
event will also be emitted.
If you add Debug System
to the system list, you will be able to see the ricochets (a square with an arrow indicating rebound) in the Scene
window.
Advanced penetration mechanics with energy-based calculations and materials.
Features:
Configuration:
Layer Mask
: Layers considered for penetration raycasts.Energy Scale
: Scaling factor applied to material strength when computing required energy. Lower than 1.0 will make the projectile more likely to penetrate.Max Entry Deflection Angle
: Maximum angle in degrees by which a projectile’s path can be deflected upon entering a surface, based on incidence angle.This system (and actually Collision and Ricochet) uses Ballistic Material
for its calculations. If you do not assign any material to the objects, it will use Default Material
from Ballistic Manager
(see above). If you do not assign any, the ‘Concrete’ material will be used.
In the FronkonGames/TrueBallistics/Data/Materials
folder you have a few materials already defined. You can also create your own (they are ScriptableObjects) from the Project
window and using the menu Fronkon Games → True Ballistics → Material Data
.
Configuration:
Description
: Description of the material.Min Angle For Ricochet Prob
: Angle (degrees) from surface normal. Impacts at angles greater than this (grazing angles) have increasing ricochet probability.Guaranteed Ricochet Angle
: Angle (degrees) from surface normal. Impacts at angles greater than this (very grazing angles) will always ricochet if probability is met.Ricochet Probability Curve
: Curve defining ricochet probability (Y-axis, 0-1) based on impact angle with surface normal (X-axis, 0-90 degrees). Higher angles = more grazing.Restitution Normal
: Coefficient of restitution for the velocity component normal to the surface (0 = no bounce, 1 = perfect bounce).Restitution Tangent
: Coefficient of restitution for the velocity component tangential to the surface (0 = sticks, 1 = no friction).Energy Retention Factor
: Overall percentage of kinetic energy retained after ricochet (0 = all lost, 1 = all retained). Applied AFTER restitution effects if both are used conceptually.Density
: Density of the material in kg/m^3. Used for penetration calculations.Yield Strength
: Yield strength of the material in MPa. Higher values resist penetration.Add the Ballistic Material
component to the objects you want to specify a material. Remember that they must be at the same level as the collider that detects the impact.
In Ballistic Material
you can activate Use Material Cache
to improve performance, but note that if you do so, you will not be able to change at runtime the material of the objects.
Three events related to projectile penetration are use:
If you add Debug System
to the system list, you will be able to see the the entry point (a circle with a vertical cross), the trajectory (in cyan color) and the exit point (a circle with a vertical cross).
If the projectile gets stuck inside the object, you will see its trajectory (in magenta) and the point where the projectile is (magenta circle with vertical cross).
Some considerations:
GPU-accelerated visual tracer rendering.
Features:
Environmental effects simulation using ICAO Standard Atmosphere.
Features:
Configuration:
altitude
: Altitude in meters.temperature
: Temperature in Celsius.wind
: Wind vector in m/s.precipitation
: Precipitation intensity (0-1).Coriolis effect simulation for long-range ballistics.
Features:
Configuration:
planetAngularVelocity
: Planet rotation rate.latitude
: Observer latitude.Spin-induced projectile drift for long-range simulation.
Features:
Configuration:
driftFactor
: Overall drift scaling.Comprehensive debug visualization (Editor only).
Features:
Creating a custom system involves inheriting from SystemBase
and implementing the required methods:
[CreateAssetMenu(fileName = "CustomSystem", menuName = "My Game/Custom System")]
public class CustomSystem : SystemBase
{
// Execution order (lower = earlier)
public override int ExecutionOrder => 1500;
// System initialization
public override void Initialize(BallisticsManager manager)
{
base.Initialize(manager);
// Setup system resources
}
// Called before physics update
public override void PreTick(float deltaTime)
{
if (!active) return;
// Pre-physics logic
}
// Main system update
public override void Tick(float deltaTime)
{
if (!active) return;
// Main system logic
}
// Called after physics update
public override void PostTick(float deltaTime)
{
if (!active) return;
// Post-physics logic
}
// System cleanup
public override void DeInitialize()
{
// Cleanup resources
base.DeInitialize();
}
}
Example: Simple Gravity Well System
[CreateAssetMenu(fileName = "GravityWellSystem", menuName = "My Game/Gravity Well System")]
public class GravityWellSystem : SystemBase
{
[Header("Gravity Well Settings")]
public Transform gravityWellCenter;
public float gravityWellStrength = 10f;
public float gravityWellRadius = 50f;
public override int ExecutionOrder => SystemExecution.Physics + 50; // After PhysicsSystem
public override void PostTick(float deltaTime)
{
if (!active || gravityWellCenter == null) return;
// Get component arrays
var physicsComponents = manager.GetComponentArray<PhysicsComponent>();
// Process all entities with physics components
for (int i = 0; i < BallisticsManager.MaxEntities; i++)
{
if (!manager.entities[i]) continue;
ref var physics = ref physicsComponents[i];
// Calculate distance to gravity well
Vector3 toWell = gravityWellCenter.position - physics.position;
float distance = toWell.magnitude;
// Apply gravity well force if within radius
if (distance < gravityWellRadius && distance > 0.1f)
{
float force = gravityWellStrength / (distance * distance);
Vector3 gravityForce = toWell.normalized * force * physics.mass;
// Apply force
physics.velocity += gravityForce * deltaTime / physics.mass;
}
}
}
}
SimpleFPS
is an educational first-person controller demo that showcases True Ballistics
integration. It’s designed for learning and prototyping, not production use.
SimpleFPSEvents
for decoupled communicationSimpleFPSDependencyContainer
automatically subscribes methods✅ Use for: Learning, prototyping, testing weapon configurations
❌ Don’t use for: Production games, complex gameplay systems
Do you have any problem or any suggestions? Send me an email to fronkongames@gmail.com and I’ll be happy to help you.
Remember that if you want to inform me of an error, it would help me if you sent to me the log file.
If you are happy with this asset, consider write a review in the store
❤️ thanks! ❤️