Skip to content

Instantly share code, notes, and snippets.

@puttputt
Created January 29, 2021 02:53
Show Gist options
  • Save puttputt/72c7a9d5c5a5f423e353bc019f76aefa to your computer and use it in GitHub Desktop.
Save puttputt/72c7a9d5c5a5f423e353bc019f76aefa to your computer and use it in GitHub Desktop.
UE4 Gameplay Ability System Basic Implementation
#include "BasicAttributeSet.h"
#include "GameplayEffect.h"
#include "GameplayEffectExtension.h"
void UBasicAttributeSet::PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
//Clamping Health based on Max Health.
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
}
}
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "BasicAttributeSet.generated.h"
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class GASNOOB_API UBasicAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data) override;
UPROPERTY(BlueprintReadOnly, Category = "GAS|Health")
FGameplayAttributeData MaxHealth;
ATTRIBUTE_ACCESSORS(UBasicAttributeSet, MaxHealth)
UPROPERTY(BlueprintReadOnly, Category = "GAS|Health")
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UBasicAttributeSet, Health)
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "BasicCharacter.h"
// Sets default values
ABasicCharacter::ABasicCharacter()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("AbilitySystemComponent"));
AttributeSet = CreateDefaultSubobject<UBasicAttributeSet>(TEXT("AttributeSet"));
}
// Called when the game starts or when spawned
void ABasicCharacter::BeginPlay()
{
Super::BeginPlay();
InitializeAttributes();
if (IsValid(AbilitySystemComponent))
{
AbilitySystemComponent->GetSet<UAttributeSet>();
//GetGameplayAttributeValueChangedDelegate will enable you to bind delegates without programming them manually.
AbilitySystemComponent->InitAbilityActorInfo(this, this);
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeSet->GetHealthAttribute()).AddUObject(this, &ABasicCharacter::HandleHealthChanged);
}
}
// Called every frame
void ABasicCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void ABasicCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
UAbilitySystemComponent* ABasicCharacter::GetAbilitySystemComponent() const
{
return AbilitySystemComponent;
}
void ABasicCharacter::InitializeAttributes()
{
if (!IsValid(AbilitySystemComponent))
{
return;
}
if (!DefaultAttributes)
{
UE_LOG(LogTemp, Error, TEXT("%s() Missing DefaultAttributes for %s. Please fill in the character's Blueprint."), *FString(__FUNCTION__), *GetName());
return;
}
FGameplayEffectContextHandle EffectContext = AbilitySystemComponent->MakeEffectContext();
EffectContext.AddSourceObject(this);
FGameplayEffectSpecHandle NewHandle = AbilitySystemComponent->MakeOutgoingSpec(DefaultAttributes, 0, EffectContext);
if (NewHandle.IsValid())
{
FActiveGameplayEffectHandle ActiveGEHandle = AbilitySystemComponent->ApplyGameplayEffectSpecToTarget(*NewHandle.Data.Get(), AbilitySystemComponent);
}
}
void ABasicCharacter::GrantAbility(TSubclassOf<UGameplayAbility> AbilityClass, int32 Level, int32 InputCode)
{
if (GetLocalRole() == ROLE_Authority && IsValid(AbilitySystemComponent) && IsValid(AbilityClass))
{
UGameplayAbility* Ability = AbilityClass->GetDefaultObject<UGameplayAbility>();
if (IsValid(Ability))
{
FGameplayAbilitySpec AbilitySpec(
Ability,
Level,
InputCode
);
AbilitySystemComponent->GiveAbility(AbilitySpec);
}
}
}
void ABasicCharacter::ActivateAbility(int32 InputCode)
{
if (IsValid(AbilitySystemComponent))
{
AbilitySystemComponent->AbilityLocalInputPressed(InputCode);
}
}
float ABasicCharacter::GetHealth() const
{
if (!AttributeSet)
return 1.f;
return AttributeSet->GetHealth();
}
void ABasicCharacter::HandleHealthChanged(const FOnAttributeChangeData& Data)
{
OnHealthChanged(Data.NewValue);
}
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AbilitySystemInterface.h"
#include "AbilitySystemComponent.h"
#include "BasicAttributeSet.h"
#include "BasicCharacter.generated.h"
UCLASS()
class GASNOOB_API ABasicCharacter : public ACharacter, public IAbilitySystemInterface
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ABasicCharacter();
UAbilitySystemComponent* GetAbilitySystemComponent() const override;
UFUNCTION(BlueprintCallable)
virtual float GetHealth() const;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void InitializeAttributes();
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "GAS|Abilities")
class UAbilitySystemComponent* AbilitySystemComponent;
UPROPERTY()
UBasicAttributeSet* AttributeSet;
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "GAS|Abilities")
TSubclassOf<class UGameplayEffect> DefaultAttributes;
UFUNCTION(BlueprintCallable, Category = "GAS|Abilities")
void ActivateAbility(int32 InputCode);
UFUNCTION(BlueprintCallable, Category = "GAS|Abilities")
void GrantAbility(TSubclassOf<UGameplayAbility> AbilityClass, int32 Level, int32 InputCode);
UFUNCTION(BlueprintImplementableEvent)
void OnHealthChanged(float DeltaValue);
void HandleHealthChanged(const FOnAttributeChangeData& Data);
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
using UnrealBuildTool;
public class GASNOOB : ModuleRules
{
public GASNOOB(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
PrivateDependencyModuleNames.AddRange(new string[] {
"GameplayAbilities",
"GameplayTags",
"GameplayTasks"
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment