Activation policy and the weapon

Course day 12 (ability policy, weapon setup) · commit 17f78d1 · UWarriorGameplayAbility, AWarriorWeaponBase, GA_Shared_SpawnWeapon, GA_Hero_SpawnAxe · 9 min

In one breath

All your abilities derive from one base class that adds an activation policy. OnTriggered abilities wait for input or an event. OnGiven abilities run as soon as they're granted, then remove themselves. That's a neat way to run one-off setup through GAS, like "spawn the axe and put it on his back".

The policy

UENUM(BlueprintType)
enum class EWarriorAbilityActivationPolicy : uint8 { OnTriggered, OnGiven };

void UWarriorGameplayAbility::OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo,
                                            const FGameplayAbilitySpec& Spec) {
    Super::OnGiveAbility(ActorInfo, Spec);
    if (AbilityActivationPolicy == EWarriorAbilityActivationPolicy::OnGiven)
        if (ActorInfo && !Spec.IsActive())
            ActorInfo->AbilitySystemComponent->TryActivateAbility(Spec.Handle);
}

void UWarriorGameplayAbility::EndAbility(...) {
    Super::EndAbility(...);
    if (AbilityActivationPolicy == EWarriorAbilityActivationPolicy::OnGiven)
        if (ActorInfo) ActorInfo->AbilitySystemComponent->ClearAbility(Handle);
}

Why spawn a weapon through an ability?

The weapon actor

AWarriorWeaponBase::AWarriorWeaponBase() {
    PrimaryActorTick.bCanEverTick = true;               // ← see below
    WeaponMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WeaponMesh"));
    SetRootComponent(WeaponMesh);
    WeaponCollisionBox = CreateDefaultSubobject<UBoxComponent>(TEXT("WeaponsCollisionBox"));
    WeaponCollisionBox->SetupAttachment(GetRootComponent());
    WeaponCollisionBox->SetBoxExtent(FVector(20.f));
    WeaponCollisionBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
Spot it

AWarriorWeaponBase has bCanEverTick = true but no Tick function. That's template boilerplate. Every spawned weapon registers a tick that does nothing. Set it to false, as the base character already does. It's a small thing, but it's exactly the point your mock Q5/Q6 answers were about.

Quiz yourself

OnTriggered vs OnGiven: what's the difference in behaviour?

OnTriggered waits for something (input, an event) to activate it. OnGiven activates itself the moment it's granted and, in this project, clears itself from the ASC when it ends.

What is an FGameplayAbilitySpec, and what's its handle for?

A granted instance of an ability on an ASC (class, level, input and so on). The handle is its ID, used to activate, cancel or clear that specific grant.

Why clear an OnGiven ability in EndAbility?

It's a one-shot (spawn the weapon). Leaving it granted is clutter, and it could be activated again by accident.

Why does the weapon's collision box start at NoCollision?

It should only register hits during the attack's active frames. It gets toggled on and off from the attack animation (anim notify state), so carrying or idling doesn't deal damage.

Why must a UENUM(BlueprintType) be : uint8?

Blueprint only supports byte-sized enums.

What's wasteful in AWarriorWeaponBase's constructor?

bCanEverTick = true with no Tick. Each weapon registers an empty tick function every frame. Set it false.