๐ก C++๋ก ์ ์ ๋ง๋ค์ด๋ณด์. ๋ํ ์ ํ์ํ๊ธฐ๊ณ๋ฅผ ํฌํจํ์ฌ ๋ง๋ค์ด ๋ณด๊ฒ ๋ค.
์ด๋ฒ์๋ ์ ์ด ๊ณต๊ฒฉํ ๋ ์๊ตฐ์ด ํผ๊ฒฉ๋๋๋ก ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
Edit - Project Settings - Engine - Collision์ผ๋ก ์ด๋ํด์ฃผ์ธ์.
๊ทธ๋ฆฌ๊ณ Trace Channels์์ EnemyMeleeAttack ์ฑ๋์ ์ถ๊ฐ ํด์ฃผ๊ฒ ์ต๋๋ค.
Attack ์ขํ๋ฅผ ์ํ ์ปดํฌ๋ํธ๋ฅผ ์ถ๊ฐํด์ค ์ ์์ผ๋,
๊ทธ๋ฅ GetMesh()์์ Z๋ฅผ ๋ํ๋ ๋ฐฉ์์ผ๋ก ์งํํ๊ฒ ์ต๋๋ค.
me->GetMesh()๋ก ์ ๋ฉ์๋ฅผ ๋ฐ์์ Start, End์์น๋ฅผ ๋ฐ์ต๋๋ค.
์ด๋ Mesh์ ์ขํ๊ณ๋ Forward๊ฐ ์๋ RightVector๋ฅผ ์ฌ์ฉํด์ฃผ์ธ์.
๊ทธ๋ฆฌ๊ณ ๋ณธ์ธ ๋ฌด์ Params๊น์ง ์ผ๋จ ์์ฑํ๊ฒ ์ต๋๋ค.
void UEnemyFSM::AttackState()
{
FVector Direction = target->GetActorLocation() - me->GetActorLocation();
if (Direction.Size() <= attackRange)
{
if (currentTime > attackDelayTime)
{
UAnimInstance* AnimInstance = me->GetMesh()->GetAnimInstance();
if (AnimInstance != nullptr)
{
// ์๋ต
FVector startPos = me->GetMesh()->GetComponentLocation() + FVector(0, 0, 100);
FVector endPos = startPos + (me->GetMesh()->GetRightVector() * 150);
FHitResult hitInfo;
FCollisionQueryParams params;
params.AddIgnoredActor(me);
}
}
}
}
์ ์ธ์๋ฅผ ์ฌ์ฉํด์ LineTrace๋ฅผ ์๊ฒ ์ต๋๋ค.
bHit์์ LineTraceSingeByChannel์ ์ด์ฃผ์ธ์.
์ด๋ ์ฑ๋์ ECollisionChannel::ECC_GameTraceChannel1 ๋ฃ์ด ์ฃผ์ธ์.
์ฐ๋ฆฌ๊ฐ ๋ฃ์ ์ฑ๋์ 1๋ฒ์ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ๋๋ค.
void UEnemyFSM::AttackState()
{
FVector Direction = target->GetActorLocation() - me->GetActorLocation();
if (Direction.Size() <= attackRange)
{
if (currentTime > attackDelayTime)
{
UAnimInstance* AnimInstance = me->GetMesh()->GetAnimInstance();
if (AnimInstance != nullptr)
{
// ์๋ต
bool bHit = GetWorld()->LineTraceSingleByChannel(hitInfo, startPos, endPos, ECollisionChannel::ECC_GameTraceChannel1, params);
}
}
}
}
์ด์ด์ LineTrace์ ๋ง์ ๋์์ด ์๋ค๋ฉด bHit์ ์ ๋ณด๊ฐ ๋ค์ด ๊ฐ ๊ฒ๋๋ค.
๊ทธ๋ฆฌ๊ณ Player๊ฐ ๊ฐ์ง๊ณ ์๋ ์ปดํฌ๋ํธ์ ์ ๋ํฌ ๋ค์์ ํ๋ ๊ฐ์ ธ์ค๊ฒ ์ต๋๋ค.
์ ๋ GunMeshComp๋ฅผ ์ฌ์ฉํ๊ฒ ์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ Player๋์ ๋์ผํ๊ฒ ApplyDamage๋ฅผ ์ฌ์ฉํด์ฃผ์ธ์.
void UEnemyFSM::AttackState()
{
FVector Direction = target->GetActorLocation() - me->GetActorLocation();
if (Direction.Size() <= attackRange)
{
if (currentTime > attackDelayTime)
{
UAnimInstance* AnimInstance = me->GetMesh()->GetAnimInstance();
if (AnimInstance != nullptr)
{
// ์๋ต
if (bHit)
{
auto enemy = hitInfo.GetActor()->GetDefaultSubobjectByName(TEXT("GunMeshComp"));
if (enemy)
{
UGameplayStatics::ApplyDamage(hitInfo.GetActor(), 1, NULL, NULL, NULL);
}
}
}
}
}
}
MyPlayer Class๋ก ์ด๋ํ๊ฒ ์ต๋๋ค.
ํ๋ ์ด์ด์๊ฒ๋ ์ฒด๋ ฅ์ ๋ฃ์ด ์ฃผ๊ฒ ์ต๋๋ค.
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = FSMComponent)
float Hp = 3;
MyPlayer.h๋ก ๊ฐ์ TakeDamage()๋ฅผ ์ ์ธํด์ฃผ์ธ์.
virtual float TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
ํ๋ ์ด์ด๋ ํผ๊ฒฉ์ AM_Hit๋ฅผ ์ฌ์ํ๋๋ก ํด์ฃผ๊ฒ ์ต๋๋ค.
UPROPERTY(EditAnywhere, Category = Montage)
UAnimMontage* AM_Hit;
์ฐ์ ํค๋๋ฅผ ํ๋ ์ถ๊ฐํด์ค์๋ค.
#include "Components/CapsuleComponent.h"
๊ทธ๋ฆฌ๊ณ Enemy๋์ ๊ฐ์ด ๋์ผํ๊ฒ ์ฝ๋๋ฅผ ์์ฑํด์ค๋๋ค.
์ํ์ ํ ๋์ ์ํํจ์์ ์ฝ๋๋ฅผ ์ง์ ๋ฃ์ผ๋ฉด ๋๊ฒ ์ฃ ?
float AMyPlayer::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float damage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
Hp -= damage;
if (Hp <= 0)
{
GetMesh()->SetSimulatePhysics(true);
GetMesh()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
else
{
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance != nullptr)
{
AnimInstance->Montage_Play(AM_Hit);
}
}
return damage;
}
โ์ปดํ์ผ ์ ์ฅโํ๊ณ ์ธ๋ฆฌ์ผ ์๋ํฐ๋ก ์ด๋ํด์ฃผ์ธ์.
BP_Player๋ฅผ ์ด์ด์ AM_Hit์ ๋ฃ์ด ์ฃผ์ธ์.
โ์ปดํ์ผ ์ ์ฅโํ๊ณ ์คํํด๋ณด๊ฒ ์ต๋๋ค.
๋งฅ ์์ด ์ฐ๋ฌ์ง๋ค์.
์ ๊ณต๊ฒฉ๊ณผ ํ๋ ์ด์ด์ ํผ๊ฒฉ ์ ๋๋ฉ์ด์ ์ด ์ฝ๊ฐ ํ์ด๋ฐ์ด ๋ง์ง ์์ต๋๋ค.
๋ณธ๋ Notify๋ฅผ ์ฌ์ฉํ์ฌ ์ ๋๋ฉ์ด์ ์ ํน์ ์์ ์ Line Trace๋ฅผ ์๊ณ ์ํธ์์ฉ์ด ๋๋๋ก ํด์ผ๊ฒ ์ฃ .
๋ํ ํ๋ ์ด์ด๊ฐ ์ฃฝ์์์๋ ๊ณ์ํด์ ์ ๋ค์ด target์ ๋ํ ์ํ ๋์์ด ๊ณ์๋ฉ๋๋ค.
๋ ๋ถ๋ถ์ ๋์ค์ ์๊ฐ์ด ๋๋ค๋ฉด ์ ๋ฐ์ดํธ ํด๋ณด๊ฒ ์ต๋๋ค.