Project Description:
An Ability Framework in Unreal Engine 4 that fully supports Networks. The framework is intended for Designers to expand with and create new abilities without worrying about network and basic setups. The system should work on LAN and/or other Online Subsystems (Steam etc.)
Roles & Responsibilities:
Technical Designer/System Designer/Programmer
Design, create and implement Ability System Framework for various game genres to use.
Design architecture of logic flow and all classes as well as communication standards.
Optimize Network performance
Provide easy configs for Designers
Coop Demo (10 hrs building from scratch with this framework)
PvP Demo (Building along with this framework as a functionality test)
Ability Example Snippet (For Designers)
Ability Set
Modifier Example
Logic Flow
Following along the red line, Actor A activates an ability, after checked by server, the ability called ApplyModifierTo(AActor Target, AModifier NewModifier, float Duration) function through interface, by doing so, a modifier was applied to Actor B’s UModifierTargetComp, through a bunch of checks, the modifier was successfully applied, then the modifier did corresponding functions and garbage collected.
ACustomActor : AActor
As shown above, ACustomActor is the basic object in this framework, which performs as a simple startup point for all actors in this framework. The main reason for using AActor instead of UObject is to use the network supporting feature.
UAttributeComp : UActorComponent
As mentioned above, UAttributeComp has 2 member properties: AttributeClass and StatusClass, It also performs InitializeAttributePreset() and InitializeStatusPreset() after BeginePlay(), which passes the outer Actor to AAttributePreset and AStatusPreset. This component is replicated.
AAttributePreset
User define any property in this class, such as Health, Mana, etc. It also contains a list of polymorphic functions:
AddAttribute ( Template<T> TargetProperty , Template<T> DeltaValue )
MultiplyAttribute ( Template<T> TargetProperty , Template<T> Multipler )
SetAttribute ( Template<T> TargetProperty , Template<T> NewValue )
These functions can be called by anything that wants to change these attributes, such as receiving damage, or responses to the Enum_ModifyMethod in FCostStruct, see below:
AStatusPreset
AStatusPreset stores a bunch of predefined Booleans, which could be anything similar to Stun, Drunk, Fly, Sleep, Run, Heal, etc. By default, a couple check functions are created, and user can override them freely. If one of them return true. For example:
OnRep_StunChanged(bool) will be called, allow corresponding logic to be applied to the caster, for example, disable player’s input when stunned. Usually, status is being changed by an AModifier, the reset function should be handled in AModifier’s OnPreExpire() function.
UModifierTargetComp : UActorComponent
UModifierTargetComp responds to interface message call ApplyModifierTo(Modifier, Duration). It first checks if the modifier type or modifier itself, is explicitly blocked by any existing modifier. Otherwise the modifier will be added to modifier list (call OnReapply() if the modifier is already in the list) Then, the BlockType and BlockList from this modifier will be registered into this component, for future modifier apply check.
After modifier has been added to ModifierList, corresponding LifeCycleHandler(float Duration) will be called to control the life cycle of this modifier, user can manually start tick() by calling StartIntervalThink().
Eventually LifeCycleHandler(float Duration) fires OnPreExpire() –> OnReadyToExpire() call chain when duration ended, given user the last chance to do any logic before the modifier is being removed, then RemoveFromModifierList(Modifier) will be called by AModifierTargetComp, the modifier will be pop out from Modifier List and GCed in next GC cycle (Or manually GCed).
AModifier : ACustomActor
Once LifeCycleHandler(float Duration) is being called from UModifierTargetComp, OnApplied() will be fired first to do any initialization logic. By default, the modifier will not tick on its own, unless user manually calls StartIntervalThink(float DeltaTime)AModifier class has a bunch of events to respond to UModifierTargetComp events:
OnApplied()
OnReapplied()
OnBlocked()
OnStackChanged(UInt8 NewStack)LifeCycleHandler(float Duration)
eventually fires OnPreExpire() -> OnReadyToExpire() call chain.
UAbilitySetComp : UActorComponent, AAbilitySet : ACustomActor
UAbilitySetComp and AAbilitySet are simple classes, UAbilitySetComp holds an AAbilitySet, and an InitializeAbilitySet() function to pass parent actor into AAbilitySetAAbilitySet stores a TArray<AAbility*> as well as an InitializeAbilities() function, which passes both BelongingActor and BelongingAbilitySet to each AAbility class
AAbility : ACustomActor
When activating an Ability, TryActivate() is fired, results in a function call chain, ActivatePrecheck() is called first, to ensure the Ability is not in cooldown, not in use or disabled by modifiers. Then followed with CostPrecheck() to sync with server and see if caster has enough stats to perform this action. If both passed, CommitAbility() is called, and this is the last chance server can abort this behavior.Once committed, ApplyCost() is called to modify caster’s stats as ability cost, then the actual lifecycle of performing the ability is started:
OnActivated() is called immediately when the ability is activated, allowing initialization logic to run here.
OnTakeEffectNotifyActivated() is called when ability montage reaches TakeEffect Notify, since an AnimMontage can have multiple notifies, so this ability supports combo attack.
StartIntervalThink(float DeltaTime) is manually called to constantly fire OnIntervalThink() based on DeltaTime.
OnIntervalThink() is constantly fired by StartIntervalThink every fixing amount of time.
StartCooldown() is manually called to start cooldown, based on whether user wants the ability to cooldown at the start of this ability or at the end. After cooldown finished, bInCooldown is set to false.
EndAbility() is manually called to finish this ability, it has to be called otherwise the ability will last forever!
OnAbilityPreEnd() is called after user manually called EndAbility(), allowing any last logic to perform before the ability stops
OnAbilityReadyToEnd() is followed by OnAbilityPreEnd(), which sets bCanActivate to true and stops OnIntervalThink().
Comments