728x90
반응형
- 정리
- 트레이스 채널을 활용한 공격 판정
- 공격 판정 구현을 위한 물리 트레이스 채널 및 프로필 설정
- 디버그 드로잉 기능을 활용한 충돌 디버깅
- 데미지 프레임웍을 사용한 데미지 전달
- 델리게이트와 람다함수의 간편한 활용
- 트레이스 채널을 활용한 공격 판정
- 캐릭터 액션의 충돌 판정
- 월드가 제공하는 충돌 판정 서비스 사용
- 월드는 크게 세 가지의 충돌 판정 서비스를 제공
- 월드 내 배치된 충돌체와 충돌하는지 파악하고, 충돌한 액터 정보를 얻을 수 있음
- LineTrace
- Sweep
- Overlap
- 트레이스 채널과 충돌 프로필 생성
- 액션 판정을 위한 트레이스 채널의 생성 : ABAction. 기본 반응은 무시
- 캐릭터 캡슐용 프로필 : ABAction 트레이스 채널에 반응. 오브젝트 타입은 Pawn
- 스켈레탈 메시용 프로필 : 랙돌 구현에 주로 활용
- 기믹 트리거용 프로필 : 폰 캡슐에만 반응하도록 설정. 오브젝트 타입은 WorldStatic
- 원하는 트레이스 채널과 프로필을 만들 수 있다.
- Collision Respo
- Ignore
- 통과할 수 있음
- Overlap
- 통과하지만 이벤트가 발생
- Block
- 통과하지 못함
- Ignore
- Trace Type 중에 Destructible이 있는데, 이는 파괴한 것에 대한 충돌 처리를 설정이다. 파괴한 조각들이 길을 막으면 불편하기 때문에 보통 Ignore로 설정하는 것이 좋다.
- 설정하고 나면 Config 폴더 하단의 DefaultEngine.ini에 저장이 된다.
- 아까 설정한 이름인 ABAction을 검색해 보면, 다음과 같이 나오게 된다. 이름을 ABAction이라고 설정했지만, 코드내에서는 ECC_GameTraceChannel1 이라고 하는 열거형 값을 사용하고 있으므로, 해당 값을 바로 사용해 주는 것이 조금 더 편리하다.
- AnimNotify로 사용할 C++ 클래스를 만들어주고, 애니메이션 몽타주에서 히트 체크를 할 프레임에 방금 만든 Notify를 Add Notify 해준다.
#include "Animation/AnimNotify_AttackHitCheck.h"
#include "Character/ABCharacterBase.h" // 다른 폴더의 헤더파일을 추가하는 것은 결국 의존성이 생긴다는 것
void UAnimNotify_AttackHitCheck::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
// 메쉬 컴포넌트가 있다면
if (MeshComp)
{
MeshComp->GetOwner();
}
}
- AnimNotify_AttackHitCheck.cpp
- 다른 폴더의 헤더를 추가하는 것은 결국 의존성이 생기기 마련이다. 이 노티파이 기능의 경우 공용으로 여러 종류의 캐릭터가 있을 때 같이 사용되는 것이 좋은데, 이때마다 이렇게 헤더를 추가하는 것은 별로 좋지 않다.
- 좀 더 범용성 있게 만들려면 인터페이스를 구현해 주는 것이 좋다.
- 어쩔 수 없는 의존성이 발생되는 경우에는 가급적이면 인터페이스를 통해서 구현하도록 설계하면 보다 범용적으로 이러한 노티파이 기능들을 사용할 수가 있다.
- 월드 트레이싱 함수의 선택
- 세 가지 카테고리로 원하는 함수 이름을 얻을 수 있음
- 카테고리 1 : 처리방법
- LineTrace
- Sweep
- Overlap
- 카테고리 2 : 대상
- Test : 무언가 감지되었는지를 테스트
- Single 또는 AnyTest : 감지된 단일 물체 정보를 반환 (LineTrace, Sweep은 Single / Overlpa은 AnyTest)
- Multi : 감지된 모든 물체 정보를 배열로 반환
- 카테고리 3 : 처리 설정
- ByChannel : 채널 정보를 사용해 감지
- ByObjectType : 물체에 지정된 물리 타입 정보를 사용해 감지
- ByProfile : 프로필 정보를 사용해 감지
- {처리방법}{대상}{처리설정} 을 통해 월드 트레이싱 함수를 구성할 수 있다.
- 캐릭터 공격 판정의 구현 기획
- 캐릭터의 위치에서 시선 방향으로 물체를 감지
- 작은 구체를 제작, 시선 방향으로 특정 거리까지만 투사 (Sweep)
- 하나의 물체만 감지 (Single)
- 트레이스 채널을 사용해 감지 (ByChannel)
{처리방법}{대상}{처리설정} → {Sweep}{Single}{ByChannel}
#pragma once
#include "CoreMinimal.h"
#define CROFILE_ABCAPSULE TEXT("ABCapsule")
#define CROFILE_ABTRIGGER TEXT("ABTrigger")
#define CCHANNEL_ABACTION ECC_GameTraceChannel1
- ABCollision.h
- 전처리기용 파일 생성하기
- 탐색기에서 전처리기용 폴더를 만들고, 텍스트 파일로 간단히 생성하기. 이후 코드 제너레이트
- ini 파일에서 지정된 채널 열거형값으로 바로 변환되는데, 전처리기를 통해 좀 더 편리하게 코딩할 수 있다.
- 물리 충돌 테스트
- 디버그 드로잉 함수를 사용해 물리 충돌을 시각적으로 테스트하기
- 90도로 회전시킨 캡슐 그리기
- Origin
- HlafHieght
- Radius
UINTERFACE(MinimalAPI)
class UABAnimationAttackInterface : public UInterface
{
GENERATED_BODY()
};
class ARENABATTLE_API IABAnimationAttackInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual void AttackHitCheck() = 0; // 추상가상함수를 만들어 준다. 구현부에서 무조건 구현하도록
};
- ABAnimationAttackInterface.h
#include "Interface/ABAnimationAttackInterface.h" // 인터페이스 인클루드
/...
UCLASS()
class ARENABATTLE_API AABCharacterBase : public ACharacter, public IABAnimationAttackInterface // 인터페이스 상속
{
// Attack Hit Section
protected:
virtual void AttackHitCheck() override;
}
- ABCharacterBase.h
// 트레이스 채널을 체크해 물체가 서로 충돌되는 지를 검사하는 로직
void AABCharacterBase::AttackHitCheck()
{
FHitResult OutHitResult;
// 1. 콜리전을 분석할때 어떤 태그 정보로 분석할 때 식별자 정보로 사용이 되는 인자.
// 2. 복잡한 형태의 콜리전을 대상으로 감지할 것인가
// 3. 무시할 인자들
FCollisionQueryParams Params(SCENE_QUERY_STAT(Attack), false, this);
const float AttackRange = 40.0f;
const float AttackRadius = 50.0f;
const float AttackDamage = 30.0f;
const FVector Start = GetActorLocation() + GetActorForwardVector() * GetCapsuleComponent()->GetScaledCapsuleRadius();
const FVector End = Start + GetActorForwardVector() * AttackRange;
// SweepSingleByChannel과 같은 함수는 월드가 제공하는 서비스이기 때문에 GetWorld를 통해 포인터를 가져와준다.
bool HitDetected = GetWorld()->SweepSingleByChannel(OutHitResult, Start, End, FQuat::Identity, CCHANNEL_ABACTION, FCollisionShape::MakeSphere(AttackRadius), Params);
if (HitDetected)
{
}
// 디버그 드로우
#if ENABLE_DRAW_DEBUG
FVector CapsuleOrigin = Start + (End - Start) * 0.5f;
float CapsuleHalfHeight = AttackRange * 0.5f;
// 충돌했으면 Green / 충돌하지않았으면 Red
FColor DrawColor = HitDetected ? FColor::Green : FColor::Red;
// FRotationMatrix ~ : 시선 방향으로 눕히기
DrawDebugCapsule(GetWorld(), CapsuleOrigin, CapsuleHalfHeight, AttackRadius, FRotationMatrix::MakeFromZ(GetActorForwardVector()).ToQuat(), DrawColor, false, 5.0f);
#endif
- ABCharacterBase.cpp
- NPC 설정
- 기존에 만들어 둔 ABCharacterBase를 상속받아 C++Class를생성해준다.
- 또한, ABCharacterBase를 조금 수정해줘야 하는데 기본 에셋들에 대한 기본값들을 설정해준다.
// 기본 에셋에 대한 기본값들 설정하기
static ConstructorHelpers::FObjectFinder<UAnimMontage> ComboActionMontageRef(TEXT("/Script/Engine.AnimMontage'/Game/ArenaBattle/Animation/AM_ComboAttack.AM_ComboAttack'"));
if (ComboActionMontageRef.Object)
{
ComboActionMontage = ComboActionMontageRef.Object;
}
static ConstructorHelpers::FObjectFinder<UABComboActionData> ComboActionDataRef(TEXT("/Script/ArenaBattle.ABComboActionData'/Game/ArenaBattle/CharacterAction/ABA_ComboAttack.ABA_ComboAttack'"));
if (ComboActionDataRef.Object)
{
ComboActionData = ComboActionDataRef.Object;
}
- ABCharacterBase.cpp
- NPC가 공격을 받으면 죽는 모션 설정하기
- NPC의 죽는 모션을 설정하기 위해 죽는 모션에 대한 애니메이션 몽타주를 같은 방법으로 만들어 준다.
- 다만, 죽는 모션은 바로 실행되어야 하기 때문에 Enable Auto Blend Out에 대한 설정을 Off로 설정해준다.
- 애니메이션 블루프린트를 열어서 DeadSlot을 설정하고 DefaultSlot 다음에 Output으로 나가도록 설정해준다. 그렇게 되면 DeadSlot이 좀 더 우선순위를 가지게 된다.
// ...
// 죽는 상태를 설정하는 함수
virtual void SetDead();
// 죽는 애니메이션 몽타주를 재생하는 함수
void PlayDeadAnimation();
float DeadEventDelayTime = 5.0f;
- ABCharacterBase.h
// 트레이스 채널을 체크해 물체가 서로 충돌되는 지를 검사하는 로직
void AABCharacterBase::AttackHitCheck()
{
}
// 데미지를 주는 로직을 가진 함수
float AABCharacterBase::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
// EventInstigator - 나에게 피해를 입힌 가해자
// DamageCauser - 피해를 입힌 가해자가 사용한 무기라던지 아니면 가해자가 빙의한 폰, 액터 정보들
// 만약 피해를 받는 나에게 방어력이 설정되어 있다면, 여기서 들어온 데미지를 경감시켜서 최종값으로 리턴하면 된다.
Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
SetDead();
return DamageAmount;
}
// 죽은 상태를 설정하는 함수
void AABCharacterBase::SetDead()
{
// 죽었으니 움직임 제한시켜주면서 죽는 애니메이션 재생 + 콜리전 기능 제한
GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_None);
PlayDeadAnimation();
SetActorEnableCollision(false);
}
// 죽는 애니메이션 몽타주를 재생하는 함수
void AABCharacterBase::PlayDeadAnimation()
{
// AnimInstance 가져오기 + 모든 애니메이션 몽타주 중지 시키고 죽는 애니메이션 재생하기
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
AnimInstance->StopAllMontages(0.0f);;
AnimInstance->Montage_Play(DeadMontage, 1.0f);
}
- ABCharacterBase.cpp
UCLASS()
class ARENABATTLE_API AABCharacterNonPlayer : public AABCharacterBase
{
GENERATED_BODY()
public:
AABCharacterNonPlayer();
protected:
void SetDead() override;
};
- AABCharacterNonPlayer.h
#include "Character/ABCharacterNonPlayer.h"
AABCharacterNonPlayer::AABCharacterNonPlayer()
{
}
void AABCharacterNonPlayer::SetDead()
{
Super::SetDead();
FTimerHandle DeadTimerHandle;
GetWorld()->GetTimerManager().SetTimer(DeadTimerHandle, FTimerDelegate::CreateLambda(
[&]()
{
Destroy();
}
), DeadEventDelayTime, false);
}
- AABCharacterNonPlayer.cpp
- 데미지를 주는 함수와 죽은 상태를 설정하는 함수, 죽는 애니메이션 몽타주를 재생하는 함수를 만들어 주고, NonPlayer는 SetDead()함수가 동작하면, 피격 후 약 5초뒤에 사라질 수 있도록 동작하는 로직을 타이머를 통해 구현해주고, 람다를 통해 Destroy()시켜준다.
해당 포스트는 인프런의 <이득우의 언리얼 프로그래밍 Part2 -언리얼 게임 프레임웍의 이해>
강의를 수강하고 정리한 내용입니다.
이득우의 언리얼 프로그래밍 Part2 - 언리얼 게임 프레임웍의 이해 | 이득우 - 인프런
청강문화산업대학교에서 언리얼 엔진, 게임 수학, UEFN 게임제작을 가르치고 있습니다. - 이득우의 언리얼 C++ 프로그래밍, 넥슨 코리아 공식 교육 교재 선정 2023 - 스마일게이트 언리얼 프로그래
www.inflearn.com
728x90
'공부 > 이득우의 언리얼 프로그래밍' 카테고리의 다른 글
[Study] Part 2 - 아이템 시스템 (8/15) (0) | 2024.06.13 |
---|---|
[Study] Part 2 - 캐릭터 스탯과 위젯 (7/15) (0) | 2024.06.04 |
[Study] Part 2 - 캐릭터 콤보 액션 (5/15) (2) | 2024.06.02 |
[Study] Part 2 - 캐릭터 애니메이션 설정 (4/15) (2) | 2024.06.01 |
[Study] Part 2 - 캐릭터 컨트롤 설정 (3/15) (0) | 2024.05.28 |