The TimeMod class from Game Modules 4enables global and local time scales to be used, meaning individual objects can have time scales unique to themselves while also being affected by a global time scale.
Projectiles can also make use of this class.
In the example below, I will demonstrate how to add a custom script to the projectiles which will track their unique TimeMod, and also set the Particle System simulation speed.
I will also demonstrate a new Movement Behavior derived from an existing one which takes into account the GlobalTimeScale on the projecitles.
In the example below, I have a "TimeScaleZone" layer, which is used for areas on the map which may change the TimeScale of any object within it.
Projectile Setup
Add a Collider
First, add a collider to your projectile, and set the "Include" and "Exclude" layers so that only the TimeScaleZone is affected.
Note: Depending on your setup, you may need to create this logic in a new child object, so that there is only one collider on each object in your Projectile. If you don't have a collder, you can set this on the parent object.
Add the Custom Script
You'll want to create your own script, but you can copy this to start. You may have to change some values to align with the way you're setting up your global TimeMod object.
In this example, I'm going to create a new behavior that derives from MovementBehaviorForward, which comes with Projectile Factory. The same logic will apply to any movement behavior that moves the object via a deltaTime value.
Again, you can copy this, but you may need to modify things to better fit your project.
namespaceMagicPigGames.ProjectileFactory{ [CreateAssetMenu(fileName ="New Basic Forward Movement Behavior Battle Ages", menuName ="Projectile Factory/Moving Behavior/Battle Ages - Basic Forward Movement Behavior")] [Serializable]publicclassMovementBehaviorForwardBattleAges:MovementBehaviorForward {privateProjectileTimeScale _projectileTimeScale;privateProjectileTimeScale ProjectileTimeScale {get {if (_isInitialized) return _projectileTimeScale; // Only check for this value once // Set the value with GetComponentif (_projectileTimeScale ==null) _projectileTimeScale =Projectile.GetComponent<ProjectileTimeScale>(); // Set isInitialized to true and return the value _isInitialized =true;return _projectileTimeScale; } }privatebool _isInitialized;protectedoverridevoidMove() {var deltaTime = ProjectileTimeScale ==null?Time.deltaTime:ProjectileTimeScale.DeltaTime;Projectile.transform.Translate(LocalDirection * (ProjectileSpeed * deltaTime),Space.Self); } }}
We compute the value of deltaTime in the Move() method, using the ProjectileTimeScale class if it's attached to the projectile, otherwise the standard Time.deltaTime.
Optional: Set the Simulation Speed of Particle Systems
You can create a new class which derives from ProjectileTimeScale to add additional methods, or create other classes that reference ProjectileTimeScale, whichever you prefer. Here we have a new child class called ProjectileParticleSystemTimeScale.
publicclassProjectileParticleSystemTimeScale:MonoBehaviour{publicProjectileTimeScale projectileTimeScale;publicParticleSystem[] particleSystems;privatefloat _timeScale;publicfloat TimeScale =>projectileTimeScale.GlobalTimeScale;publicvoidUpdate() {var timeScale = TimeScale;if (Mathf.Approximately(timeScale, _timeScale))return; _timeScale = timeScale;foreach (var ps in particleSystems)SetSimulationSpeed(ps, timeScale); }privatevoidSetSimulationSpeed(ParticleSystem ps,float timeScale) {var main =ps.main;main.simulationSpeed= timeScale; } // Automatically populate particleSystems with all ParticleSystems in childrenpublicvoidOnValidate() {if (particleSystems ==null||particleSystems.Length==0) particleSystems =GetComponentsInChildren<ParticleSystem>();if (projectileTimeScale ==null) projectileTimeScale =GetComponent<ProjectileTimeScale>(); }}
The OnValidate() method will automatically populate the list of Particle Systems. Set the list count to 0 to force the script to recompute the list if you add additional systems later.
You can use these scripts (and the collider) on other particles that aren't "Projectiles" as well, to ensure that muzzle flashes and impacts also react to the Time Scale.