0. 개요
향상된 입력 시스템의 변화에 따라 어빌리티 활성화 이후 InputPress 함수가 호출되도록 바뀌었다.
변경된 구조를 이용하고 기존의 블루프린트 로직을 C++로 이관한다.
1. 범위 표시기 - MagicCircle 수정
어빌리티 내에서 Show Magic Circle / Hide Magic Circle을 이용하여 BP_MagicCircle을 생성 / 제거하고 있다.
이 때, UI에 나타나는 문구는 게임플레이 큐를 이용하는데, 이 게임플레이 큐를 각 어빌리티 내에서 부여하고 있다.
해당 로직을 MagicCircle 내로 옮긴다.
(1) MagicCircle
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnCircleInitialized, AActor*, AvatarActor);
UCLASS()
class AURA_API AMagicCircle : public AActor
{
GENERATED_BODY()
public:
AMagicCircle();
virtual void Tick(float DeltaTime) override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
TObjectPtr<UDecalComponent> MagicCircleDecal;
UPROPERTY(BlueprintAssignable)
FOnCircleInitialized CircleInitialized;
UPROPERTY(BlueprintAssignable)
FOnCircleInitialized RemoveCircle;
protected:
virtual void BeginPlay() override;
};
블루프린트 델리게이트를 추가하고 매개 변수로 액터를 넘겨준다.
(2) BP_MagicCircle


델리게이트에 각각 게임플레이 큐를 추가하는 이벤트와 태그를 제거하는 이벤트를 바인딩한다.
2. 아케인 파편 어빌리티 - C++
블루프린트 이벤트 그래프의 로직 대부분을 C++ 코드로 변경한다.
(1) 마우스 적중 결과 처리 함수
void UArcaneShards::ReceivedMouseHitResult(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{
if (!TargetDataHandle.IsValid(0))
return;
const FGameplayAbilityTargetData* TargetData = TargetDataHandle.Get(0);
const FHitResult* HitResult = TargetData->GetHitResult();
// 마우스 히트 정보를 멤버 변수로 만듬
CurrentMouseLocation = HitResult->ImpactPoint;
NumPoints = GetAbilityLevel();
GroundPoints.Empty();
// 어빌리티 업그레이드 확인
CheckAbilityUpgrades(FAuraGameplayTags::Get().Abilities_Arcane_ArcaneShards);
FTransform PointCollectionTransform;
PointCollectionTransform.SetLocation(CurrentMouseLocation);
PointCollection = GetWorld()->SpawnActorDeferred<APointCollection>(
PointCollectionClass,
PointCollectionTransform,
GetAvatarActorFromActorInfo(),
nullptr,
ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
PointCollection->FinishSpawning(PointCollectionTransform);
GroundPoints = PointCollection->GetGroundPoints(FMath::Min(NumPoints, MaxNumShards));
}
TargetDataUnderMouse가 반환하는 데이터 핸들을 직접 받아 바닥에 포인트 컬렉션을 생성하는 작업까지 진행한다.
(2) 타이머 설정 함수
void UArcaneShards::ReadyToSpawnShards()
{
AActor* AvatarActor = GetAvatarActorFromActorInfo();
// 범위 표시기 제거
if (AvatarActor->Implements<UPlayerInterface>())
{
IPlayerInterface::Execute_HideMagicCircle(AvatarActor);
}
// UI 범위기 메시지 제거
RemoveRangeSpellHelpMessage(AvatarActor);
if (UWorld* World = GetWorld())
{
World->GetTimerManager().SetTimer(ShardSpawnTimer, this, &UArcaneShards::SpawnShards,SpawnShardsDeltaTime, true);
}
// 쿨다운, 코스트 적용
CommitAbility(GetCurrentAbilitySpecHandle(),
GetCurrentActorInfo(),
GetCurrentActivationInfo());
}
범위 표시기를 제거하고 타이머를 생성하여 DeltaTime 변수에 따라서 파편 기둥을 소환한다.
(3) 파편 기둥 소환 - 타이머 핸들의 콜백 함수
void UArcaneShards::SpawnShards()
{
AActor* AvatarActor = GetAvatarActorFromActorInfo();
if (Idx < GroundPoints.Num())
{
// 파편 위치 계산
ShardSpawnLocation = GroundPoints[Idx]->GetComponentTransform().GetLocation();
ShardSpawnRotation = GroundPoints[Idx]->GetComponentTransform().GetRotation().Rotator();
TArray<AActor*> ActorsToIgnore;
ActorsToIgnore.Empty();
ActorsToIgnore.Add(AvatarActor);
TArray<AActor*> OutOverlappingActors;
OutOverlappingActors.Empty();
// 데미지 입힐 플레이어 계산
UAuraAbilitySystemLibrary::GetLivePlayersWithinRadius(
AvatarActor,
OutOverlappingActors,
ActorsToIgnore,
RadialDamageOuterRadius,
ShardSpawnLocation);
for (AActor* DamagedActor : OutOverlappingActors)
{
if (!IsValid(DamagedActor))
continue;
// 아군이라면 건너뛰기
if (!UAuraAbilitySystemLibrary::IsNotFriend(DamagedActor, AvatarActor))
{
continue;
}
// 클래스 디폴트를 이용하여 데미지 이펙트 파라미터 생성
FVector DirectionOverride = DamagedActor->GetActorLocation() - ShardSpawnLocation;
FDamageEffectParams Params = MakeDamageEffectParamsFromClassDefaults(
DamagedActor,
ShardSpawnLocation,
true,
DirectionOverride,
true,
DirectionOverride,
true,
45.f);
// 데미지 적용
UAuraAbilitySystemLibrary::ApplyDamageEffect(Params);
}
// 아케인 파편 기둥 이펙트 생성
FGameplayCueParameters CueParams;
CueParams.Location = ShardSpawnLocation;
CueParams.Normal = UKismetMathLibrary::GetRightVector(ShardSpawnRotation);
K2_ExecuteGameplayCueWithParams(FGameplayTag::RequestGameplayTag("GameplayCue.ArcaneShards"), CueParams);
}
if (Idx >= GroundPoints.Num())
EndSpawnShards();
else
Idx++;
}
파편 기둥을 하나씩 생성하면서 데미지를 입히고, 기둥 플레이 큐를 생성한다.
(4) 파편 소환 종료
void UArcaneShards::EndSpawnShards()
{
PointCollection->Destroy();
EndAbility(
GetCurrentAbilitySpecHandle(),
GetCurrentActorInfo(),
GetCurrentActivationInfo(),
true, false);
}
포인트 컬렉션을 파괴하고 어빌리티를 종료한다.
(5) EndAbility
void UArcaneShards::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled)
{
Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled);
auto* AvatarActor = GetAvatarActorFromActorInfo();
if (AvatarActor->Implements<UPlayerInterface>())
{
IPlayerInterface::Execute_HideMagicCircle(GetAvatarActorFromActorInfo());
}
// 데미지 입힘 종료
if (UWorld* World = GetWorld())
{
World->GetTimerManager().ClearTimer(ShardSpawnTimer);
}
// 포인트 컬렉션이 아직도 파괴되지 않았으면 파괴
if (IsValid(PointCollection))
PointCollection->Destroy();
}
범위 표시기가 사라지지 않았을 경우를 대비하여 범위 표시기를 제거한다. 포인트 컬렉션도 마찬가지이다.
3. 아케인 파편 어빌리티 - 블루프린트 이벤트 그래프

기존의 범위 지정 데칼과 자동 이동 중지 로직은 유지하고, 나머지 로직은 C++ 함수로 대체한다.
EndAbility 이벤트도 제거한다.
'UE 5 스터디 > Gameplay Ability System(GAS)' 카테고리의 다른 글
| 24-3. 엔진 업그레이드 - (2) MVVM - 로드 및 저장 UI 버그 수정 (0) | 2025.07.08 |
|---|---|
| 32-15. 로그 라이크 - (7) 데미지 계산(ExecCalc) - (1) 속성 추가 데미지 업그레이드 (0) | 2025.07.02 |
| 24-1. 엔진 업그레이드 - 컴파일 오류 해결 (0) | 2025.06.30 |
| 24. 언리얼 엔진 업그레이드 (UE 5.2 -> UE 5.6) (0) | 2025.06.30 |
| 32-14. 로그 라이크 - (3) 게임플레이 어빌리티 - (5) 화염 폭풍 스펠 (0) | 2025.06.27 |
