공부용 이모저모
UE4 - 충돌 설정과 데미지 전달 본문
이득우 C++ 9장 내용
콜리전 설정(충돌설정)
종류
1.스태틱 메쉬 에셋 : 스태틱 매쉬(가만있는 메쉬)에 충돌설정을 심는 방법.비주얼 적인 표현이 가능하다
2.도형 컴포넌트 : 구체,박스,캡슐(캐릭터) 등의 도형에 충돌을 설정한다. 주로 스켈레탈 메쉬(다이나믹 메쉬)에 쓰인다.
3.피직스 에셋 : 캐릭터의 각 관절 등에 충돌영역을 심어 물리를 설정.스켈레탈 메쉬에서만 쓰인다.
콜리전 채널 - 콜리전 할 대상을 정할 수 있다.
채널 종류
WorldStatic - 정적 배경액터에 쓰이는 콜리전 채널. 주로 스태틱 매시 컴포넌트 사용
WorldDynamic - 움직이는 액터용 콜리전 채널, 블루 프린터에 속한 스태틱 매시 컴포넌트에 주로 사용.
Pawn - 플레이어의 조작 객체.캡슐 컴포넌트가 기본으로 되어있다.
Visibility - 물체가 보이는지 탐지할때 쓰인다.(폰은 제외) 마우스로 선택하는 Picking에 쓰인다.
Camera - 카메라와 목표물간 장애물이 있는지 검사한다. 벽이 캐릭터를 가릴때 카메라를 유동적으로 움직이는등에 쓰임
PhysicsBody - 물리 시뮬레이션으로 움직이는 컴포넌트에 쓰인다.
Collision Enabled는 3가지 옵션이 있다.
Query: 두 물체의 충돌영역이 겹치는지 테스트.겹치는것을 Overlap이라 부르며 BeginOverlap 이벤트가 발생한다. RayCast(마우스 충돌등에 쓰임)도 Query 옵션에 해당된다.
Physics:물리적인 시뮬레이션을 사용할때 설정한다.
Query and Physics : 두 기능을 동시에 사용하나, 부담이 간다.
Generate Overlap Events - 충돌이 감지되었을때 BeginOverlap || hitEvent을 실행시킬 것인가?
무시: 충돌이 발생하지 않음.
겹침: 서로 뚫고 들어가나, BeginOverlap을 발동 시킬 수 있음
블록: 서로 충돌하지 못하게 막는다.단 HitEvent는 일어난다(BeginOverlap과 별도)
Visibility,Camera만 트레이스 체널이고 나머지는 오브젝트 채널에 속한다.
기본을 블록으로 설정했기 때문에 베이스는 전부 블록으로 되어있다.
트리거는 언리얼에서 영역안에 들어왔을때를 감지해주는 용도로 사용하기 때문에
일반적으론 겹침 체크 해두는것이 좋다고 한다. 트리거와 같이 용도에 맞게 몇몇 옵션을 수정해야한다.
OverlapAll : 겹침
OverlapAllDynamic : 겹침
IgnoreOnlyPawn : 무시(폰만 제외)
OverlapOnlyPawn : 겹침(폰 류에만 겹침 설정)
Spectator : 무시(외부 관중과의 충돌여부)
CharacterMesh : 무시(캐릭터 매시에 쓰이는 물리)
RagDoll : 무시(스켈레탈 메시의 피직스 에셋 물리를 가동하기 위한 물리 설정)
UI : 겹침(UI에 사용하는 요소)
#include "ABCharacter.h"
#include "ABAnimInstance.h"
#include "ABGhostTrail.h"
// Sets default values
AABCharacter::AABCharacter()
{
...
//ABCharacter로 콜리전 변경
GetCapsuleComponent()->SetCollisionProfileName(TEXT("ABCharacter"));
}
트레이스 채널의 활용
지난번 애니메이션에 이어 캡슐 컴포넌트를 이용한 충돌로 연속공격에 판정을 넣기로 한다
SweepSingleByChannel 함수 : 트레이스 채널을 사용해 물리적 충돌 여부를 가림. GetWorld에 내장된 함수.
이하 해당 함수의 파라메터
HitResult : 물리적 충돌이 탐지 된 경우 관련된 정보를 담을 구조체
Start : 탐색을 시작할 위치
End : 탐색을 끝낼 위치
Rot : 탐색에 사용할 도형의 회전
TraceChannel : 물리충돌 감지에 사용할 채널 정보
CollisionShape : 탐색에 사용할 기본 도형 정보.구체,캡슐,박스 사용
Params : 탐색 방법에 대한 설정값을 모아둔 구조체
ResponseParams : 탐색 반응을 설정하기 위한 구조체
언리얼 엔진은 게임에서 사용 할 수 있도록 32개의 콜리전 채널을 제공한다.
여기서 기본 언리얼 사용 콜리전이 8개, 엔진에서 별도로 사용하는게 6개이고,
유저가 사용 할 수 있는 콜리전 채널은 18개이다.
엔진 코드의 EngineTpyes.h에 해당 선언된 18개의 채널을 확인 할 수 있다.
UENUM(BlueprintType)
enum ECollisionChannel
{
...
ECC_GameTraceChannel1 UMETA(Hidden),
ECC_GameTraceChannel2 UMETA(Hidden),
ECC_GameTraceChannel3 UMETA(Hidden),
ECC_GameTraceChannel4 UMETA(Hidden),
ECC_GameTraceChannel5 UMETA(Hidden),
ECC_GameTraceChannel6 UMETA(Hidden),
ECC_GameTraceChannel7 UMETA(Hidden),
ECC_GameTraceChannel8 UMETA(Hidden),
ECC_GameTraceChannel9 UMETA(Hidden),
ECC_GameTraceChannel10 UMETA(Hidden),
ECC_GameTraceChannel11 UMETA(Hidden),
ECC_GameTraceChannel12 UMETA(Hidden),
ECC_GameTraceChannel13 UMETA(Hidden),
ECC_GameTraceChannel14 UMETA(Hidden),
ECC_GameTraceChannel15 UMETA(Hidden),
ECC_GameTraceChannel16 UMETA(Hidden),
ECC_GameTraceChannel17 UMETA(Hidden),
ECC_GameTraceChannel18 UMETA(Hidden),
...
}
저 채널은 프로젝트 세팅에서 새 트레이스 채널을 만들때마다 배정된다.
이는 DefaultEngine.ini 에서 확인 할 수 있다.
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Block,bTraceType=False,bStaticObject=False,Name="ABCharacter")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Attack")
FCollisionShape::MakeSphere - 타원 콜리젼 만드는 함수
이걸 사용해서 판정을 추가하기로 한다
ABCharacter.h 수정
private:
....
void AttackCheck();
ABCharacter.cpp 수정
void AABCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
...
//AttackHitCheck 노티파이를 받으면 AttackCheck 실행
ABAnim->OnAttackHitCheck.AddUObject(this, &AABCharacter::AttackCheck);
}
void AABCharacter::AttackCheck()
{
FHitResult HitResult;
FCollisionQueryParams Params(NAME_None, false, this);
//결과를 채널로 반환
bool bResult = GetWorld()->SweepSingleByChannel(
HitResult,
GetActorLocation(),
GetActorLocation() + GetActorForwardVector() * 200.0f,
FQuat::Identity,
ECollisionChannel::ECC_GameTraceChannel2,
FCollisionShape::MakeSphere(50.0f),
Params);
if (bResult)
{
if (HitResult.Actor.IsValid())
{
//존재한다면 로그 남기기
UE_LOG(LogTemp, Warning, TEXT("Hit Actor Name : %s"), *HitResult.Actor->GetName());
}
}
}
디버그 드로잉
언리얼 엔진에서 제공하는 기능으로 디버그중 시각적으로 범위를 표기해준다.
DebugDrawHelpers.h 헤더에 들어있다.
ABCharacter.h 수정
class ARENABATTLE_API AABCharacter : public ACharacter
{
...
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Attack, Meta = (AllowPrivateAccess = true))
float AttackRange;
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Attack, Meta = (AllowPrivateAccess = true))
float AttackRadius;
};
ABCharacter.cpp 수정
#include "DrawDebugHelpers.h"
AABCharacter::AABCharacter()
{
...
AttackRange = 200.0f;
AttackRadius = 50.0f;
}
void AABCharacter::AttackCheck()
{
...
bool bResult = GetWorld()->SweepSingleByChannel(
HitResult,
GetActorLocation(),
GetActorLocation() + GetActorForwardVector() * 200.0f,
FQuat::Identity,
ECollisionChannel::ECC_GameTraceChannel2,
FCollisionShape::MakeSphere(50.0f),
Params);
//이번에 추가
#if ENABLE_DRAW_DEBUG
FVector TraceVec = GetActorForwardVector() * AttackRange;
FVector Center = GetActorLocation() + TraceVec * 0.5f;
//반지름
float HalfHeight = AttackRange * 0.5f + AttackRadius;
//캡슐 회전방향
FQuat CapsuleRot = FRotationMatrix::MakeFromZ(TraceVec).ToQuat();
//타겟 발견시 녹색,미발견시 빨강
FColor DrawColor = bResult ? FColor::Green : FColor::Red;
//생성후 삭제되기까지의 시간
float DebugLifeTime = 5.0f;
//캡슐 디버그 메쉬그리기
DrawDebugCapsule(GetWorld(), Center, HalfHeight, AttackRadius, CapsuleRot, DrawColor, false, DebugLifeTime);
#endif
...
}
데미지 프레임워크
언리얼 엔진 제공기능으로, 데미지를 해당 액터로 전달해주는 기능이다.
액터 내부에 TakeDamage라는 함수가 구현되어 있으며, 4가지 인자로 구성된다.
DamageAmount : 전달할 데미지의 세기
DamageEvent : 데미지 종류
EventInstigator : 공격 명령을 내린 가해자
DamageCauser : 데미지 전달을 위해 쓰인 도구
여기서 가해자란, Pawn을 의미하는게 아닌 Pawn을 조종하는 컨트롤러를 가리킨다.(즉 다른 플레이어)
언리얼엔진이 FPS PVP기반 게임이기 때문에 이러한 방식으로 보내주는것으로 보인다.
ABCharacter.h 변경
UCLASS()
class ARENABATTLE_API AABCharacter : public ACharacter
{
...
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual void PostInitializeComponents() override;
virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;
...
TakeDamage 함수 override
ABCharacter.cpp 변경
void AABCharacter::AttackCheck()
{
...
if (bResult)
{
if (HitResult.Actor.IsValid())
{
//UE_LOG(LogTemp, Warning, TEXT("Hit Actor Name : %s"), *HitResult.Actor->GetName());
//로그 대신 데미지
FDamageEvent DamageEvent;
//찾은 대상에게 50의 데미지 입히기
HitResult.Actor->TakeDamage(50.0f, DamageEvent, GetController(), this);
}
}
}
float AABCharacter::TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser)
{
float FinalDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
UE_LOG(LogTemp, Warning, TEXT("Actor Name : %s Damage : %f"), *GetName() , FinalDamage);
return FinalDamage;
}
기존 액터에 TakeDamage 기능이 있고, AABCharacter은 이를 상속하여 추가 기능을 실행시키는 원리이다.
죽음 옵션 추가
ABAnimInstance.h 수정
public:
//함수란
void SetDeadAnim() { IsDead = true; }
private:
//변수란
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Pawn, Meta = (AllowPrivateAccess = true))
bool IsDead;
ABAnimInstance.Cpp
UABAnimInstance::UABAnimInstance()
{
IsDead = false;
}
//애니메이션 초당 확인
void UABAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
//폰의 포인터를 얻어온다
auto Pawn = TryGetPawnOwner();
if (!::IsValid(Pawn))
return;
//IsDead가 아닐때만 값 변경
if (!IsDead)
{
//폰의 속도 데이터를 입력한다(GetVelocity가 속도 데이터이고 Size가 그 수치이다)
CurrentPawnSpeed = Pawn->GetVelocity().Size();
//폰을 캐릭터로 캐스팅
auto Character = Cast<ACharacter>(Pawn);
if (Character)
{
//캐릭터의 떨어짐 여부를 저장한다.
IsInAir = Character->GetMovementComponent()->IsFalling();
}
}
}
컴파일 후 애님그래프로 가면 IsDead가 추가되어있다.
ABCharacter.cpp 추가
float AABCharacter::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float FinalDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
UE_LOG(LogTemp, Warning, TEXT("Actor Name : %s Damage : %f"), *GetName() , FinalDamage);
if (FinalDamage > 0.0f)
{
//IsDead = true;
ABAnim->SetDeadAnim();
//죽었으니 충돌판정 제거
SetActorEnableCollision(false);
}
return FinalDamage;
}
아직 체력바 개념은 없으니, 데미지가 들어오면 죽게 처리했다.
'UE4 - C++' 카테고리의 다른 글
UE4 - 게임데이터와 UI 위젯 (0) | 2021.11.04 |
---|---|
UE4 - 아이템 상자와 무기 제작 (0) | 2021.10.28 |
UE4 - 잔상 효과 만들기(SPAWN/TIME LINE/POSEABLEMESH) (0) | 2021.09.24 |
UE4 - 애니메이션 몽타주 (0) | 2021.09.09 |
UE4 - 점프기능 구현 (0) | 2021.08.31 |