Because I am learning Gameplay Ability System in Unreal IV, I found that there are few Chinese tutorials on the Internet, so I hope to record my learning process and method, and also hope to help some people in need. Of course, because I am also just learning, so this tutorial will have a lot of problems and defects, please understand.

Note that the use of the game ability system must be C++, so I’m here to read this article by default, the elder brother has some basic knowledge of unreal iv. Without further ado, let’s go!

This article references the Youtube video link

1. Add the GAS system

To use the GAS system first need to Enable the Gameplay Abilities plugin in Plugins

Then in projectname.build. cs, add three dependencies: GameplayAbilities, GameplayTasks, and GameplayTags

PublicDependencyModuleNames.AddRange(new string[] { "Core"."CoreUObject"."Engine"."InputCore"."HeadMountedDisplay"."GameplayAbilities"."GameplayTasks"."GameplayTags" });
Copy the code

Then rebuild the solution

2. Then understand the role of several basic types in GAS systems:

(1) AbilitySystemComponent(ASC) is a component that handles all interactions of the skill system. Think of it as the heart of the game’s skill system.

(2) Gameplay Tags are a series of hierarchical Tags that can be defined as Weapon.Hit. You can use these tags to set relationships, such as those with magic resistance tags that can’t be damaged by magic attack tags. We can also use a Gameplay Cue to respond to the GE corresponding to Tage.

(3) The Attributes and Attribute Set are responsible for defining Attributes in the skill system, including Health, Stamina, etc. It can only be modified by Gameplay effects, including the initialization of a role attribute value.

(4) Gameplay Effects(GE) is a method for modifying Attributes and Gameplay Tags of oneself or others, such as damage, health recovery, etc. It is also a data type and should not have logic, it only means how to modify the data. How much data to modify.

Gameplay Abilities specifies the actions Actor can take in the game, such as shooting, melee attacks, etc. It is executed in the following order.

(6) Ability Tasks

(7) Gameplay Cues, when the Gameplay Effect is successfully applied, all Gameplay Cues configured in Gameplay Tags will be triggered.

The following figure is part of the relationship diagram of GAS system as I understand it. It is only a general relationship and personal understanding, so it is not accurate. Please refer to it.

Create Ability System Component, Gameplay Ability and an Attribute Set in Unreal 4. I’m going to name it GAS.

4. Open Visual Studio (Rider). In projectname.h, add the enum class
UENUM(BlueprintType)
enum class EGASAbilityInputID: uint8
{
   None,
   Confirm,
   Cancel,
   Punch
};
Copy the code
5. Then define the Attribute Set for the role, where I want the role to have health.

First, define a Macro method. This method is convenient for modifying and initializing property values. It can directly generate getters, setters, and other methods for an Attribute. The implementation of this method is available in Attributeset.h, at the bottom, and copied directly.

#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
Copy the code

And then declare a constructor and GetLifeTimeReplicatiedProps method.

UGASAttributeSet();

/** Returns properties that are replicated for the lifetime of the actor channel */
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
Copy the code

Next, define the health Attribute. ReplicatedUsing indicates that the function is called when the property value is changed.

FGameplayAttributeData is used to create attributes, which act as a Struct and are recommended for use in skill systems. The implementation is also in Attributeset.h, which you can see for yourself.

UPROPERTY(BlueprintReadOnly, Category="Attributes", ReplicatedUsing=OnRep_Health)
FGameplayAttributeData Health;
// This uses the macro method defined earlier
ATTRIBUTE_ACCESSORS(UGASAttributeSet, Health);

UFUNCTION()
virtual void OnRep_Health(const FGameplayAttributeData& OldHealth);
Copy the code

The implementations of these functions are then generated in CPP.

OnRep_Health directly uses the attribute. h method for handling modified attributes.

void UGASAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
{
   GAMEPLAYATTRIBUTE_REPNOTIFY(UGASAttributeSet, Health, OldHealth);
}
Copy the code

GetLifetimeReplicatedProps implementation (I still don’t understand the function of the function, but in the tutorial have made corresponding requirements)

UGASAttributeSet::UGASAttributeSet(){}/** Allows gamecode to specify RepNotify condition*/
void UGASAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
   Super::GetLifetimeReplicatedProps(OutLifetimeProps);

   DOREPLIFETIME_CONDITION_NOTIFY(UGASAttributeSet, Health, COND_None, REPNOTIFY_Always);
}
Copy the code

The code for the Attribute Set is done.

6. Then in GasGamePlayability.h. Declare a capability input enum variable, the enum class we implemented earlier in Step 4.
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="Ability")
EGASAbilityInputID AbilityInputID = EGASAbilityInputID::None;
Copy the code
7. The last and longest step of the code is to open your character.h. The AbilitySystem interface is inherited
#include "AbilitySystemInterface.h"
class AGASCharacter : public ACharacter.public IAbilitySystemInterface
Copy the code

You need an AbilitySystemComponent (the heart of the GAS system) and an AttributeSet (an Attributes collection) in character

UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera, meta = (AllowPrivateAccess = "true"))
class UGASAbilitySystemComponent* AbilitySystemComponent;

UPROPERTY()
class UGASAttributeSet* Attributes;
Copy the code

You also need to override a method that returns character’s AbilitySystemComponent

virtual class UAbilitySystemComponent* GetAbilitySystemComponent(a)const override;
Copy the code
UAbilitySystemComponent* AGASCharacter::GetAbilitySystemComponent() const
{
   return AbilitySystemComponent;
}
Copy the code

In the role constructor, create AbilitySystemComponent and Attribute Set

AbilitySystemComponent = CreateDefaultSubobject<UGASAbilitySystemComponent>("AbilitySystem");
AbilitySystemComponent->SetIsReplicated(true);
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Minimal);

Attributes = CreateDefaultSubobject<UGASAttributeSet>("Attributes");
Copy the code

Now if you Build the Solution, you can see the AbilitySystemComponent under the Movement Component of the role

But now the action system does not have Ability to be activated, nor is it bound to input.

First we need to implement the abilities that can be used to initialize the action system. A DefaultAbilities are required to “give” these abilities to an action system. Then assign an initial value to the attributes of the role. Since the attributes of the action system need to be modified by gameplay Effect, even when initialized, we need a DefaultAttributeEffect. Initialize Attribute to define two objects in public. This is then assigned in the blueprint.

UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category="GAS")
TSubclassOf<class UGameplayEffect> DefaultAttributeEffect;

UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category="GAS")
TArray<TSubclassOf<class UGASGameplayAbility>> DefaultAbilities;
Copy the code

With the DefaultAttributeEffect. We need to initialize the attribute values of the role using the default Gameplay Effect.

virtual void InitializeAttributes();
Copy the code

implementation

// Initialize Attributes
void AGASCharacter::InitializeAttributes()
{
   if(AbilitySystemComponent && DefaultAttributeEffect)
   {
      FGameplayEffectContextHandle EffectContext = AbilitySystemComponent->MakeEffectContext();
      EffectContext.AddSourceObject(this);

      FGameplayEffectSpecHandle SpecHandle = AbilitySystemComponent->MakeOutgoingSpec(DefaultAttributeEffect, 1, EffectContext);

      if(SpecHandle.IsValid()) { FActiveGameplayEffectHandle GEHandle = AbilitySystemComponent->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data.Get()); }}}Copy the code

I think it would be easier to look at the blueprint to understand the features, and the above features are implemented in the blueprint as follows.

FGameplayEffectContextHandle description:

/** Handle that wraps a FGameplayEffectContext or subclass, to allow it to be polymorphic and replicate properly*/
Copy the code

FGameplayEffectSpsecHandle in fantasy four described in the following:

/** Allows blueprints to generate a GameplayEffectSpec once and then reference it by handle, to apply it multiple times/multiple targets. */
Copy the code

The last function ApplyGameplayEffectSpecToSelf, will create the Gameplay effect ACTS on the target, here initialized through the effect on their properties.

Next comes the need to toggle DefaultAbilities for skill systems.

virtual void GiveAbilities();
Copy the code

implementation

void AGASCharacter::GiveAbilities()
{
   if(HasAuthority() && AbilitySystemComponent)
   {
      for(TSubclassOf<UGASGameplayAbility>& StartupAbility: DefaultAbilities)
      {
         AbilitySystemComponent->GiveAbility(
            FGameplayAbilitySpec(StartupAbility, 1,static_cast<int32>(StartupAbility.GetDefaultObject()->AbilityInputID), this));
         AbilitySystemComponent->InitAbilityActorInfo(this.this); }}}Copy the code

FGameplayAbilitySpec takes one GameplayAbility as input and the rest of the input:

InitAbilityActorInfo tells the action system who is its master! Obey your master’s command.

The initialization of Ability and Attribute is then complete.

Finally, you need to bind the action system to the input.

Binding function requires two parameters, one is the role of the Input Component of a pointer, one is FGameplayAbilityInputBinds, FGameplayAbilityInputBinds constructor needs at least three parameters: The first two arguments are strings that define the input commands for “Confirm” and “Cancel.” The third argument is the UEnum for all inputs, the one we defined in the header file earlier. We complete the binding in OnRep_PlayerState().

virtual void OnRep_PlayerState() override;
Copy the code

implementation

void AGASCharacter::OnRep_PlayerState()
{
   Super::OnRep_PlayerState();

   AbilitySystemComponent->InitAbilityActorInfo(this.this);

   InitializeAttributes();

   if(AbilitySystemComponent && InputComponent)
   {
      const FGameplayAbilityInputBinds Binds("Confirm"."Cancel"."EGASAbilityInputID", static_cast<int32>(EGASAbilityInputID::Confirm), static_cast<int32>(EGASAbilityInputID::Cancel)); AbilitySystemComponent->BindAbilityActivationToInputComponent(InputComponent, Binds); }}Copy the code

Finally, rewrite the PossessedBy function, because the owner of the Character is really a Character Controller, so the Controller needs to be the “master” of the skill system.

virtual void PossessedBy(AController* NewController) override;
Copy the code

function

void AGASCharacter::PossessedBy(AController* NewController)
{
   Super::PossessedBy(NewController);
   // Server Gas Init
   AbilitySystemComponent->InitAbilityActorInfo(this.this);

   InitializeAttributes();
   GiveAbilities();
}
Copy the code
8. OK, at this point, the code part is complete. Next, enter Unreal Iv Editor.

Create a new blueprint class, GameplayEffect, named GE_CharacterDefault, that initializes the Attributes of the role

In this Gameplay Effect, you only need to add one element to the Modifiers.

Assign GE_CharacterDefault to the Default Attribute Effect in the role blueprint

Run the game, enter the command (this step should be after adding Ability (step 9), otherwise error will be reported)

You can see that the property is initialized

9. Next, implement the character attack ability.

First add the Action Mapping in the Input SettingSimilarly, create a new blueprint class

Named GA_PunchHere we implement the simplest, Punch ability, play the animation once, and then end the ability.

When finished, bind the left mouse button to the ability.

Then run, click the left mouse button, we can see the character can play the attack animation.

10. Achieve attack damage

After the character has the ability to attack, it cannot deal damage, in order to achieve the ability to damage. Create the same Gameplay effect that causes the damage as in step 8 and name it GE_DamageNotice that the GameplayCue Tags are set to GameplayCue.TakeDamage, which can be created by ourselves.

We don’t want the character to form damage checks throughout the attack, so we need to enable collision checks after keyframes. Create a new blueprint class AnimNotify and name it AN_PunchTurn on AN_Punch so that when the object playing the animation receives Notify, the Punch event of the character will be called. The event here has not been implemented.Add Notify to the attack animation.

Realize the Punch EventAfter starting punch, a spherical collision detector will be started at the Socket position named Weapon on the right hand. If the detector detects a pawn of collision (valid), it will send a Gameplay Event to this actor. The Event Tag needs to be Weapon.Hit, which can be created by adding a Tag.

11. Improve Punch Ability

Back to GA_Punch, we need to wait for the event caused by the collision before ending the activity, and then apply a Gameplay Effect (GE_Damage) to the target after receiving the event

Now we can deal damage, but there is no feedback, we want an attack animation to play when the enemy is hurt. Create a Gameplay Cue and name it GC_TakaDamage

Notice that the Class Setting in GC_TakaDamage sets the tag to Gameplay.TakeDamage just like we did in GE_Damage, which means that the Gameplay Cue will apply to any Effect with this tag.

Completed 12.

Start the game

You can see that the attacked unit plays a Hit animation. Done!