mirror of
https://github.com/Donchitos/Claude-Code-Game-Studios.git
synced 2026-10-16 01:37:05 +00:00
Fix release for 1.1.1: the minimal path end to end, engine commands that run on Godot, Unity and Unreal, hook warnings you can see, and verdicts that say when they could not check. Details in CHANGELOG.md; upgrade steps in UPGRADING.md (v1.1.1 → v1.1.2). Fixes #67 Fixes #131 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WuJn2FdynEybfL5KC697nJ
12 KiB
12 KiB
Unreal Engine 5.7 — Gameplay Ability System (GAS)
Last verified: 2026-02-13
Status: Production-Ready
Plugin: GameplayAbilities (built-in, enable in Plugins)
Overview
Gameplay Ability System (GAS) is a modular framework for building abilities, attributes, effects, and gameplay mechanics. It's the standard for RPGs, MOBAs, shooters with abilities, and any game with complex ability systems.
Use GAS for:
- Character abilities (spells, skills, attacks)
- Attributes (health, mana, stamina, stats)
- Buffs/debuffs (temporary effects)
- Cooldowns and costs
- Damage calculation
- Multiplayer-ready ability replication
Core Concepts
1. Ability System Component (ASC)
- The main component that owns abilities, attributes, and effects
- Added to Characters or PlayerStates
2. Gameplay Abilities
- Individual skills/actions (fireball, heal, dash, etc.)
- Activated, committed (cost/cooldown), and can be cancelled
3. Attributes & Attribute Sets
- Stats that can be modified (Health, Mana, Stamina, Strength, etc.)
- Stored in Attribute Sets
4. Gameplay Effects
- Modify attributes (damage, healing, buffs, debuffs)
- Can be instant, duration-based, or infinite
5. Gameplay Tags
- Hierarchical tags for ability logic (e.g.,
Ability.Attack.Melee,Status.Stunned)
Setup
1. Enable Plugin
Edit > Plugins > Gameplay Abilities > Enabled > Restart
2. Add Ability System Component
#include "AbilitySystemComponent.h"
#include "AttributeSet.h"
UCLASS()
class AMyCharacter : public ACharacter {
GENERATED_BODY()
public:
AMyCharacter() {
// Create ASC
AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("AbilitySystem"));
AbilitySystemComponent->SetIsReplicated(true);
AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);
// Create Attribute Set
AttributeSet = CreateDefaultSubobject<UMyAttributeSet>(TEXT("AttributeSet"));
}
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Abilities")
TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;
UPROPERTY()
TObjectPtr<const UAttributeSet> AttributeSet;
};
3. Initialize ASC (Important for Multiplayer)
void AMyCharacter::PossessedBy(AController* NewController) {
Super::PossessedBy(NewController);
// Server: Initialize ASC
if (AbilitySystemComponent) {
AbilitySystemComponent->InitAbilityActorInfo(this, this);
GiveDefaultAbilities();
}
}
void AMyCharacter::OnRep_PlayerState() {
Super::OnRep_PlayerState();
// Client: Initialize ASC
if (AbilitySystemComponent) {
AbilitySystemComponent->InitAbilityActorInfo(this, this);
}
}
Attributes & Attribute Sets
Create Attribute Set
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
UCLASS()
class UMyAttributeSet : public UAttributeSet {
GENERATED_BODY()
public:
UMyAttributeSet();
// Health
UPROPERTY(BlueprintReadOnly, Category = "Attributes", ReplicatedUsing = OnRep_Health)
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UMyAttributeSet, Health)
UPROPERTY(BlueprintReadOnly, Category = "Attributes", ReplicatedUsing = OnRep_MaxHealth)
FGameplayAttributeData MaxHealth;
ATTRIBUTE_ACCESSORS(UMyAttributeSet, MaxHealth)
// Mana
UPROPERTY(BlueprintReadOnly, Category = "Attributes", ReplicatedUsing = OnRep_Mana)
FGameplayAttributeData Mana;
ATTRIBUTE_ACCESSORS(UMyAttributeSet, Mana)
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
protected:
UFUNCTION()
virtual void OnRep_Health(const FGameplayAttributeData& OldHealth);
UFUNCTION()
virtual void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth);
UFUNCTION()
virtual void OnRep_Mana(const FGameplayAttributeData& OldMana);
};
Implement Attribute Set
#include "Net/UnrealNetwork.h"
UMyAttributeSet::UMyAttributeSet() {
// Default values
Health = 100.0f;
MaxHealth = 100.0f;
Mana = 50.0f;
}
void UMyAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const {
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(UMyAttributeSet, Health, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UMyAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(UMyAttributeSet, Mana, COND_None, REPNOTIFY_Always);
}
void UMyAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) {
GAMEPLAYATTRIBUTE_REPNOTIFY(UMyAttributeSet, Health, OldHealth);
}
// Implement other OnRep functions similarly...
Clamping Attributes
Attribute Sets have no built-in clamping: the Data Table Min Value and
Max Value columns have no effect. Clamp in the Attribute Set:
PreAttributeChange()is called just before any modification to an attribute, and is the hook for rules likeHealth = Clamp(Health, 0, MaxHealth)— itsNewValueis mutable.PreAttributeBaseChange()is called just before a change to an attribute's base value when an aggregator exists, andPostGameplayEffectExecute()just after a Gameplay Effect is executed to modify the base value — clamp base-value changes from instant effects there.
Stacking rules govern re-applications of the same Gameplay Effect; they do not bound one attribute pushed by different effects.
Gameplay Abilities
Create Gameplay Ability
#include "Abilities/GameplayAbility.h"
UCLASS()
class UGA_Fireball : public UGameplayAbility {
GENERATED_BODY()
public:
UGA_Fireball() {
// Ability config
InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
NetExecutionPolicy = EGameplayAbilityNetExecutionPolicy::ServerInitiated;
// Tags
// ⚠️ UNVERIFIED FOR 5.7 — `AbilityTags` may be deprecated in favour of
// SetAssetTags()/GetAssetTags(). Reported by the `unreal-specialist`
// agent (2026-08-12), which believed the change landed around 5.5 and
// correctly REFUSED to emit code on a symbol it could not verify.
// NOT SOURCEABLE offline: this repo has no 5.7 API dump to check against,
// and the same knowledge-gap warning that governs the agent governs this
// file. Verify against the UE 5.7 docs before using this snippet, and
// correct both occurrences (here and ~line 328) together.
AbilityTags.AddTag(FGameplayTag::RequestGameplayTag(FName("Ability.Attack.Fireball")));
}
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override {
if (!CommitAbility(Handle, ActorInfo, ActivationInfo)) {
// Failed to commit (not enough mana, on cooldown, etc.)
EndAbility(Handle, ActorInfo, ActivationInfo, true, true);
return;
}
// Spawn fireball projectile
SpawnFireball();
// End ability
EndAbility(Handle, ActorInfo, ActivationInfo, true, false);
}
void SpawnFireball() {
// Spawn fireball logic
}
};
Grant Abilities to Character
void AMyCharacter::GiveDefaultAbilities() {
if (!HasAuthority() || !AbilitySystemComponent) return;
// Grant abilities
AbilitySystemComponent->GiveAbility(FGameplayAbilitySpec(UGA_Fireball::StaticClass(), 1, INDEX_NONE, this));
AbilitySystemComponent->GiveAbility(FGameplayAbilitySpec(UGA_Heal::StaticClass(), 1, INDEX_NONE, this));
}
Activate Ability
// Activate by class
AbilitySystemComponent->TryActivateAbilityByClass(UGA_Fireball::StaticClass());
// Activate by tag
FGameplayTagContainer TagContainer;
TagContainer.AddTag(FGameplayTag::RequestGameplayTag(FName("Ability.Attack.Fireball")));
AbilitySystemComponent->TryActivateAbilitiesByTag(TagContainer);
Gameplay Effects
Create Gameplay Effect (Damage)
// Create Blueprint: Content Browser > Gameplay > Gameplay Effect
// OR in C++:
UCLASS()
class UGE_Damage : public UGameplayEffect {
GENERATED_BODY()
public:
UGE_Damage() {
// Instant damage
DurationPolicy = EGameplayEffectDurationType::Instant;
// Modifier: Reduce Health
FGameplayModifierInfo ModifierInfo;
ModifierInfo.Attribute = UMyAttributeSet::GetHealthAttribute();
ModifierInfo.ModifierOp = EGameplayModOp::Additive;
ModifierInfo.ModifierMagnitude = FScalableFloat(-25.0f); // -25 health
Modifiers.Add(ModifierInfo);
}
};
Apply Gameplay Effect
// Apply damage to target
if (UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Target)) {
FGameplayEffectContextHandle EffectContext = AbilitySystemComponent->MakeEffectContext();
EffectContext.AddSourceObject(this);
FGameplayEffectSpecHandle SpecHandle = AbilitySystemComponent->MakeOutgoingSpec(
UGE_Damage::StaticClass(), 1, EffectContext);
if (SpecHandle.IsValid()) {
AbilitySystemComponent->ApplyGameplayEffectSpecToTarget(*SpecHandle.Data.Get(), TargetASC);
}
}
Gameplay Tags
Define Tags
Project Settings > Project > Gameplay Tags > Gameplay Tag List
Example hierarchy:
Ability
├─ Ability.Attack
│ ├─ Ability.Attack.Melee
│ └─ Ability.Attack.Ranged
├─ Ability.Defend
└─ Ability.Utility
Status
├─ Status.Stunned
├─ Status.Invulnerable
└─ Status.Silenced
Use Tags in Abilities
UCLASS()
class UGA_MeleeAttack : public UGameplayAbility {
GENERATED_BODY()
public:
UGA_MeleeAttack() {
// This ability has these tags
AbilityTags.AddTag(FGameplayTag::RequestGameplayTag(FName("Ability.Attack.Melee")));
// Block these tags while active
BlockAbilitiesWithTag.AddTag(FGameplayTag::RequestGameplayTag(FName("Ability.Attack")));
// Cancel these abilities when activated
CancelAbilitiesWithTag.AddTag(FGameplayTag::RequestGameplayTag(FName("Ability.Defend")));
// Can't activate if target has these tags
ActivationBlockedTags.AddTag(FGameplayTag::RequestGameplayTag(FName("Status.Stunned")));
}
};
Cooldowns & Costs
Add Cooldown
// In Ability Blueprint or C++:
// Create Gameplay Effect with Duration = Cooldown time
// Assign to Ability > Cooldown Gameplay Effect Class
Add Cost (Mana)
// Create Gameplay Effect that reduces Mana
// Assign to Ability > Cost Gameplay Effect Class
Common Patterns
Get Current Attribute Value
float CurrentHealth = AbilitySystemComponent->GetNumericAttribute(UMyAttributeSet::GetHealthAttribute());
Listen for Attribute Changes
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(UMyAttributeSet::GetHealthAttribute())
.AddUObject(this, &AMyCharacter::OnHealthChanged);
void AMyCharacter::OnHealthChanged(const FOnAttributeChangeData& Data) {
UE_LOG(LogTemp, Warning, TEXT("Health: %f"), Data.NewValue);
}
Sources
- https://docs.unrealengine.com/5.7/en-US/gameplay-ability-system-for-unreal-engine/
- Clamping: Gameplay Attributes and Attribute Sets https://dev.epicgames.com/documentation/en-us/unreal-engine/gameplay-attributes-and-attribute-sets-for-the-gameplay-ability-system-in-unreal-engine ;
UAttributeSetAPI https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Plugins/GameplayAbilities/UAttributeSet ;PreAttributeChangehttps://dev.epicgames.com/documentation/en-us/unreal-engine/API/Plugins/GameplayAbilities/UAttributeSet/PreAttributeChange - https://github.com/tranek/GASDocumentation (community guide)