[Unreal/C++] Collider On/Off 충돌체 켜고 끄기
언리얼 엔진에서 게임을 만들 때 공격 상태에서만 충돌체를 켜는 것이 효율적일때가 많다.
위 이미지 처럼 앞에 충돌체를 두면 공격상태가 아님에도 불구하고 실시간으로 충돌처리가 일어난다.
원하는 동작은 박치기를 했을 때 플레이어에게 데미지를 주는 것이다.
불필요한 말들을 제거하고 충돌체를 끄고 켜는 방법을 설명하자면 콜리전의 상태를 바꿔주는 것이다.
저 오브젝트 타입은 C++에서 ECollisionEnable에 enum 형식으로 정의되어 있다.
NoCollision = 충돌체를 사용하지 않는다.
QueryOnly = 이벤트 발생을 위해 사용한다.
PhysicsOnly = 물리적 충돌을 위해 사용한다.
QueryAndPhysics = 이벤트와 물리적 충돌 둘다 사용한다.
NoCollision UMETA(DisplayName="No Collision")
QueryOnly UMETA(DisplayName="Query Only (No Physics Collision)"),
PhysicsOnly UMETA(DisplayName="Physics Only (No Query Collision)"),
QueryAndPhysics UMETA(DisplayName="Collision Enabled (Query and Physics)")
이를 바꾸기 위해서 PrimitiveComponent를 상속받은 Sphere, Capsule, Box Component 등에서 SetCollisionEnable(ECollisionEnabled Type)을 사용할 수 있다.
물론 충돌체의 Visible을 껐다 켰다 함으로써 충돌을 방지할 수는 있지만 단순히 채널로 구분하는 충돌이기 때문에 추천하지 않는 방법이다.
collider->SetCollisionEnabled(ECollisionEnabled::NoCollision);
collider->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
collider->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly);
collider->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
어쨌든 충돌체를 설정했다면 델리게이트로 충돌 여부를 받아오면 된다.
void ACharger::InitDelegates()
{
SphereCollider->OnComponentBeginOverlap.AddDynamic(this, &ACharger::OnComponentBeginOverlap);
}
void ACharger::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor->ActorHasTag("Enemy")) return;
UGameplayStatics::ApplyDamage(OtherActor, 5, GetOwner()->GetInstigatorController(), this, UDamageType::StaticClass());
}
충돌에서 대상을 제외하고 싶다면 Tag를 이용한 방법을 추천한다.
지금까지는 다른 방법들에 비해 간단하고 효율적인 방법이다.
여기까지 이해가 되었다면 공격을 할 때 애니메이션 몽타주에서 충돌체를 껐다켰다 할 필요가 있을 것이다.
애니메이션 몽타주에서 충돌체를 껐다켰다 하기 위해 Animation Notify나 Notify State를 사용한다.
사실상 Tick을 사용하지 않기 때문에 Notify State보다는 단일 Notify가 효율성이 좋지만 내 귀찮음으로 Notify State 를 사용한다. 많은 스크립트는 나를 헷갈리게 하기 때문이다.
Animation Notify State를 만들어주고 필요한 NotifyBegin 함수와 NotifyEnd 함수를 오버라이딩 해준다.
위에 보이는 GetNotifyName_Implementation은 애니메이션 몽타주 에디터에 보이는 이름을 재정의 하는 것이다.
저 함수가 없다면 한 눈에 보이지 않는 클래스명이 가독성을 떨어뜨릴 것이다.
public :
FString GetNotifyName_Implementation() const override;
public :
virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference) override;
virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) override;
그렇게 만든 Animation Notify State를 정의 해준다.
위에서 말한 것처럼 GetNotifyName_Implementation은 에디터에 보이는 이름을 설정해준다.
#include "Enemy/Notifies/EnemyAttackCheck.h"
#include "Enemy/Charger/Charger.h"
FString UEnemyAttackCheck::GetNotifyName_Implementation() const
{
return "AttackCheck";
}
void UEnemyAttackCheck::NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration, const FAnimNotifyEventReference& EventReference)
{
if (MeshComp->GetWorld()->WorldType == EWorldType::Type::EditorPreview)
return;
Cast<ACharger>(MeshComp->GetOwner())->SetCollisionActive(true);
}
void UEnemyAttackCheck::NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
if (MeshComp->GetWorld()->WorldType == EWorldType::Type::EditorPreview)
return;
Cast<ACharger>(MeshComp->GetOwner())->SetCollisionActive(false);
}
또한 필수적으로 if(MeshComp->GetWorld()->WorldType == EWorldType::Type::EditorPreview) return 을 추가해주길 바란다.
이 것이 없다면 에디터상에서도 Notify가 실행되기 때문에 의도하지 않은 Fatal Error를 자주 볼 수 있을 것이다.
위 문장은 에디터 프리뷰로 상태에서는 Notify를 실행하지 않는다는 뜻이다.
이렇게 만들어진 notifyState는 아래와 같이 AttackCheck라는 이름으로 보이게 된다.
'Unreal > Manual' 카테고리의 다른 글
Unreal Mesh Socket 위치에서 SpawnActorDeferred 하기 (0) | 2024.01.12 |
---|---|
Unreal Particle Object 가져오기 (0) | 2024.01.11 |
Unreal Debug 용 원(Circle) 그리기 (0) | 2024.01.11 |
Unreal BeginPlay에서 Skeletal Mesh 바꾸기 (0) | 2024.01.09 |
Unreal 적의 체력이 화면을 정면으로 바라보도록 구현 (0) | 2024.01.09 |