[UE GAS] 아이템 상자 구현

장식이펙트와 아이템 상자의 구현
- 장식 이펙트를 담당하는 게임플레이 큐의 활용방법의 학습
- 기간형 게임플레이 이펙트를 활용한 다양한 아이템 상자의 구현
- GAS의다양한 API를 활용한 무기에 관련된 게임플레이 이벤트와 어트리뷰트의 설정
목차
기획
게임플레이 이펙트를 활용한 아이템과 무기 기획
- 데미지, 회복상자의 구현
- 체력 레젠(Regeneration) 상자, DOT(Damage over time) 상자의 구현
- 캐릭터에 무기 추가
- 무기로 인한 공격 범위 증가: 75
- 무기로 인한 공격력 증가: 100
핵심 컴포넌트


Gameplay Cue를 활용한 캐릭터 피격 이펙트 구현
게임플레이 큐 Gameplay Cue
Gameplay Cue
- 시각 이펙트나 사운드와 같은 게임 로직과 무관한 시각적, 청각적 기능을 담당함
- Client부분에만 사용하고 Dedicated Server에서는 사용할 필요가 없음
- 두 종류의 Gameplay Queue가 있음
- Static Gameplay Cue : 일시적으로 발생하는 특수효과 사용. Execute 이벤트 발동.
- Actor Gameplay Queue : 일정 기간동안 발생하는 특수효과에 사용. Add/Remove 이벤트 발동.
- C++로도 구현할수 있지만, Blueprint로 제작하는 것이 더 생산적임.
- GameplayEffect(GE)에서 자동으로 GamplayCue(GC)와 연동할수 있도록 기능을 제공하고 있음.
- Gameplay Queue의 재생은 GameplayCueManager가 관리함. ( 다른 시스템과 분리된 구조)
- Gameplay Tag를 사용해 쉽게 발동시킬 수 있음
- 이 때 반드시 GameplayCue로시작하는 Gameplay Tag를 사용해야 함.
GameplayCue에 쓸 GameplayTags 지정하기
Project Settings - GameplayTags - Gameplay Tag List
- GameplayCue.Character.AttackHit : 캐릭터에 맞았을 때 발동하는 특수효과를 의미하는 태그
- GameplayCue.Character.Damage : 캐릭터가 맞았을 때 들어가는 데미지를 의미하는 태그
- GameplayCue.Chest.Open : 를 의미하는 태그

ABGC_AttackHit 생성
캐릭터를 공격해서 명중했을때 이펙트가 터지는 이펙트
GameplayCueNotify_Static - GC_ABGC_AttackHit 생성


ABGC_AttackHit.h
#pragma once #include "CoreMinimal.h" #include "GameplayCueNotify_Static.h" #include "ABGC_AttackHit.generated.h" UCLASS() class ARENABATTLEGAS_API UABGC_AttackHit : public UGameplayCueNotify_Static { GENERATED_BODY() public: UABGC_AttackHit(); virtual bool OnExecute_Implementation(AActor* Target, const FGameplayCueParameters& Parameters) const override; protected: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=GameplayCue) TObjectPtr<class UParticleSystem> ParticleSystem; };
ABGC_AttackHit.cpp
#include "GC/ABGC_AttackHit.h" #include "Particles/ParticleSystem.h" #include "Kismet/GameplayStatics.h" UABGC_AttackHit::UABGC_AttackHit() { static ConstructorHelpers::FObjectFinder<UParticleSystem> ExplosionRef(TEXT("/Script/Engine.ParticleSystem'/Game/StarterContent/Particles/P_Explosion.P_Explosion'")); if (ExplosionRef.Object) { ParticleSystem = ExplosionRef.Object; // 파티클 이펙트 지정 } } bool UABGC_AttackHit::OnExecute_Implementation(AActor* Target, const FGameplayCueParameters& Parameters) const { const FHitResult* HitResult = Parameters.EffectContext.GetHitResult(); if (HitResult) { UGameplayStatics::SpawnEmitterAtLocation(Target, ParticleSystem, HitResult->ImpactPoint, FRotator::ZeroRotator, true); // 충돌 위치에 스폰 } return false; }
※ GameplayEffectTypes.h
HitResult는 FGameplayEffectContextHandle에 담겨 전달된다.


ABGC_AttackHit 클래스를 상속받는 BPGC_AttackHit 생성

ABGA_AttackHitCheck
ABGA_AttackHitCheck.h
#pragma once #include "CoreMinimal.h" #include "Abilities/GameplayAbility.h" #include "ABGA_AttackHitCheck.generated.h" UCLASS() class ARENABATTLEGAS_API UABGA_AttackHitCheck : public UGameplayAbility { GENERATED_BODY() public: UABGA_AttackHitCheck(); virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override; protected: UFUNCTION() void OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle); UPROPERTY(EditAnywhere, Category = "GAS") TSubclassOf<class UGameplayEffect> AttackDamageEffect; UPROPERTY(EditAnywhere, Category = "GAS") TSubclassOf<class UGameplayEffect> AttackBuffEffect; float CurrentLevel; // CurveTable의 현재레벨 변수 };
ABGA_AttackHitCheck.cpp
#include "GA/ABGA_AttackHitCheck.h" #include "ArenaBattleGAS.h" #include "AbilitySystemBlueprintLibrary.h" #include "GA/AT/ABAT_Trace.h" #include "GA/TA/ABTA_Trace.h" #include "Attribute/ABCharacterAttributeSet.h" #include "ArenaBattleGAS.h" #include "Tag/ABGameplayTag.h" UABGA_AttackHitCheck::UABGA_AttackHitCheck() { InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor; } void UABGA_AttackHitCheck::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) { Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData); CurrentLevel = TriggerEventData->EventMagnitude; UABAT_Trace* AttackTraceTask = UABAT_Trace::CreateTask(this, AABTA_Trace::StaticClass()); AttackTraceTask->OnComplete.AddDynamic(this, &UABGA_AttackHitCheck::OnTraceResultCallback); AttackTraceTask->ReadyForActivation(); } void UABGA_AttackHitCheck::OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle) { if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetDataHandle, 0)) { FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 0); ABGAS_LOG(LogABGAS, Log, TEXT("Target %s Detected"), *(HitResult.GetActor()->GetName())); UAbilitySystemComponent* SourceASC = GetAbilitySystemComponentFromActorInfo_Checked(); UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(HitResult.GetActor()); const UABCharacterAttributeSet* SourceAttribute = SourceASC->GetSet<UABCharacterAttributeSet>(); FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(AttackDamageEffect, CurrentLevel); if (EffectSpecHandle.IsValid()) { ApplyGameplayEffectSpecToTarget(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, EffectSpecHandle, TargetDataHandle); FGameplayEffectContextHandle CueContextHandle = UAbilitySystemBlueprintLibrary::GetEffectContext(EffectSpecHandle); CueContextHandle.AddHitResult(HitResult); FGameplayCueParameters CueParam; CueParam.EffectContext = CueContextHandle; TargetASC->ExecuteGameplayCue(ABTAG_GAMEPLAYCUE_CHARACTER_ATTACKHIT, CueParam); } FGameplayEffectSpecHandle BuffEffectSpecHandle = MakeOutgoingGameplayEffectSpec(AttackBuffEffect); if (BuffEffectSpecHandle.IsValid()) { ApplyGameplayEffectSpecToOwner(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, BuffEffectSpecHandle); } } bool bReplicatedEndAbility = true; bool bWasCancelled = false; EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, bReplicatedEndAbility, bWasCancelled); }
void UABGA_AttackHitCheck::OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
- if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetDataHandle, 0))
- if (EffectSpecHandle.IsValid())
- ApplyGameplayEffectSpecToTarget(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, EffectSpecHandle, TargetDataHandle);
- FGameplayEffectContextHandle CueContextHandle = UAbilitySystemBlueprintLibrary::GetEffectContext(EffectSpecHandle);
CueContextHandle.AddHitResult(HitResult);
FGameplayCueParameters CueParam;
CueParam.EffectContext = CueContextHandle; - TargetASC->ExecuteGameplayCue(ABTAG_GAMEPLAYCUE_CHARACTER_ATTACKHIT, CueParam);
- ApplyGameplayEffectSpecToTarget(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, EffectSpecHandle, TargetDataHandle);
- if (EffectSpecHandle.IsValid())
실행화면

아이템 상자의 구현하기
ABGASItemBox 생성
Actor - ABGASItemBox 생성


ABGASItemBox.h
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "AbilitySystemInterface.h" #include "GameplayTagContainer.h" #include "ABGASItemBox.generated.h" UCLASS() class ARENABATTLEGAS_API AABGASItemBox : public AActor, public IAbilitySystemInterface { GENERATED_BODY() public: AABGASItemBox(); virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override; virtual void NotifyActorBeginOverlap(class AActor* Other) override; protected: virtual void PostInitializeComponents() override; void ApplyEffectToTarget(AActor* Target); // ItemBox을 먹은 대상에게 GE를 적용 void InvokeGameplayCue(AActor* Target); // ItemBox 자체의 이펙트를 재생하기 위한 Cue protected: UPROPERTY() TObjectPtr<class UAbilitySystemComponent> ASC; UPROPERTY(VisibleAnywhere, Category = Box) TObjectPtr<class UBoxComponent> Trigger; UPROPERTY(VisibleAnywhere, Category = Box) TObjectPtr<class UStaticMeshComponent> Mesh; UPROPERTY(EditAnywhere, Category = GAS) TSubclassOf<class UGameplayEffect> GameplayEffectClass; UPROPERTY(EditAnywhere, Category = GAS, Meta = (Categories=GameplayCue)) FGameplayTag GameplayCueTag; };
ABGASItemBox.cpp
#include "Item/ABGASItemBox.h" #include "AbilitySystemComponent.h" #include "Components/BoxComponent.h" #include "Components/StaticMeshComponent.h" #include "Physics/ABCollision.h" #include "AbilitySystemBlueprintLibrary.h" AABGASItemBox::AABGASItemBox() { ASC = CreateDefaultSubobject<UAbilitySystemComponent>(TEXT("ASC")); Trigger = CreateDefaultSubobject<UBoxComponent>(TEXT("Trigger")); Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh")); RootComponent = Trigger; Mesh->SetupAttachment(Trigger); Trigger->SetCollisionProfileName(CPROFILE_ABTRIGGER); Trigger->SetBoxExtent(FVector(40.0f, 42.0f, 30.0f)); static ConstructorHelpers::FObjectFinder<UStaticMesh> BoxMeshRef(TEXT("/Script/Engine.StaticMesh'/Game/ArenaBattle/Environment/Props/SM_Env_Breakables_Box1.SM_Env_Breakables_Box1'")); if (BoxMeshRef.Object) { Mesh->SetStaticMesh(BoxMeshRef.Object); } Mesh->SetRelativeLocation(FVector(0.0f, -3.5f, -30.0f)); Mesh->SetCollisionProfileName(TEXT("NoCollision")); } UAbilitySystemComponent* AABGASItemBox::GetAbilitySystemComponent() const { return ASC; } void AABGASItemBox::NotifyActorBeginOverlap(AActor* Other) { Super::NotifyActorBeginOverlap(Other); InvokeGameplayCue(Other); // ItemBox 자체의 이펙트를 재생 ApplyEffectToTarget(Other); // ItemBox을 먹은 Target에서 이펙트를 재생 Mesh->SetHiddenInGame(true); // 매쉬를 숨김 SetActorEnableCollision(false); // 충돌x SetLifeSpan(2.0f); } void AABGASItemBox::PostInitializeComponents() { Super::PostInitializeComponents(); ASC->InitAbilityActorInfo(this, this); // ItemBox 초기화 } void AABGASItemBox::ApplyEffectToTarget(AActor* Target) { UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Target); if (TargetASC) { FGameplayEffectContextHandle EffectContext = TargetASC->MakeEffectContext(); EffectContext.AddSourceObject(this); FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1, EffectContext); if (EffectSpecHandle.IsValid()) { //TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get()); // C++ Ver. TargetASC->BP_ApplyGameplayEffectSpecToSelf(EffectSpecHandle); // BP Ver. } } } void AABGASItemBox::InvokeGameplayCue(AActor* Target) // 자기 자신(=ItemBox)에게 특수효과를 재생 { FGameplayCueParameters Param; Param.SourceObject = this; Param.Instigator = Target; Param.Location = GetActorLocation(); ASC->ExecuteGameplayCue(GameplayCueTag, Param); }
일반 데미지 버젼 - BPGE_Damage

Dot 데미지 버젼 - BPGE_Dot

BPGE_CharaterStat 생성

BPGC_ChestOpen 생성
GameplayCueNotify_Static - BPGC_ChestOpen 생성


BPGE_Damage 생성 + BPGC_Damage 생성
BPGE_Damage
GameplayEffect - BPGE_Damage 생성


BPGC_Damage

BPGE_Heal 생성 + BPGE_Regen 생성
BPGE_Heal

BPGE_Regen

실행화면

무적상태로 만드는 아이템 상자
BPGE_Invincible + BPGE_InvincibleInf + BPGE_InvincibleRemove 생성



무기를 주는 아이템 상자
ABGASWeaponBox 생성
ABGASItemBox - ABGASWeaponBox 생성


ABGASWeaponBox.h
#pragma once #include "CoreMinimal.h" #include "Item/ABGASItemBox.h" #include "ABGASWeaponBox.generated.h" UCLASS() class ARENABATTLEGAS_API AABGASWeaponBox : public AABGASItemBox { GENERATED_BODY() protected: virtual void NotifyActorBeginOverlap(AActor* Other) override; protected: UPROPERTY(EditAnywhere, Category = GAS, Meta=(Categories=Event)) FGameplayTag WeaponEventTag; };
ABGASWeaponBox.cpp
#include "Item/ABGASWeaponBox.h" #include "AbilitySystemBlueprintLibrary.h" void AABGASWeaponBox::NotifyActorBeginOverlap(AActor* Other) { Super::NotifyActorBeginOverlap(Other); UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(Other, WeaponEventTag, FGameplayEventData()); }
이 이벤트를 캐릭터(=ABGASCharacterPlayer)가 직접 수신을 하게 된다.
ABGASCharacterPlayer
ABGASCharacterPlayer.h
#pragma once #include "CoreMinimal.h" #include "Character/ABCharacterPlayer.h" #include "AbilitySystemInterface.h" #include "Abilities/GameplayAbilityTypes.h" #include "ABGASCharacterPlayer.generated.h" UCLASS() class ARENABATTLEGAS_API AABGASCharacterPlayer : public AABCharacterPlayer, public IAbilitySystemInterface { GENERATED_BODY() public: AABGASCharacterPlayer(); virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override; virtual void PossessedBy(AController* NewController) override; virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; protected: void SetupGASInputComponent(); void GASInputPressed(int32 InputId); void GASInputReleased(int32 InputId); UFUNCTION() virtual void OnOutOfHealth(); void EquipWeapon(const FGameplayEventData* EventData); void UnequipWeapon(const FGameplayEventData* EventData); protected: UPROPERTY(EditAnywhere, Category = GAS) TObjectPtr<class UAbilitySystemComponent> ASC; UPROPERTY(EditAnywhere, Category = GAS) TArray<TSubclassOf<class UGameplayAbility>> StartAbilities; UPROPERTY(EditAnywhere, Category = GAS) TMap<int32, TSubclassOf<class UGameplayAbility>> StartInputAbilities; UPROPERTY(VisibleAnywhere) TObjectPtr<class UABGASWidgetComponent> HpBar; UPROPERTY(EditAnywhere, Category = Weapon) TObjectPtr<class USkeletalMesh> WeaponMesh; UPROPERTY(EditAnywhere, Category = Weapon) float WeaponRange; UPROPERTY(EditAnywhere, Category = Weapon) float WeaponAttackRate; };
변경사항 없음
ABGASCharacterPlayer.cpp
#include "Character/ABGASCharacterPlayer.h" #include "AbilitySystemComponent.h" #include "Player/ABGASPlayerState.h" #include "EnhancedInputComponent.h" #include "UI/ABGASWidgetComponent.h" #include "UI/ABGASUserWidget.h" #include "Attribute/ABCharacterAttributeSet.h" #include "Tag/ABGameplayTag.h" AABGASCharacterPlayer::AABGASCharacterPlayer() { ASC = nullptr; static ConstructorHelpers::FObjectFinder<UAnimMontage> ComboActionMontageRef(TEXT("/Script/Engine.AnimMontage'/Game/ArenaBattleGAS/Animation/AM_ComboAttack.AM_ComboAttack'")); if (ComboActionMontageRef.Object) { ComboActionMontage = ComboActionMontageRef.Object; } HpBar = CreateDefaultSubobject<UABGASWidgetComponent>(TEXT("Widget")); HpBar->SetupAttachment(GetMesh()); HpBar->SetRelativeLocation(FVector(0.0f, 0.0f, 180.0f)); static ConstructorHelpers::FClassFinder<UUserWidget> HpBarWidgetRef(TEXT("/Game/ArenaBattle/UI/WBP_HpBar.WBP_HpBar_C")); if (HpBarWidgetRef.Class) { HpBar->SetWidgetClass(HpBarWidgetRef.Class); HpBar->SetWidgetSpace(EWidgetSpace::Screen); HpBar->SetDrawSize(FVector2D(200.0f, 20.f)); HpBar->SetCollisionEnabled(ECollisionEnabled::NoCollision); } static ConstructorHelpers::FObjectFinder<USkeletalMesh> WeaponMeshRef(TEXT("/Script/Engine.SkeletalMesh'/Game/InfinityBladeWeapons/Weapons/Blunt/Blunt_Hellhammer/SK_Blunt_HellHammer.SK_Blunt_HellHammer'")); if (WeaponMeshRef.Object) { WeaponMesh = WeaponMeshRef.Object; } WeaponRange = 75.f; WeaponAttackRate = 100.0f; } UAbilitySystemComponent* AABGASCharacterPlayer::GetAbilitySystemComponent() const { return ASC; } void AABGASCharacterPlayer::PossessedBy(AController* NewController) { Super::PossessedBy(NewController); AABGASPlayerState* GASPS = GetPlayerState<AABGASPlayerState>(); if (GASPS) { ASC = GASPS->GetAbilitySystemComponent(); ASC->InitAbilityActorInfo(GASPS, this); ASC->GenericGameplayEventCallbacks.FindOrAdd(ABTAG_EVENT_CHARACTER_WEAPONEQUIP).AddUObject(this, &AABGASCharacterPlayer::EquipWeapon); ASC->GenericGameplayEventCallbacks.FindOrAdd(ABTAG_EVENT_CHARACTER_WEAPONUNEQUIP).AddUObject(this, &AABGASCharacterPlayer::UnequipWeapon); const UABCharacterAttributeSet* CurrentAttributeSet = ASC->GetSet<UABCharacterAttributeSet>(); if (CurrentAttributeSet) { CurrentAttributeSet->OnOutOfHealth.AddDynamic(this, &ThisClass::OnOutOfHealth); } for (const auto& StartAbility : StartAbilities) { FGameplayAbilitySpec StartSpec(StartAbility); ASC->GiveAbility(StartSpec); } for (const auto& StartInputAbility : StartInputAbilities) { FGameplayAbilitySpec StartSpec(StartInputAbility.Value); StartSpec.InputID = StartInputAbility.Key; ASC->GiveAbility(StartSpec); } SetupGASInputComponent(); APlayerController* PlayerController = CastChecked<APlayerController>(NewController); PlayerController->ConsoleCommand(TEXT("showdebug abilitysystem")); } } void AABGASCharacterPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); SetupGASInputComponent(); } void AABGASCharacterPlayer::SetupGASInputComponent() { if (IsValid(ASC) && IsValid(InputComponent)) { UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(InputComponent); EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &AABGASCharacterPlayer::GASInputPressed, 0); EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &AABGASCharacterPlayer::GASInputReleased, 0); EnhancedInputComponent->BindAction(AttackAction, ETriggerEvent::Triggered, this, &AABGASCharacterPlayer::GASInputPressed, 1); } } void AABGASCharacterPlayer::GASInputPressed(int32 InputId) { FGameplayAbilitySpec* Spec = ASC->FindAbilitySpecFromInputID(InputId); if (Spec) { Spec->InputPressed = true; if (Spec->IsActive()) { ASC->AbilitySpecInputPressed(*Spec); } else { ASC->TryActivateAbility(Spec->Handle); } } } void AABGASCharacterPlayer::GASInputReleased(int32 InputId) { FGameplayAbilitySpec* Spec = ASC->FindAbilitySpecFromInputID(InputId); if (Spec) { Spec->InputPressed = false; if (Spec->IsActive()) { ASC->AbilitySpecInputReleased(*Spec); } } } void AABGASCharacterPlayer::OnOutOfHealth() { SetDead(); } void AABGASCharacterPlayer::EquipWeapon(const FGameplayEventData* EventData) { if (Weapon) { Weapon->SetSkeletalMesh(WeaponMesh); const float CurrentAttackRange = ASC->GetNumericAttributeBase(UABCharacterAttributeSet::GetAttackRangeAttribute()); const float CurrentAttackRate = ASC->GetNumericAttributeBase(UABCharacterAttributeSet::GetAttackRateAttribute()); ASC->SetNumericAttributeBase(UABCharacterAttributeSet::GetAttackRangeAttribute(), CurrentAttackRange + WeaponRange); ASC->SetNumericAttributeBase(UABCharacterAttributeSet::GetAttackRateAttribute(), CurrentAttackRate + WeaponAttackRate); } } void AABGASCharacterPlayer::UnequipWeapon(const FGameplayEventData* EventData) { if (Weapon) { const float CurrentAttackRange = ASC->GetNumericAttributeBase(UABCharacterAttributeSet::GetAttackRangeAttribute()); const float CurrentAttackRate = ASC->GetNumericAttributeBase(UABCharacterAttributeSet::GetAttackRateAttribute()); ASC->SetNumericAttributeBase(UABCharacterAttributeSet::GetAttackRangeAttribute(), CurrentAttackRange - WeaponRange); ASC->SetNumericAttributeBase(UABCharacterAttributeSet::GetAttackRateAttribute(), CurrentAttackRate - WeaponAttackRate); Weapon->SetSkeletalMesh(nullptr); } }
void AABGASCharacterPlayer::PossessedBy(AController* NewController)
- if (GASPS)
- ASC->GenericGameplayEventCallbacks.FindOrAdd(ABTAG_EVENT_CHARACTER_WEAPONEQUIP).AddUObject(this, &AABGASCharacterPlayer::EquipWeapon);
- ASC->GenericGameplayEventCallbacks.FindOrAdd(ABTAG_EVENT_CHARACTER_WEAPONUNEQUIP).AddUObject(this, &AABGASCharacterPlayer::UnequipWeapon);
- GenericGameplayEventCallbacks는 FGameplayTag와 FGameplayEventMulticastDelegate를 받는다.

void AABGASCharacterPlayer::EquipWeapon(const FGameplayEventData* EventData)
void AABGASCharacterPlayer::UnequipWeapon(const FGameplayEventData* EventData)
실행화면

정리
아이템 상자 구현
- 공격 명중시 장식 이펙트를 추가로 발동시키기
- 기간형 게임플레이 이펙트의 주기 설정이 가지는 특징의 학습
- 게임 이펙트 설정으로 장식 이펙트를 발동시키는 방법의 학습
- 태그 설정을 활용한 게임플레이 이펙트 및 태그의 제거
- 게임이벤트 발동과 어트리뷰트 직접 접근을 통한 무기추가와 제거 구현
'⭐ Unreal Engine > UE Game Ability System(GAS)' 카테고리의 다른 글
[UE GAS] 캐릭터의 광역 스킬 구현 (0) | 2024.03.10 |
---|---|
[UE GAS] 어트리뷰트와 UI 연동 Integration with Attribute and UI (0) | 2024.03.09 |
[UE GAS] 게임플레이 이펙트의 활용 Applying Gameplay Effect (0) | 2024.03.08 |
[UE GAS] 캐릭터 어트리뷰트 설정 (0) | 2024.03.07 |
[UE GAS] 공격 판정 시스템의 구현 (0) | 2024.03.06 |
댓글
이 글 공유하기
다른 글
-
[UE GAS] 캐릭터의 광역 스킬 구현
[UE GAS] 캐릭터의 광역 스킬 구현
2024.03.10 -
[UE GAS] 어트리뷰트와 UI 연동 Integration with Attribute and UI
[UE GAS] 어트리뷰트와 UI 연동 Integration with Attribute and UI
2024.03.09 -
[UE GAS] 게임플레이 이펙트의 활용 Applying Gameplay Effect
[UE GAS] 게임플레이 이펙트의 활용 Applying Gameplay Effect
2024.03.08 -
[UE GAS] 캐릭터 어트리뷰트 설정
[UE GAS] 캐릭터 어트리뷰트 설정
2024.03.07다른 GAS 액터의 상황을 확인할 수 있는 디버그 시스템 설정 방법의 학습 기본 캐릭터 어트리뷰트 설정 방법의 학습 공격 대상의 어트리뷰트 값을 변경하는 방법의 학습 특정 어트리뷰트 변경 시 사전, 사후 점검하는 방법의 학습 인프런 이득우님의 '언리얼 프로그래밍 Part4 - 게임플레이 어빌리티 시스템' 강의를 참고하였습니다. 😎 [이득우의 언리얼 프로그래밍 Part4 - 게임플레이 어빌리티 시스템] 강의 들으러 가기! 목차 캐릭터 어트리뷰트 설정 방향 캐릭터 어트리뷰트 설정 기획 캐릭터에 설정할 어트리뷰트 목록 기본 어트리뷰트 체력 Health 일반 공격 길이 AttackRange 일반 공격 변경 AttackRadius 일반 공격력 AttackRate 최대값 어트리뷰트 최대 체력 MaxHealth 최대…
댓글을 사용할 수 없습니다.