0. 개요
어떤 구체의 반경 내에 생존한 플레이어 캐릭터가 있는지 찾는 함수를 만든다.
해당 함수를 활용하여 근거리 몬스터의 데미지 판정에 이용한다.
1. CombatInterface 전투 인터페이스
(1) 새로운 함수 선언
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
bool IsDead() const;
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable)
AActor* GetAvatar();
액터의 죽음을 판단하는 IsDead 함수와 아바타 액터를 쉽게 가져오기 위한 GetAvatar 함수를 Native 이벤트로 지정한다.
(2) AuraCharacterBase에서 함수 오버라이드
public:
AAuraCharacterBase();
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const { return AbilitySystemComponent; }
UAttributeSet* GetAttributeSet() const { return AttributeSet; }
/** 전투 인터페이스 **/
virtual UAnimMontage* GetHitReactMontage_Implementation() override;
virtual void Die() override;
virtual FVector GetCombatSocketLocation_Implementation() override;
virtual bool IsDead_Implementation() const override;
virtual AActor* GetAvatar_Implementation() override;
/**여기까지 전투 인터페이스**/
protected:
bool bDead = false;
블루프린트 Native 이벤트 함수들을 오버라이드한다.
죽음을 나타내는 불리언을 선언한다.
bool AAuraCharacterBase::IsDead_Implementation() const
{
return bDead;
}
AActor* AAuraCharacterBase::GetAvatar_Implementation()
{
return this;
}
void AAuraCharacterBase::MulticastHandleDeath_Implementation()
{
// 무기 랙돌
Weapon->SetSimulatePhysics(true);
Weapon->SetEnableGravity(true);
Weapon->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly);
// 캐릭터 랙돌
GetMesh()->SetSimulatePhysics(true);
GetMesh()->SetEnableGravity(true);
GetMesh()->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly);
GetMesh()->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Block); // worldstatic에 대해 부딫힘
// 캐릭터 충돌 비활성화
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
Dissolve();
bDead = true;
}
액터가 사망하면 MulticastHandleDeath 함수가 호출된다.
최하단에 bDead = true를 넣는다.
2. AuraAbilitySystemLibrary - 커스텀 블루프린트 라이브러리
(1) 엔진 함수 살펴보기
UGameplayStatics에 구형 데미지를 입히는 함수인 ApplyRadialDamageWithFalloff 함수를 살펴본다.
bool UGameplayStatics::ApplyRadialDamageWithFalloff(const UObject* WorldContextObject, float BaseDamage, float MinimumDamage, const FVector& Origin, float DamageInnerRadius, float DamageOuterRadius, float DamageFalloff, TSubclassOf<class UDamageType> DamageTypeClass, const TArray<AActor*>& IgnoreActors, AActor* DamageCauser, AController* InstigatedByController, ECollisionChannel DamagePreventionChannel)
{
FCollisionQueryParams SphereParams(SCENE_QUERY_STAT(ApplyRadialDamage), false, DamageCauser);
SphereParams.AddIgnoredActors(IgnoreActors);
// query scene to see what we hit
TArray<FOverlapResult> Overlaps;
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
World->OverlapMultiByObjectType(Overlaps, Origin, FQuat::Identity, FCollisionObjectQueryParams(FCollisionObjectQueryParams::InitType::AllDynamicObjects), FCollisionShape::MakeSphere(DamageOuterRadius), SphereParams);
}
- 충돌 쿼리 파라미터를 생성해 구형 데미지를 입히는 파라미터를 만든다.
- 파라미터에 충돌 연산에서 제외할 액터를 추가한다.
- 월드에 대해서 다수의 액터에 대해 충돌을 계산하는 OverlapMultiByObjectType 함수를 호출한다.
- 해당 함수에 구형 쿼리 파라미터를 전달한다.
(2) 커스텀 블루프린트 라이브러리에서 구형 충돌 쿼리 이용하기
UFUNCTION(BlueprintCallable, category = "AuraAbilitySystemLibrary|GameplayMechanics")
static void GetLivePlayersWithinRadius(const UObject* WorldContextObject, TArray<AActor*>& OutOverlappingActors, const TArray<AActor*>& ActorsToIgnore, float Radius, const FVector& SphereOrigin);
- 참조에 const를 붙여야 입력핀으로 나타난다.
void UAuraAbilitySystemLibrary::GetLivePlayersWithinRadius(const UObject* WorldContextObject,
TArray<AActor*>& OutOverlappingActors, TArray<AActor*>& ActorsToIgnore, float Radius,
const FVector& SphereOrigin)
{
// 구형 충돌 쿼리
FCollisionQueryParams SphereParams;
SphereParams.AddIgnoredActors(ActorsToIgnore);
// 겹침 판단
TArray<FOverlapResult> Overlaps;
if (const UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
// SphereParams에 따른 구형 콜리전 테스트 후 Overlaps 구조체로 내보냄
World->OverlapMultiByObjectType(Overlaps, SphereOrigin, FQuat::Identity, FCollisionObjectQueryParams(FCollisionObjectQueryParams::InitType::AllDynamicObjects), FCollisionShape::MakeSphere(Radius), SphereParams);
for (auto& Overlap : Overlaps)
{
// 겹친 액터가 전투 인터페이스를 구현했는지 확인
const bool ImplementsCombatInterface = Overlap.GetActor()->Implements<UCombatInterface>();
const bool IsAlive = !ICombatInterface::Execute_IsDead(Overlap.GetActor());
if (ImplementsCombatInterface && IsAlive)
{
OutOverlappingActors.AddUnique(ICombatInterface::Execute_GetAvatar(Overlap.GetActor()));
}
}
}
}
구형 쿼리를 만들어 월드를 가져오고 겹침 테스트를 한다.
Overlaps 구조체를 순회하여 전투 인터페이스가 구현되어 있으며 살아있다면 Actor 포인터로 구성된 Out Actor 벡터에 추가하여 래핑한다.
(3) 크래시 디버그
World->OverlapMultiByObjectType(Overlaps, SphereOrigin, FQuat::Identity, FCollisionObjectQueryParams(FCollisionObjectQueryParams::InitType::AllDynamicObjects), FCollisionShape::MakeSphere(Radius), SphereParams);
for (auto& Overlap : Overlaps)
{
// 겹친 액터가 전투 인터페이스를 구현했는지 확인
const bool ImplementsCombatInterface = Overlap.GetActor()->Implements<UCombatInterface>();
const bool IsAlive = !ICombatInterface::Execute_IsDead(Overlap.GetActor());
if (ImplementsCombatInterface && IsAlive)
{
OutOverlappingActors.AddUnique(ICombatInterface::Execute_GetAvatar(Overlap.GetActor()));
}
}
전투 인터페이스를 구현했는지 확인한 이후 IsAlive를 구하는 과정에서 크래시가 발생했을 수 있다.
이는 전투 인터페이스가 구현되지 않은 대상에게서 IsAlive를 구하기 위해 ICombatInterface를 호출하려 했기 때문이다.
위의 코드 조각을 아래처럼 바꾼다.
World->OverlapMultiByObjectType(Overlaps, SphereOrigin, FQuat::Identity, FCollisionObjectQueryParams(FCollisionObjectQueryParams::InitType::AllDynamicObjects), FCollisionShape::MakeSphere(Radius), SphereParams);
for (auto& Overlap : Overlaps)
{
// 겹친 액터가 전투 인터페이스를 구현했는지 확인
if (Overlap.GetActor()->Implements<UCombatInterface>() && !ICombatInterface::Execute_IsDead(Overlap.GetActor()))
{
OutOverlappingActors.AddUnique(ICombatInterface::Execute_GetAvatar(Overlap.GetActor()));
}
}
첫번째 if 체크가 실패하면 두번째 if 체크는 실시하지 않게 된다.
'UE 5 스터디 > Gameplay Ability System(GAS)' 카테고리의 다른 글
14-6. AI 근거리 공격 - (6) 무기 소켓이 없는 몬스터의 근접 공격 (0) | 2024.12.30 |
---|---|
14-5. AI 근거리 공격 - (5) 근접 공격 데미지 (0) | 2024.12.30 |
14-3. AI 근거리 공격 - (3) 공격 몽타주와 게임플레이 이벤트 (1) | 2024.12.30 |
14-2. AI 근거리 공격 - (2) 공격 몽타주, 모션 워핑 (0) | 2024.12.30 |
14-1. AI 근거리 공격 - (1) 공격 게임플레이 어빌리티 생성 및 활성화 (0) | 2024.12.30 |