Extend duration of VFX graph particle system during runtime

Greetings,

I’ve been struggling with this on and off for a few days. I have a simple VFX graph particle system that displays a shield around enemies in my game. The vfx graph has an exposed lifetime that is set on initialization.

When an enemy is damaged, the vfx particle system spawns, and persists for its lifetime. However, I’d like to have the shield continue to appear beyond its set lifetime if it was recently damaged. Here’s the coroutine that spawns the particle system, and keeps track of how long its been alive / destroys it when the time is right:

The approaches I’ve taken have been to use the SetFloat() method to modify the age of the particle system, looking at the Add Age block and adding negative values for instance. Specifically this means I have to access a custom attribute from the VFX graph and assign it via the script. That happens in the damageShield method:

The problem is that this approach is too permanent. Add Age or Set Age will continue to update the particle with those modifications (ultimately if I Set Age back to 1 second, the shield would just persist forever). This is because I’m not ‘undoing’ the age modification. This is probably apparent in the VFX graph:

I can think up a little timer that basically sets the custom attribute for a couple frames then re-sets it, but is there a way I can use triggers or some logic in the VFX graph to make this more robust? I’ve attached a screenshot of the vfx graph, the coroutine that creates and destroys the shield, and the damageShield method (where the lifetime extension would presumably happen).

Thanks for any support, I’m new to VFX graph and have been having a hard time sorting out how to interact with scripts efficiently.

Best,
Nikko

I’m not a fan of your approach of tying the logic to the visuals. I’d track the values separately, in code, and spawn and despawn the visual FX to match rather than pushing game logic into the visual effect systems. Right now you have some logic in code (is dead, shield deployed) and some in a graph (age, lifetime) and it’s creating the disconnect.

Thanks for the response. That makes total sense, i’ve been struggling with this for so long I wasnt looking at the simplest solution. I would normally just play() or stop() a particle system, so I tried instantiating the shield on the enemy once in Start(), remove all the coroutines etc, and just use the existing shield logic to play or stop the VFX graph. This didn’t cull the existing animation however, so the solution I settled on was to:

  1. if the enemy takes damage, and it has a shield, if the VFX prefab is absent, instantiate it.
  2. if the prefab is already on the GO, use Reinit()
  3. if the shield amount drops below zero, destroy the VFX prefab.

All I was trying to do was ‘extend’ the lifetime of the shield when the enemy takes damage - using Reinit() seems to start the current system over - is that a reasonable approach? seems to do what I think its doing in testing.

Follow on here, say after the shield first appears, or is destroyed, I want to modify or add a new animation to punctuate the event. Is there benefit to making a more complex VFX graph using the event system, or is destroying one and instantiating another a reasonable design choice?

Thanks for bringing me back down to earth!

Are you familiar with the event system of the visual effect graph? I feel like it’s the missing piece for what you’re trying to do, as it allows you to fire custom events that would spawn different effects (like deployment, impact [with parameters], and destruction) all in one graph. It may save you a lot of headache as you wouldn’t need to constantly instantiate/destroy visual effects.

Some reading:
https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@7.1/manual/Events.html
https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@8.1/manual/ComponentAPI.html#event-attributes