Multiple shooters
Fire player and AI shots with independent origins, zeroing, masks and ownership.
Keep one configured SniperAndBallisticsSystem in the scene. Each weapon supplies a BulletShotParameters value when it fires. Multiple shots can share the same bullet asset and remain in flight together.
Fire from your own weapon
Add WeaponShooter.cs to each character's root, assign its muzzle and bullet asset, and set its collision layers. Call Fire() from your input, animation event or AI after Start has initialized it. This example uses zero distance 0; add any nonzero ranges to the system's Zero Distances before activation.
using IE.RSB;
using UnityEngine;
public sealed class WeaponShooter : MonoBehaviour
{
[SerializeField] private Transform muzzle;
[SerializeField] private BulletProperties bulletProperties;
[SerializeField] private LayerMask hitLayers = Physics.DefaultRaycastLayers;
[SerializeField, Min(0f)] private float zeroDistance;
private SniperAndBallisticsSystem system;
private void Start()
{
system = SniperAndBallisticsSystem.instance;
system.ActivateBullet(bulletProperties);
}
public long Fire()
{
var shot = new BulletShotParameters(muzzle.position, muzzle.forward)
{
Shooter = gameObject,
ZeroDistance = zeroDistance,
RayMask = hitLayers
};
return system.FireBallisticsBullet(bulletProperties, shot);
}
}The return value is a positive shot ID, or 0 if firing was rejected. Your weapon decides when to consume ammunition or start a cooldown. Invalid requests log an error; rejection during global bullet time is silent.
The supplied Shooter should be the character root whose hierarchy contains its colliders. Those colliders are ignored by default. Set AllowSelfHits = true if your game wants self-collisions, including ricochets. This filtering does not change layers or disable colliders, and does not implement team filtering. Detached colliders are no longer in the shooter's hierarchy.
Independent settings
Position, normalized direction, zeroing angle and collision mask are captured at firing. Changing another weapon's aim, the request struct, or the scene system's Fire Transform, mask or selected zero distance does not redirect shots already in flight.
ZeroDistance = null captures the current scene selection; 0 disables zeroing compensation. Nonzero distances must be prepared on the bullet asset, normally by adding them to the system list before ActivateBullet. Different shooters may select different prepared distances on the same bullet.
RayMask = null captures the system's mask. An explicit zero mask hits nothing. Both forward casts and penetration exit casts use the shot mask. Trigger queries still follow Physics.queriesHitTriggers.
The scene environment, tracer/debug settings and bullet assets remain shared. Treat bullet properties and damage profiles as configuration during play: they are referenced rather than copied into each shot.
Identify impacts
Subscribe to hit events. Each BulletPoint carries m_shotId, m_shooter, m_shotOrigin and m_shotDirection, along with m_properties, m_hitCollider and m_hitRigidbody.
One shot keeps its ID through penetration, ricochet, bullet-time prediction, replay and fallback to ordinary simulation. Use the collider for the exact child hitbox and its attached rigidbody for physics effects. m_hitTransform retains the older behavior and may identify a rigidbody parent.
IDs are local to the running process/domain, not persistent save-game or network IDs. The shooter reference becomes null if its GameObject is destroyed. Events can occur during the firing call, especially bullet-time start; read IDs from event records rather than assuming your local return-value variable has already been assigned.
Bullet time and compatibility
Per-shot requests default to AllowBulletTime = false. To request a cinematic, set it to true and supply BulletTimeBullet; see Firing with bullet time.
Bullet time changes the global timescale and blocks new shots from both firing APIs while running. Disable UseBulletTime for uninterrupted simultaneous combat. Per-shot ownership provides local integration; networking and authority remain your game's responsibility.
Existing FireBallisticsBullet(properties, ...) calls still work through the configured Fire Transform and global defaults. They produce shot IDs with a null shooter. The bundled player controller continues to use that API; use the new overload in your own controller when you need ownership. See BulletShotParameters for all options.