sjai013/unity-gameplay-ability-system

Could it be better to use MonoBehaviour prefab for ability/gameplay effect?

yangrc1234 opened this issue · 7 comments

Really great repo! I've learnt UE4 GAS for some time, after searching online for a similar solution in Unity, now I'm already using it to make my toy game. And it's definitely helping hah. So sad Unity just never had an official usable gameplay framework.

Still I'm wondering, that In Unreal, Effect/Ability is blueprint, which means it can be inherited to reduce duplicating works.
I'm not sure why ScriptableObject is used in our case, but if we use MonoBehaviour as base class for Effect/Ability, we could at least do some "inheritance"(quoted because we can't override any method, but only data inheritance) using Unity prefab variant system.

Of course MonoBehaviour has some overheads. But we can keep it on disk and only gets data from it, without instantiating it.

Thank you for you reply!
I know ScriptableObject is good for storing data, and I use them a lot too. But they just lack some abilities comparing to UE4 data-only blueprint. Maybe I'm just not clear enough to get you to the idea, sry for my poor english hah.
But here's a great blogpost I found that exactly tells what I mean with some examples: https://blog.gemserk.com/2020/05/26/using-unity-prefabs-and-gameobjects-only-for-data/

Thank you for the link to the blog post. I can see the value in what the author is saying, but I'm concerned about the overhead prefabs introduce.

As a reference, the current approach is to keep track of the applied GE in a list (the "AbilitySystemCharacter" class). A GameplayEffectSpec is created from the GameplayEffect SO (much like how UE's GAS works) - the GameplayEffectSpec is an instantiation of the GameplayEffect SO, so it can contain mutable data (the GameplayEffect SO is considered immutable). This list is iterated each frame to update the remaining time for durational GE. Similarly, the list can be searched to identify the current remaining time for a specific GE (which matches a tag).

Using a prefab system instead as you suggest, how would you propose identifying an applied GE? Would this involve creating a new prefab for each applied GE? This would be massive bottleneck - imagine a scenario where you're creating 100s of GE every frame. This would not be very performant. Once those prefabs are created, where would you put them in the scene? Nested under the main character? Would you keep track of the GE prefabs (presumably, you would cache the Duration Monobehaviour on those GE) using a list on the character?

Hi sjai013,

The answer is, just DON'T INSTANTIATE PREFAB.
Keep all the GameplayEffectSpec stuff, and replace GameplayEffectScriptableObject : ScriptableObject with GameplayEffectPrefab : MonoBehaviour, and it should work.

The fact is that you can read data from Prefab without instantiating it, and do comparing with no problem. Just like ScriptableObject.

I was thinking why not just making an example for this. So after 20 min of copy-paste, here it is:
https://github.com/yangrc1234/unity-gameplay-ability-system
Check main branch newest commit for changes.
Very few code is edited, most changes are converting scriptable object in the original example to prefabs.
No prefab is instantiated, everyone is happy.

Thanks for that. I see your point. This certainly seems to be a more powerful approach - I'm now not able to see why you would ever use SO when you can use prefabs in this manner.

I'll update the repo at some point for this. I really appreciate your feedback, thank you! Feel free to close this issue when you're done.

Good to hear that!

I think the source of this issue is that, Unity doesn't have a equally flexible system comparing to UE4 blueprint.
Prefab can be "inherited"(prefab variant), but we can't change the MonoBehaviour on it to a derived version. (while in UE4 we can inherit an blueprint, changing its logic and data)
And ScriptableObject is even more weaker. Hoping they can bring up a similar "ScriptableObject variant" solution.

But using Prefab system here has an advantage over UE4 GAS, that is we could extend data/logic by adding scripts to Prefab; Add child GameObject to Prefab.
while UE4 is using UObject sub class for GameplayEffect/Ability, which can't have any Component.
Just some random thoughts.

I'll share my thoughts during my development anytime in the future. :D

Just referencing this here for future reference:
https://blog.unity.com/technology/making-cool-stuff-with-scriptableobjects

Unite '16 LA - Richard Fine (at 6mins) talks about using SO instead of non-instantiated prefabs.