This document is about: QUANTUM 2
SWITCH TO

Projectiles

Overview

The ProjectileSystem provides a mechanism for updating projectiles and detecting hits.

It supports continuous collision detection (CCD) through a 2 phase process:

  1. Query Phase: At the beginning of each frame, the ProjectileQuerySystem sets up broadphase queries for each projectile. It runs after the PredictionAreaSystem but before the PhysicsSystem3D. By default it queries a linecast or shape overlap from the projectile's current position to next position calculated based on its velocity. These queries are then resolved during the PhysicsSystem3D tick.
  2. Logic Execution Phase: The results of the broadphase queries are retrieved by the ProjectileSystem from the PhysicsSystem3D and forwarded to the ProjectileController. This is the stage at which the projectiles' logic is executed in the frame. If a system depends on a projectile having executed its logic, that system needs to run after ProjectileSystem - the order in which systems are executed is defined by their order in SystemSetup.cs.

Projectile

A projectile is its own entity. Every projectile entity carries:

  • a Projectile component;
  • a concrete implementation of the ProjectileController;
  • a PhysicsCollider3D; and,
  • a PhysicsBody3D.

The requirements regarding the PhysicsCollider3D and PhysicsBody3D can be overriding via the concrete implementation of the ProjectileController methods. Please check implementations included with the FPS Template for more details.

weapon setup example
Projectile Prototype Example.

Controller API

The ProjectileController is an abstract class. It is used to create concrete implementation for each type of projectiles. The following API is used to process all projectile conctrollers in the ProjectileQuerySystem and ProjectileSystem:

  • OnInitialize(): Called once when the projectile is spawned
  • OnDeinitialize(): Called once when the projectile is destroyed
  • OnUpdate(): Called every frame, updates projectile position / velocity / ...
  • OnProcessHits(): Base implementation resolves closest hit, optionally ignores owner, teleports projectile to hit point and destroys the projectile on first hit
  • AddPhysicsQuery(): Base implementation add linecast / shape overlap query based on position and velocity in the PhysicsBody3D, shape is defined by the PhysicsCollider3D

Concrete Implementations

The concrete implementations of the ProjectileController included in the FPS Template are:

  • FPSProjectileController: Extends the default behavior with damage, knockback, target penetration, bouncing settings and hit effects. This is the base controller for all FPS projectiles.
  • DynamicProjectileController: Adds linear impulse on spawn. The projectile is moved by Quantum Physics.
  • KinematicProjectileController: Projectile moves forward at constant speed.
  • MagneticProjectileController: Projectile homes in on a specific target upon spawning and updates its rotation towards the target.
  • InstanceProjectileController: Projectile does not move, instead it spawns a physics query with a long distance and process hits instantly. It still uses the query-process approach which means there is a 1 frame delay before getting hits.

Creating a New Projectile

This is the step-by-step procedure to create a new Projectile in the FPS Template.

  1. In the Quantum solution, create a new MyProjectileController which inherits from
    • ProjectileController: to define custom behavior; and,
    • FPSProjectileController: to support basic predefined behavior (damage, layer filtering, knockback, bouncing, hit effects, ...)
  2. Add serializable fields to the controller (configuration)
  3. If needed, create a MyProjectile.qtn which contains the definition for the MyProjectile component and other data structures such as roll-backable data
  4. Override the base properties if needed and implement OnInitialize(), OnDeinitialize(), OnUpdate(), OnProcessHits() and AddPhysicsQuery() in the controller
  5. Implement the available controller interfaces (e.g. IPreProcessComponentDesires, ...)
  6. Recompile the quantum.code solution.
  7. In Unity, create an empty GameObject and the visual components / model as a child object.
  8. Add the Entity, EntityPrototype, EntityComponentController and EntityComponentProjectile scripts to the GameObject.
  9. On the Entity component, set Transform Synchronization to Error Correction.
  10. On the EntityComponentController component, select MyProjectileController from the ProjectileController drop-down menu and fill out the defined properties.
  11. On the EntityComponentProjectile component fill out defined properties.
  12. Add other entity components to define the behavior of the entity (EntityComponentMyProjectile, EntityComponentPhysicsCollider3D`, ...).
  13. If EntityComponentPhysicsCollider3D is used, set the Projectile's layer and enable the IsTrigger boolean.
  14. Create a prefab of the entity.
  15. Execute the asset resource generation via the Quantum > Generate Asset Resources menu.
  16. Your projectile is ready to use - i.e. referenced as an EntityPrototype.
Back to top