Projectile
A Projectile gives a Shootable Action a physical shot with visible travel time, gravity, collision volume, and its own lifetime. Use it for a rocket, arrow, grenade-launcher round, or slow energy bolt; use Hitscan instead when the hit should resolve immediately without a moving object.
Before you begin
- Create a Shootable Action with Projectile Shooter, Spawn Projectile, and the intended Shootable Impact modules.
- Prepare a visible projectile model. For a rocket that explodes, also prepare a separate Explosion prefab.
- Decide whether the Shootable Action’s Impact Module Group or the Projectile prefab’s Internal Impact group owns damage and effects. Configure one primary path to avoid duplicate results.
- Decide whether the shot should destruct, stick, bounce, or pass through on contact before configuring its collision and cleanup.
Build the projectile prefab
- Open Tools > Opsive > Ultimate Character Controller > Object Manager.
- In Object Builder, enter a Name, set Object Type to Projectile, and assign the visible model to GameObject.
- Select Build Object, save the prefab under the project’s
Assetsfolder, and open the generated prefab. - Confirm that the root contains Rigidbody, Capsule Collider, and Projectile. Resize the Capsule Collider to the model, or replace it with a solid Sphere or Box Collider when that better represents the shot. Trigger colliders are ignored by Trajectory Object casts.
- Set Collision Mode to Collide for a normal one-hit projectile. Object Manager leaves the inherited Reflect value while Destroy On Collision starts enabled; ProjectileBase logs a warning and forces that conflicting combination to Collide during
Awake. - Keep Initialize On Enable disabled when Shootable or Magic modules launch the object. The released Version 3 movement defaults are Mass
1, Start Velocity Multiplier1, Gravity Magnitude9.8, Speed1, and movement plus rotation Damping0.1. - Configure Impact Layers and Surface Impact, then configure Default Impact Damage Data. Unless Use Object Impact Layer And Surface is enabled, initialization copies the layer mask and Surface Impact from that default data over the object-level values.
- For a Shootable Action that owns the gameplay hit, disable Internal Impact and configure Generic Shootable Impact on the item. Keep Internal Impact enabled only when the prefab’s own Impact Action Group is an intentional second or alternative result.
- For a one-hit shot, keep Destroy On Collision enabled and set Destruction Delay to
0. Lifespan defaults to10seconds and removes a missed projectile in this configuration. - Add optional prefabs under Spawned Objects On Destruction. Use Probability
1for a guaranteed Explosion or effect, and enable Random Spin only for a presentation object whose orientation may vary.
ProjectileBase makes the Rigidbody kinematic, disables Rigidbody gravity, and freezes its constraints. Trajectory Object owns the movement; do not tune the Rigidbody as though Unity physics launches the shot.
Connect the Shootable Action
- In Shooter Action Module Group, add Projectile Shooter and make it the first enabled Shooter.
- In Projectile Action Module Group, add Spawn Projectile and make it the first enabled Projectile module. Assign the prefab to its Projectile field; the
Projectilecomponent must be on the prefab root. - Assign Fire Point Location for every enabled perspective. Keep Use Look Source Position disabled to spawn there, or enable it for the Look Source position when the current Movement Type does not use independent look.
- Enable Fire In Look Source Direction for crosshair-directed fire. Leave it disabled when the Fire Point’s forward direction should aim the shot.
- Set Projectile Fire Velocity Magnitude. Its released Version 3 default is
10. Spread defaults to0.01, Fire Count to1, and Inherit Character Velocity is disabled. - Keep Projectile Fired Layer at VisualEffect only when that layer is correct for the project, and choose Layer Change Delay. Its default is
0. The Shooter’s Impact Layers aim and obstruction-check the shot; the Projectile prefab’s impact data and layers control the moving object’s actual hits. - Spawn Projectile > Projectile Visibility defaults to On Fire, so the object is created when fired. Choose On Aim, On Reload, or Always only when a loaded arrow or round should be visible before release. Projectile Start Layer defaults to Ignore Raycast for that attached state.
- Add Generic Shootable Impact and configure its Conditions plus pass and fail Impact Action Groups. The Projectile Shooter forwards the Projectile’s collision context to every enabled Shootable Impact module.
The launch velocity is Projectile Fire Velocity Magnitude multiplied by Trigger force, plus the character’s forward local velocity when Inherit Character Velocity is enabled. Trajectory Object then divides that velocity by the product of Mass and Start Velocity Multiplier before applying its gravity, speed, and damping.
Choose the contact result
| Goal | Configure | Cleanup behavior |
|---|---|---|
| Rocket or ordinary one-hit round | Collide, Destroy On Collision enabled, Destruction Delay 0 |
The hit invokes impacts, spawns destruction objects, and returns the Projectile immediately. |
| Delay an explosion after impact | Collide, Destroy On Collision enabled, positive Destruction Delay | The Projectile stays until the delay expires; its Collider is disabled on impact by default. |
| Arrow that follows a target | Collide, Destroy On Collision disabled, include the target in Sticky Layers, and use a positive Destruction Delay or project cleanup | A uniform-scale target becomes the parent. The first hit cancels the normal Lifespan, so cleanup must be explicit. |
| Bouncing shot | Reflect or Random Reflect, Destroy On Collision disabled | Add project-owned cleanup. The first hit cancels Projectile’s Lifespan; a positive Destruction Delay instead counts from that first bounce. |
| Pass-through detector | Ignore, Destroy On Collision disabled | Add project-owned cleanup and hit filtering. Contacts are reported without changing velocity, but the built-in Lifespan does not destroy this zero-delay configuration. |
| Let a root Particle System finish after stopping emission | Wait For Particle Stop enabled | On impact or Lifespan, emission and movement stop and destruction waits for the root Particle System’s main Duration. This value replaces, rather than adds to, Destruction Delay. |
Sticky Layers is used only in Collide mode. A uniform-scale hit outside that mask forces destruction even when Destroy On Collision is disabled. A nonuniform target cannot become the parent, so a stopped arrow will not follow it.
Disable Collider On Impact starts enabled. That suits a one-hit or stuck shot. Disable it for a bouncing or pass-through design only when later Collider-based interactions must remain active; the trajectory simulator continues using its cached shape for casts.
How it runs
- Spawn Projectile obtains the prefab from
ObjectPoolBaseat fire time, or prepares it earlier when Projectile Visibility shows a loaded object. - Projectile Shooter reads the current clip round, calculates the Fire Point and direction, and obtains the object from Spawn Projectile. A pre-spawned object is linecast from the Look Source to prevent separate first-person arms from placing it through an obstruction.
- The Shooter changes the hierarchy to Projectile Fired Layer after Layer Change Delay, then initializes the root Projectile with velocity, Trigger force, Shootable Action ownership, and the prefab’s Default Impact Damage Data.
- Projectile schedules Lifespan, enables its Collider and trajectory simulation, starts active audio or particles, and ignores its owner’s hierarchy during trajectory casts.
- A hit runs shared collision and surface feedback. Projectile Shooter forwards the context to the Shootable Action’s Impact Module Group; ProjectileBase then runs its local group when Internal Impact is enabled.
- The first hit cancels the scheduled Lifespan. Collision mode changes movement, while destruction settings decide whether and when the object spawns its configured results and returns through the local or network pool.
- A shot that never hits reaches Lifespan. With Destroy On Collision enabled, this uses the same destruction path without a RaycastHit and returns the object.
Editor checkpoint
Before Play Mode, confirm that:
- Rigidbody, Projectile, and one supported solid Collider are on the prefab root;
- Initialize On Enable is disabled and Mass, Start Velocity Multiplier, and Lifespan are positive;
- Collision Mode, Sticky Layers, Destroy On Collision, Destruction Delay, and Wait For Particle Stop form one coherent contact and cleanup policy;
- Default Impact Damage Data, its layer mask, and Use Object Impact Layer And Surface match the intended targets and feedback;
- Internal Impact is disabled when Generic Shootable Impact owns damage and effects;
- Projectile Shooter and Spawn Projectile are the first enabled modules in their groups, and the Projectile field references this prefab;
- every perspective has a valid Fire Point Location, and look direction, velocity, fired layer, spread, Fire Count, and inherited velocity are intentional; and
- a pre-spawned projectile has the correct visibility, start layer, reload attachment, and animation-event or duration timing.
Verify with a firearm in Play Mode
- Equip the firearm or launcher, expand the Shootable Action’s Debug section, and fire one round. Confirm one Projectile appears at the active perspective’s Fire Point and the clip decreases by one.
- Compare Fire Point direction with Fire In Look Source Direction enabled and disabled. Confirm velocity, Trigger force, character movement inheritance, spread, and gravity produce the intended path.
- Hit a target on an included layer. Confirm Generic Shootable Impact runs exactly once, applies the intended damage and surface result, and the Projectile follows its one-hit, delayed, or sticky policy.
- Fire at an excluded layer and a trigger-only collider. Confirm the moving Projectile does not report those contacts even when the Shooter’s aiming mask includes nearby scenery.
- Miss every target. Confirm the Projectile returns to its pool after Lifespan.
- Test an arrow against a uniform moving target and a nonuniform target. Confirm only the supported target becomes its parent, and verify the explicit delayed or project-owned cleanup.
- Reuse the same prefab repeatedly. Confirm its Collider, parent, layer, particles, trail, impact state, ownership, position, and lifespan reset before every shot.
- With multiplayer enabled, repeat as owner, server, and observer. Confirm one authoritative impact and destruction result, one remote visual, and correct network-pool return.
Troubleshooting and released-Version-3 limitations
| Symptom | Check | Fix |
|---|---|---|
| The projectile is null, does not move, or throws when fired | Projectile Shooter is paired with Basic Projectile, Spawn Projectile > Projectile is empty, or the prefab lacks Projectile on its root. |
Pair Projectile Shooter with Spawn Projectile, assign the prefab, and keep Projectile on the root. |
| A generated Projectile logs a collision warning and changes to Collide | Object Manager left Collision Mode Reflect while Destroy On Collision starts enabled. | Set Collide explicitly for a one-hit shot. Disable collision destruction only with a tested alternative cleanup policy. |
| The shot hits the wrong layers | Shooter Impact Layers are being treated as the flight collision mask, or prefab Impact Layers are overwritten at initialization. | Use the Shooter mask for aiming and pre-spawn obstruction; configure Default Impact Damage Data and Use Object Impact Layer And Surface for the moving Projectile. |
| Damage or effects occur twice | Generic Shootable Impact and Projectile Internal Impact both contain gameplay actions. | Choose one result owner, normally Generic Shootable Impact, and disable the other path. |
OnObjectImpact never arrives |
The legacy workflow assumed every collision emitted the event. Released Version 3 sends it only when a configured Impact Action, such as Impact Event, invokes it. | Add the appropriate Impact Action and enable its source or target callback. Use Projectile’s C# OnImpact or On Collision Event for direct collision observation. |
| An arrow disappears instead of sticking | Destroy On Collision is enabled, the target layer is outside Sticky Layers, or Collision Mode is not Collide. | Disable collision destruction, use Collide, include the target layer, and test its scale and parenting. |
| A stuck arrow or bouncing shot never disappears | Its first hit canceled Projectile’s Lifespan and no destruction event was scheduled. | Give a stuck arrow a positive Destruction Delay, or add project-owned cleanup. For a timed bounce independent of first contact, use project-owned cleanup rather than Destruction Delay. |
| A stopped arrow does not follow the moving target | The target Transform has nonuniform scale, so ProjectileBase does not parent to it. | Use a uniform-scale attachment transform or handle attachment in project code. |
| The first bounce disables later collider interactions | Disable Collider On Impact remains enabled. | Disable it for a tested multi-contact setup when the Collider itself must remain active. |
| A pass-through Projectile never returns after Lifespan | Ignore, Destroy On Collision disabled, and zero Destruction Delay leave no destruction condition; any earlier contact also canceled Lifespan. | Return it from project code or use a one-hit configuration. A positive delay starts from the first contact, not from launch. |
| A spawned Explosion or effect is missing | Spawned Objects On Destruction is empty, its probability is below 1, or destruction never occurs. |
Assign the tested prefab, use probability 1 for a guaranteed result, and verify the Projectile’s cleanup path. |
| A delayed Explosion appears at the old impact point | Destruction was scheduled from a collision before the target moved. Released Version 3 retains that original RaycastHit point and normal. |
Use immediate destruction for that result, or implement project cleanup that spawns from the Projectile’s current Transform. |
| Wait For Particle Stop does not preserve a child effect | ProjectileBase searches only the Projectile root for Particle System and waits its main Duration; child systems and Trail Renderer lifetime are not included. | Put the coordinating Particle System on the root or use project-owned effect cleanup. |
| Projectile Enable Delay After Other Use has no effect | Projectile Shooter serializes the default 0.4 field but does not read it in released Version 3. |
Coordinate dual-item timing with Use Rate, animation events, or project code. |
| Weapon-source conditions fail only for moving projectiles | Projectile Shooter clears the direct Shootable Action reference before Check Weapon Source Category and Check Weapon Source Definition evaluate. | Avoid those filters unless Allow Non Weapon Impact matches the design; use projectile/target conditions or a project-fixed Shooter module. |
| A network shot duplicates or disappears | The prefab is not registered with the network pool or custom spawning also runs on observers. | Register the prefab with the installed integration, keep impacts authoritative, and do not independently spawn the same shot on remote roles. |
Saving, pooling, and multiplayer
The prefab stores trajectory, collision, impact, destruction, lifetime, particle, and audio configuration. Current position, velocity, parent, ignored owner, remaining lifetime or destruction delay, impact state, and active visual state are runtime data. Save the durable gameplay result and deliberately respawn or discard in-flight projectiles around a load boundary rather than expecting a flight to resume.
Projectile destruction uses ObjectPoolBase. With the supported multiplayer integration enabled, Projectile Shooter spawns through NetworkObjectPool, non-server local instances defer to the server, and ProjectileBase restricts network destruction to the server. Prefab registration, custom-module replication, save behavior, and authoritative damage remain integration or project responsibilities.
Related tasks
- Shootable Action configures Shooter, Projectile, ammo, clip, impact, feedback, and reload modules.
- Trajectory Object explains shared movement, collision, settling, and preview settings.
- Impact Actions configure damage, force, surface effects, and callbacks.
- Damage Processor configures project-specific damage rules.
- Explosion configures an area result spawned on destruction.
- Magic Projectile connects the same runtime Projectile to a Magic Action.
- Object Pool explains reusable object ownership.
- Events explains Event System registration and cleanup.
Developer reference
Projectile derives from ProjectileBase and adds Lifespan. ProjectileBase exposes Initialize(...), InitializeProjectileProperties(...), Destruct(...), OnImpact, and OnDestruct. Trajectory Object exposes movement, collision, force, and simulation members.
ProjectileShooter implements IProjectileOwner. Its Owner is the character, SourceComponent is the Character Item Action, and DamageSource is the Shootable Action. OnProjectileImpact associates the collision with the Shootable Action and invokes ShootableAction.OnFireImpact; its OnProjectileDestruct callback is intentionally empty.
Base On Collision Event is a UnityEvent receiving the physical RaycastHit. OnObjectImpact is an Opsive Event System callback produced only by configured Impact Actions. Spawn Projectile also publishes OnShootableWeaponShowProjectile(GameObject, bool) when a loaded projectile is shown or hidden. Subscribe and unsubscribe C# or Event System listeners with the pooled object’s lifecycle.