Need help with effects system

Started by
3 comments, last by Telanor 10 years, 3 months ago

I've been working on getting an effects system set up but I'm having some trouble figuring out how to implement some parts of it. I've made a sort of outline of the key parts of it, how I think some things should work, and what things I don't know how to do. If anyone could look over it and comment on whether these are good ideas or not, or how to do some of these things, I'd appreciate it. If anything in my rather abbreviated list doesn't make sense I can explain it better, if need be.

2 types of effects: active, reactive (not a code based differentiation)
active: DoTs and instants, stat changes. Not interested in other effects, just applies some kind of stat change
reactive: shields, effect modifiers.
Change effects when they update?
Somehow need to pass computed change from active effects to reactive ones for modification
How does sorting play into this? does effect type (additive, multiplicitive, exclusive) matter?

Sorting:
effects have a priority number manually assigned as well as a type (additive, multiplicitive, exclusive)
exclusive effects apply before additive/multiplicitive and prevent same-priority effects from applying (how?)
possibly sort, then group same-priority effects together, stop processing group after hitting exclusive effect

Processing:
each tick, effect list is sorted
loop over list, call update on each effect
remove effects with remaining duration <= 0

Visuals:
when multiple instances of a single effect are active, need to apply the visual only once (how?)
visual probably can't be applied every update, needs to be applied once then removed, which means something has to hold a reference to the VFX object
what holds the reference? can't be held by the effect instance
how do you ensure that as one effect wears off, the visual stays active until all effects of that type have worn off

Networking:
when are packets sent? after each stat change? after each effect is processed? after all effects are processed?
is there any per-update data involved besides stat changes?

Misc:
for things like stun, root, etc, have a handful of hidden bool stats that determine state. Input system can check these to selectively disable
likely needs to use same system as visuals to ensure the state remains set so long as any effect is active that applies the state

Advertisement

Just some thoughts....

Processing

Sounds reasonable. Might be worthwhile to consider that you might need to signal when effects begin/end and design with that in mind for the future.

Visuals

In order to only apply the visual aspect of your multiple effects once, you could decouple the visual aspect from the logical effect. This means that each logical effect references a visualFxId or handle that is a lookup into a set of visual effects that can be applied. As a part of the update pass, you simply store a set<visualFxId> and that way if multiple logical effects reference the same visual effect but several logical effects have ended but others continue to express the same visual, you get the visual continuing to be applied.

The visuals will likely need to be updated each frame. Many times visuals include animation blends, particles, and other aspects to give the desired affect on the screen and thus do necessitate per-frame updates to keep them synchronized.

Networking

This ultimately can be done in whatever way you find that works best. I prefer to have effect information either included in a game object's update packet or at least have all the effect information packed together in it's own packet. The client should only be applying network game object updates at a predefined point in the main loop, so having that data sent in a single packet does make sure that all effect values are consistent at that point in time. If the client has a set of lookup tables that give it pertinent information on how to render stuff, you can easily pack your effect data into a few bytes per effect and leave it up to the client to render accordingly. Since we're talking about just associating icons and effects in some buff/debuff bar, animations, etc. These are low priority stuff that make no sense for the server to manage other than providing the least amount of state to the client.

Misc

If you treat your input stream like a queue, you can easily have some logic that when a stun/root effect has been applied, it registers an input stream listener that has a higher priority than the normal player's input stream listener. This effect listener essentially would consume the input necessarily to eliminate any effect of movement until the effect has ended. Once the effect ends, it unregisters and the input stream queue goes about it's business, being consumed by the player's input stream listener.

Thanks crancran, I'll give those ideas a try. For the input listener though, wouldn't there be an issue with multiple effects of the same type applying listeners? Also my current input setup simply inspects the current key/action state, it doesn't really consume anything. I can see some cases where having a queue and consuming actions would work nicely though. I'll have to consider it.

There's still the question of how to manage the 'reactive' effects, so they can do things like modify incoming damage and such. That one's pretty key to the whole system. If anyone has any ideas for that, I'd appreciate it.

Sorting:

Notice that even your 2 level sort is still somewhat arbitrary in case that a combination of type and priority does not prevent other instances of the same combination being attached. E.g. if 2 exclusive effects with the same priority are attached, which one wins? What happens if resorting isn't robust, hence causes their order to reverse sometimes?

Letting an exclusive effect hide other effects of the same priority is relatively simple. Because higher priority comes first after sorting, and exclusive effects come before others (of the same priority) all you need to do is to check whether the first effect for a given priority is an exclusive one, and if so, jump straight to the next priority after processing the current effect.

Processing:

Notice that you should not work with listening here. That is because you should assess the consequences of effects after all effects are applied. If not doing so, a damage effect may cause the N/PC to die just because the pending healing effect was not processed yet.

Notice further that some effects work transitionally while other work statefully. E.g. a HealthBoost adds 100 HP when being attached and subtracts them when being detached, but its update() method does nothing in-between attachment and detachment. A DiseaseEffect continuously subtracts some HPs instead. But that is hidden in the particular update() methods.

Visual:

As crancran already noted, using some kind of set would do the trick.

Misc:

I totally disagree with effects having a, well, effect on the input sub-system. First of, the input sub-system is low level compared to the effect system. As such it should not need to know about effects at all. Second, if you think about feedback to the player, wouldn't it be helpful if the player actually sees that the N/PC wants to move but cannot? In fact, effects (in this sense) should work on the character's animation / state machine level, but not on the input level.

Good point about the sorting. There probably won't be that many exclusive effects, so maybe it's fine to leave it as is? I'm not sure what should be done in that situation though.

Notice that you should not work with listening here. That is because you should assess the consequences of effects after all effects are applied. If not doing so, a damage effect may cause the N/PC to die just because the pending healing effect was not processed yet.


Yea, figuring out how to set that up is the toughest part of this that I'm stuck on. I figure the effects need to do their computations during update without applying them, somehow pass the results around to the other effects, and then apply them afterwards. The only way I've though of is to maybe stick the results into a list/dictionary and I guess loop over all the effects and let them alter the values. Seems kinda inefficient though.

I totally disagree with effects having a, well, effect on the input sub-system. First of, the input sub-system is low level compared to the effect system. As such it should not need to know about effects at all. Second, if you think about feedback to the player, wouldn't it be helpful if the player actually sees that the N/PC wants to move but cannot? In fact, effects (in this sense) should work on the character's animation / state machine level, but not on the input level.


I probably should have worded that a bit better. I didn't mean the input system itself, but rather the input-processing component (as in a component of an entity-component system). It translates the input actions (such as walk_forward) into character movement and such. It's already handling player/character state there so it shouldn't be entirely out of place I don't think.

I'm not sure I understand what you mean by showing the player that an (N)PC wants to move but can't. How do you show that someone is stunned and is trying to move? I can't think of any game that's shown such a thing before.

This topic is closed to new replies.

Advertisement