[Unreal][C++] 1์ธ์นญ ์ŠˆํŒ… ํŠœํ† ๋ฆฌ์–ผ

2024. 1. 21. 15:38ยท๐Ÿ“ Game/โœ Unreal

1์ธ์นญ ์ŠˆํŒ… ํŠœํ† ๋ฆฌ์–ผ

https://docs.unrealengine.com/5.3/ko/first-person-shooter-tutorial-in-unreal-engine/

 

์ผ์ธ์นญ ์ŠˆํŒ… C++ ํŠœํ† ๋ฆฌ์–ผ

์ผ์ธ์นญ ์ŠˆํŒ… ๊ฒŒ์ž„ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›Œ๋ด…๋‹ˆ๋‹ค.

docs.unrealengine.com

 

1. ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑํ•˜๊ธฐ

1) ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

์ƒˆ ํ”„๋กœ์ ํŠธ ๋‚ด ๋งต์„ ์ƒ์„ฑํ•˜๊ณ , ๊ทธ ๋งต์„ ์—๋””ํ„ฐ ์‹œ์ž‘ ๋งต์œผ๋กœ ์ง€์ •ํ•œ๋‹ค.

 

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

  • ๊ฒŒ์ž„ ํ”„๋กœ์ ํŠธ ์นดํ…Œ๊ณ ๋ฆฌ ๋‚ด ๊ธฐ๋ณธ(Blank) ํ…œํ”Œ๋ฆฟ ์„ ํƒ
  • C++ ํ”„๋กœ์ ํŠธ ํƒ€์ž… ์„ ํƒ
  • ์‹œ์ž‘์šฉ ์ฝ˜ํ…์ธ  ๋น„ํ™œ์„ฑํ™”
  • ํ”„๋กœ์ ํŠธ ์ด๋ฆ„ FPSProject ์ง€์ •

 

์—๋””ํ„ฐ ์‹œ์ž‘ ๋งต ์„ค์ •

  • FPS ๋งต ์ƒ์„ฑ
  • ํ”„๋กœ์ ํŠธ ์„ธํŒ…์—์„œ ์—๋””ํ„ฐ ์‹œ์ž‘ ๋งต ์„ค์ •

 

2) ๊ฒŒ์ž„๋ชจ๋“œ C++ ํด๋ž˜์Šค๋ฅผ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค๋กœ ํ™•์žฅํ•˜๊ธฐ

๊ฒŒ์ž„๋ชจ๋“œ C++ ํด๋ž˜์Šค๋ฅผ ๋ฒ ์ด์Šค๋กœ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค๋ฅผ ๋””ํดํŠธ ๊ฒŒ์ž„๋ชจ๋“œ๋กœ ์„ค์ •ํ•œ๋‹ค. ์ด๋•Œ ๊ธฐ๋ณธ์œผ๋กœ ์ƒ์„ฑ๋œ ๊ฒŒ์ž„๋ชจ๋“œ C++ ํด๋ž˜์Šค๊ฐ€ ์—†๋‹ค๋ฉด C++ ํด๋ž˜์Šค ๋งˆ๋ฒ•์‚ฌ๋กœ ์ƒ์„ฑ์ด ํ•„์š”ํ•˜๋‹ค.

 

๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค ์ƒ์„ฑ

 

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๊ฒŒ์ž„๋ชจ๋“œ C++ ํด๋ž˜์Šค์— ๋กœ๊ทธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ทฐํฌํŠธ์— ๋กœ๊ทธ๊ฐ€ ๋‚˜์˜ค๊ฒŒ ๋œ๋‹ค.

 

๊ฒŒ์ž„๋ชจ๋“œ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค ์ ์šฉ ์™„๋ฃŒ

 

2. ์บ๋ฆญํ„ฐ ๊ตฌํ˜„ํ•˜๊ธฐ

1) ์บ๋ฆญํ„ฐ ์ƒ์„ฑํ•˜๊ธฐ

Visual Studio ์†”๋ฃจ์…˜์—์„œ .h ๋ฐ .cpp ํŒŒ์ผ์„ ์ง์ ‘ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, C++ ํด๋ž˜์Šค ๋งˆ๋ฒ•์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ์ ํŠธ์— ์ƒˆ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. C++ ํด๋ž˜์Šค ๋งˆ๋ฒ•์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—”์ง„์ด UE๋ณ„๋กœ ์ ํ•ฉํ•œ ๋งคํฌ๋กœ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ํ—ค๋” ๋ฐ ์†Œ์Šค ํ…œํ”Œ๋ฆฟ์„ ์ƒ์„ฑํ•œ๋‹ค.

 

์บ๋ฆญํ„ฐ ์ƒ์„ฑ

 

์ „ ๋‹จ๊ณ„์˜ ๊ฒŒ์ž„๋ชจ๋“œ์™€ ๋™์ผํ•˜๊ฒŒ, ์บ๋ฆญํ„ฐ C++ ํด๋ž˜์Šค๋„ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค๋„ ํ™•์žฅํ•œ ํ›„ ๊ธฐ๋ณธ ์บ๋ฆญํ„ฐ๋กœ ์„ค์ •ํ•œ๋‹ค. ๊ธฐ๋ณธ ๊ฒŒ์ž„๋ชจ๋“œ์—์„œ ๋””ํดํŠธ ํฐ ํด๋ž˜์Šค์— ์ง€์ •ํ•˜๋ฉด ๋œ๋‹ค.

 

๋””ํดํŠธ ํฐ ํด๋ž˜์Šค ์ง€์ •

 

2) ์บ๋ฆญํ„ฐ ์›€์ง์ด๊ธฐ

WASD ํ‚ค์— ์ž…๋ ฅ ์ถ• ๋งคํ•‘์„ ๊ตฌ์„ฑํ•˜์—ฌ ์ƒˆ ์บ๋ฆญํ„ฐ๊ฐ€ ๋งต์„ ์ด๋™ ํ•˜๋„๋ก ํ•  ๊ฒƒ์ด๋‹ค. ํ”„๋กœ์ ํŠธ ์„ธํŒ…์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ• ๋งคํ•‘์„ ๊ตฌ์„ฑํ•œ๋‹ค.

 

์ด๋™ ์ถ• ๋งคํ•‘

  • MoveForward: W, S
  • MoveRight: D, A

 

๋‹ค์Œ์œผ๋กœ ํ”Œ๋ ˆ์ด์–ด ์ž…๋ ฅ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  FPSCharacter ํด๋ž˜์Šค์— ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

  • InputComponent๋Š” ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์„ ์ •์˜ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋กœ ์ž…๋ ฅ์„ ์ˆ˜์‹ ํ•  ์•กํ„ฐ์— ๋ถ™์ผ ์ˆ˜ ์žˆ๋‹ค.

 

// Fill out your copyright notice in the Description page of Project Settings.


#include "FPSCharacter.h"

// Sets default values
AFPSCharacter::AFPSCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AFPSCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	// 'movement' ๋ฐ”์ธ๋”ฉ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
	PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
}

void AFPSCharacter::MoveForward(float Value)
{
	// ์–ด๋””๊ฐ€ '์•ž'์ธ์ง€ ์ฐพ๊ณ , ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ํ•ด๋‹น ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™ํ•˜๊ณ ์ž ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
	AddMovementInput(Direction, Value);
}    

void AFPSCharacter::MoveRight(float Value)
{
	// ์–ด๋””๊ฐ€ '์˜ค๋ฅธ์ชฝ'์ธ์ง€ ์ฐพ๊ณ , ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ํ•ด๋‹น ๋ฐฉํ–ฅ์œผ๋กœ ์ด๋™ํ•˜๊ณ ์ž ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
	FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
	AddMovementInput(Direction, Value);
}

 

์—ฌ๊ธฐ๊นŒ์ง€ ํ•˜๋ฉด ์บ๋ฆญํ„ฐ๊ฐ€ ์•ž, ๋’ค, ์–‘์˜†์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

3) ๋งˆ์šฐ์Šค๋กœ ์นด๋ฉ”๋ผ ์›€์ง์ด๊ธฐ

์บ๋ฆญํ„ฐ์˜ ์‹œ์„  ๋ฐ ์ด๋™ ๋ฐฉํ–ฅ์„ ๋งˆ์šฐ์Šค๋กœ ์กฐ์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด๋‹ค. ์ถ• ๋งคํ•‘๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ํ”„๋กœ์ ํŠธ ์„ธํŒ…์—์„œ ํšŒ์ „ ์ถ• ๋งคํ•‘์„ ๊ตฌ์„ฑํ•œ๋‹ค.

 

ํšŒ์ „ ์ถ• ๋งคํ•‘

  • Turn: Mouse X
  • LookUp: Mouse Y

 

ํšŒ์ „ ๋ฐ ๋ฐ”๋ผ๋ณด๊ธฐ์— ๋Œ€ํ•œ ๋งˆ์šฐ์Šค ์ž…๋ ฅ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. 

  • Character ๋ฒ ์ด์Šค ํด๋ž˜์Šค์— AddControllerYawInput, AddControllerPitchInput ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์–ด ๋ฐ”์ธ๋”ฉ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

 

void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	// 'movement' ๋ฐ”์ธ๋”ฉ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
	PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);    
	
	// 'look' ๋ฐ”์ธ๋”ฉ์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
	PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
	PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
}

 

4) ์บ๋ฆญํ„ฐ์— ๋ฉ”์‹œ ์ถ”๊ฐ€ํ•˜๊ธฐ

ํŠœํ† ๋ฆฌ์–ผ์˜ ์ƒ˜ํ”Œ ๋ฉ”์‹œ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ž„ํฌํŠธํ•˜์—ฌ ์ค€๋น„ํ•œ๋‹ค.

 

์• ์…‹ ์ž„ํฌํŠธ

 

์บ๋ฆญํ„ฐ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค๋ฅผ ์—ฐ ํ›„ ๋ฉ”์‹œ ์ปดํฌ๋„ŒํŠธ์— ์ค€๋น„ํ•œ ๋ฉ”์‹œ๋ฅผ ์„ ํƒํ•œ๋‹ค. ์ถ”๊ฐ€๋กœ ํŠธ๋žœ์Šคํผ์„ ์„ค์ •ํ•˜์—ฌ SkeletalMeshComponent๋ฅผ CapsuleComponent์— ์ •๋ ฌํ•œ๋‹ค.

 

๋ฉ”์‹œ ์ถ”๊ฐ€

 

5) ์นด๋ฉ”๋ผ ๋ทฐ ๋ณ€๊ฒฝํ•˜๊ธฐ

๋””ํดํŠธ ์นด๋ฉ”๋ผ๋Š” ๋ฉ”์‹œ์˜ ๋ชฉ ์•ˆ์ชฝ์— ์œ„์น˜ํ•˜์—ฌ ๊ฐœ์„ ์ด ํ•„์š”ํ•˜๋‹ค. ์œ„์น˜, ํ•„๋“œ ์˜ค๋ธŒ ๋ทฐ ๋“ฑ ์นด๋ฉ”๋ผ์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์กฐ์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” FPS ์นด๋ฉ”๋ผ๋ฅผ ๊ตฌ์„ฑํ•  ๊ฒƒ์ด๋‹ค.

 

๋จผ์ €, ์บ๋ฆญํ„ฐ ํด๋ž˜์Šค ํ—ค๋” ํŒŒ์ผ์—์„œ ํฌํ•จ๋œ ํŒŒ์ผ ๋ชฉ๋ก์„ ํ™•์žฅํ•˜์—ฌ ์นด๋ฉ”๋ผ ๊ด€๋ จ ๊ธฐ๋Šฅ์— ์•ก์„ธ์Šค ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •ํ•œ๋‹ค.

 

์ด๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์ถ”๊ฐ€ํ•œ ์ฝ”๋“œ์˜ ์œ„์น˜๋ฅผ ํ™•์ธํ•ด ๋ณด์ž!!!!!!!!!!
#include "FPSCharacter.generated.h" ์œ„์— ์œ„์น˜ํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"

 

๊ทธ ํ›„ cpp ํŒŒ์ผ์—์„œ ์นด๋ฉ”๋ผ ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ๊ณผ ์บก์А ์ปดํฌ๋„ŒํŠธ ์•„๋ž˜ ์นด๋ฉ”๋ผ๋ฅผ ๋ถ™์ด๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์นด๋ฉ”๋ผ ์œ„์น˜์™€ ํฐ์ด ์นด๋ฉ”๋ผ์˜ ํšŒ์ „์„ ์ œ์–ดํ•˜๋„๋ก ํ•œ๋‹ค.

 

AFPSCharacter::AFPSCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	// ์ผ์ธ์นญ ์นด๋ฉ”๋ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
	FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
	check(FPSCameraComponent != nullptr);

	// ์บก์А ์ปดํฌ๋„ŒํŠธ์— ์นด๋ฉ”๋ผ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์–ดํƒœ์น˜ํ•ฉ๋‹ˆ๋‹ค.
	FPSCameraComponent->SetupAttachment(CastChecked<USceneComponent, UCapsuleComponent>(GetCapsuleComponent()));

	// ์นด๋ฉ”๋ผ๊ฐ€ ๋ˆˆ ์•ฝ๊ฐ„ ์œ„์— ์œ„์น˜ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
	FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));

	// ํฐ์ด ์นด๋ฉ”๋ผ ํšŒ์ „์„ ์ œ์–ดํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
	FPSCameraComponent->bUsePawnControlRotation = true;
}

 

6) ์บ๋ฆญํ„ฐ์— 1์ธ์นญ ๋ฉ”์‹œ ์ถ”๊ฐ€ํ•˜๊ธฐ

FPS ๊ฒŒ์ž„์„ ๋งŒ๋“ค ๋•Œ๋Š” ๋ณดํ†ต ํ’€ ๋ฐ”๋”” ๋ฉ”์‹œ์™€ ๋ฌด๊ธฐ ๋ฐ ์† ๋ฉ”์‹œ๋ผ๋Š” ๋ณ„๋„์˜ ์บ๋ฆญํ„ฐ ๋ฉ”์‹œ 2๊ฐœ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ํ’€ ๋ฐ”๋”” ๋ฉ”์‹œ๋Š” 3์ธ์นญ ์‹œ์ ์—์„œ ์บ๋ฆญํ„ฐ๋ฅผ ๋ณผ ๋•Œ ์‚ฌ์šฉ๋˜๋ฉฐ, ํ”Œ๋ ˆ์ด์–ด๊ฐ€ 1์ธ์นญ ์‹œ์ ์œผ๋กœ ๊ฒŒ์ž„์„ ๋ณผ ๋•Œ๋Š” ์ˆจ๊ฒจ์ง„๋‹ค. ๋ฌด๊ธฐ ๋ฐ ์† ๋ฉ”์‹œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์นด๋ฉ”๋ผ์— ๋ถ™์–ด ์žˆ์œผ๋ฉฐ, ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๋งต์„ 1์ธ์นญ ์‹œ์ ์œผ๋กœ ๋ณผ ๋•Œ๋งŒ ํ‘œ์‹œ๋œ๋‹ค.

 

1์ธ์นญ ๋ฉ”์‹œ

 

1์ธ์นญ ๋ฉ”์‹œ๋ฅผ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์บ๋ฆญํ„ฐ ํ—ค๋” ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•œ ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด C++ ํŒŒ์ผ์˜ ์ƒ์„ฑ์ž ํ•จ์ˆ˜์— ์ถ”๊ฐ€ํ•œ๋‹ค.

  • SetOnlyOwnerSee๋Š” ์ด ๋ฉ”์‹œ๊ฐ€ ์ด ์บ๋ฆญํ„ฐ์— ๋น™์˜ํ•œ PlayerController ์—๋งŒ ๋ณด์ธ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

// ์†Œ์œ  ํ”Œ๋ ˆ์ด์–ด์˜ ์ผ์ธ์นญ ๋ฉ”์‹œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
check(FPSMesh != nullptr);

// ์†Œ์œ  ํ”Œ๋ ˆ์ด์–ด๋งŒ ์ด ๋ฉ”์‹œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
FPSMesh->SetOnlyOwnerSee(true);

// FPS ๋ฉ”์‹œ๋ฅผ FPS ์นด๋ฉ”๋ผ์— ์–ดํƒœ์น˜ํ•ฉ๋‹ˆ๋‹ค.
FPSMesh->SetupAttachment(FPSCameraComponent);

// ์ผ๋ถ€ ์ธ๋ฐ”์ด๋Ÿฐ๋จผํŠธ ์„€๋„๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜์—ฌ ๋‹จ์ผ ๋ฉ”์‹œ ๊ฐ™์€ ๋А๋‚Œ์„ ๋ณด์กดํ•ฉ๋‹ˆ๋‹ค.
FPSMesh->bCastDynamicShadow = false;
FPSMesh->CastShadow = false;

// ์†Œ์œ  ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ์ผ๋ฐ˜(์‚ผ์ธ์นญ) ๋ฐ”๋”” ๋ฉ”์‹œ๋ฅผ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
GetMesh()->SetOwnerNoSee(true);

 

 

1์ธ์นญ ๋ฉ”์‹œ๋ฅผ ์ž„ํฌํŠธํ•œ๋‹ค. ์ด๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•œ ํ›„ ์ž„ํฌํŠธ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 

1์ธ์นญ ๋ฉ”์‹œ ์ž„ํฌํŠธ

 

1์ธ์นญ ๋ฉ”์‹œ๋ฅผ 1์ธ์นญ ๋ฉ”์‹œ ์ปดํฌ๋„ŒํŠธ์— ์ถ”๊ฐ€ํ•œ ํ›„ ์‹คํ–‰ํ•˜๋ฉด, ๊ธฐ์กด ํ’€ ๋ฉ”์‹œ๋Š” ๋ณด์ด์ง€ ์•Š๊ณ  1์ธ์นญ ๋ฉ”์‹œ๋งŒ ๋ณด์ผ ๊ฒƒ์ด๋‹ค. ๋งŒ์•ฝ, ์—ฌ์ „ํžˆ ํ’€ ๋ฉ”์‹œ๊ฐ€ ๋ณด์ธ๋‹ค๋ฉด ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค์—์„œ ๋ฉ”์‹œ ๋””ํ…Œ์ผ ๋‚ด ๋ Œ๋”๋ง ์„ค์ •์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋œ๋‹ค.

 

๋ Œ๋”๋ง ์„ค์ • ๋ณ€๊ฒฝ

 

3. ๋ฐœ์‚ฌ์ฒด ๊ตฌํ˜„ํ•˜๊ธฐ

1) ๋ฐœ์‚ฌ์ฒด ์ถ”๊ฐ€ํ•˜๊ธฐ

C++ ํด๋ž˜์Šค ๋งˆ๋ฒ•์‚ฌ๋ฅผ ํ†ตํ•ด FPSProjectile ์•กํ„ฐ๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ๋ฐœ์‚ฌ์ฒด๊ฐ€ ๋  USphere ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

  • USphereComponent CollisionComponent: Sphere ์ฝœ๋ฆฌ์ „ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค
  • ProjectileMovementComponent: ๋ฐœ์‚ฌ์ฒด ์ด๋™ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.
  • FireInDirection ํ•จ์ˆ˜: ๋ฐœ์‚ฌ ๋ฐฉํ–ฅ์œผ๋กœ์˜ ๋ฐœ์‚ฌ์ฒด ์†๋„๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

 

AFPSProjectile::AFPSProjectile()
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	if (!RootComponent)
	{
		RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("ProjectileSceneComponent"));
	}

	if (!CollisionComponent)
	{
		// ์Šคํ”ผ์–ด๋ฅผ ๋‹จ์ˆœ ์ฝœ๋ฆฌ์ „ ํ‘œํ˜„์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
		CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
		// ์Šคํ”ผ์–ด์˜ ์ฝœ๋ฆฌ์ „ ๋ฐ˜๊ฒฝ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
		CollisionComponent->InitSphereRadius(15.0f);
		// ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฝœ๋ฆฌ์ „ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
		RootComponent = CollisionComponent;
	}

	if (!ProjectileMovementComponent)
	{
		// ์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ฐœ์‚ฌ์ฒด์˜ ์ด๋™์„ ์ฃผ๋„ํ•ฉ๋‹ˆ๋‹ค.
		ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
		ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
		ProjectileMovementComponent->InitialSpeed = 3000.0f;
		ProjectileMovementComponent->MaxSpeed = 3000.0f;
		ProjectileMovementComponent->bRotationFollowsVelocity = true;
		ProjectileMovementComponent->bShouldBounce = true;
		ProjectileMovementComponent->Bounciness = 0.3f;
		ProjectileMovementComponent->ProjectileGravityScale = 0.0f;
	}
}

// ๋ฐœ์‚ฌ ๋ฐฉํ–ฅ์œผ๋กœ์˜ ๋ฐœ์‚ฌ์ฒด ์†๋„๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
void AFPSProjectile::FireInDirection(const FVector& ShootDirection)
{
	ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;
}

 

์ด์ œ ๋ฐœ์‚ฌ์ฒด๋ฅผ ํ‘œํ˜„ํ•  ๋ฉ”์‹œ์™€ ๋จธํ„ฐ๋ฆฌ์–ผ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด๋‹ค.

 

ํŠœํ† ๋ฆฌ์–ผ์—์„œ ๋ฐœ์‚ฌ์ฒด ๋ฉ”์‹œ(Sphere)๋ฅผ ์ €์žฅํ•˜๊ณ  ์ž„ํฌํŠธ ํ•œ๋‹ค. ๊ธฐ์กด์—๋Š” C++ ํด๋ž˜์Šค๋ฅผ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค๋กœ ์ƒ์„ฑํ•œ ํ›„ ๊ทธ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค์— ๋ฉ”์‹œ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ–ˆ์ง€๋งŒ, ์ง€๊ธˆ์€ ๋ ˆํผ๋Ÿฐ์Šค ๋ณต์‚ฌ๋ฅผ ํ†ตํ•ด ์ ์šฉํ•ด ๋ณผ ๊ฒƒ์ด๋‹ค.

 

Sphere ์Šคํƒœํ‹ฑ ๋ฉ”์‹œ๋ฅผ ์šฐํด๋ฆญํ•˜๊ณ  ๋ ˆํผ๋Ÿฐ์Šค ๋ณต์‚ฌ(Copy Reference)๋ฅผ ์„ ํƒํ•œ ํ›„ ์ฝ”๋“œ์— ์ ์šฉํ•œ๋‹ค.

์—์…‹ ๋ ˆํผ๋Ÿฐ์Šค ๊ฒฝ๋กœ๋Š” ์ฝ˜ํ…์ธ  ๋ธŒ๋ผ์šฐ์ €์— ์Šคํ”ผ์–ด ๋จธํ‹ฐ๋ฆฌ์–ผ์„ ์ €์žฅํ•œ ์œ„์น˜์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ ๋ณต์‚ฌํ•œ ์—์…‹ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋ถ™์—ฌ ๋„ฃ์„ ๊ฒฝ์šฐ ์—์…‹์˜ ๋ ˆํผ๋Ÿฐ์Šค ๊ฒฝ๋กœ ์•ž์— ์—์…‹์˜ ํƒ€์ž… ์ด๋ฆ„์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” Material'/Game/Sphere.Sphere' ์ผ ๊ฒƒ์ด๋‹ค. ์—์…‹์˜ ํƒ€์ž… ์ด๋ฆ„(์˜ˆ: Material)์„ ๋ ˆํผ๋Ÿฐ์Šค ๊ฒฝ๋กœ์—์„œ ์ œ๊ฑฐํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.

 

๋ ˆํผ๋Ÿฐ์Šค ๋ณต์‚ฌ

AFPSProjectile::AFPSProjectile()
{
    if (!ProjectileMeshComponent)
    {
        ProjectileMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ProjectileMeshComponent"));
        static ConstructorHelpers::FObjectFinder<UStaticMesh>Mesh(TEXT("'/Game/Sphere.Sphere'"));
        if (Mesh.Succeeded())
        {
            ProjectileMeshComponent->SetStaticMesh(Mesh.Object);
        }
    }
}

 

๋‹ค์Œ์œผ๋กœ๋Š” ๋ฐœ์‚ฌ์ฒด์˜ ๋จธํ„ฐ๋ฆฌ์–ผ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด๋‹ค. ์ฝ˜ํ…์ธ  ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋จธํ„ฐ๋ฆฌ์–ผ์„ ์ƒ์„ฑํ•œ ํ›„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•œ๋‹ค.

 

๋ฐœ์‚ฌ์ฒด ๋จธํ„ฐ๋ฆฌ์–ผ

 

๋ฉ”์‹œ์™€ ๋™์ผํ•˜๊ฒŒ ๋ ˆํผ๋Ÿฐ์Šค ๋ณต์‚ฌ๋ฅผ ์ด์šฉํ•ด ๋ฉ”์‹œ ์ปดํฌ๋„ŒํŠธ์— ๋จธํ„ฐ๋ฆฌ์–ผ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

AFPSProjectile::AFPSProjectile()
{
    static ConstructorHelpers::FObjectFinder<UMaterial>Material(TEXT("'/Game/SphereMaterial.SphereMaterial'"));
    if (Material.Succeeded())
    {
        ProjectileMaterialInstance = UMaterialInstanceDynamic::Create(Material.Object, ProjectileMeshComponent);
    }
    ProjectileMeshComponent->SetMaterial(0, ProjectileMaterialInstance);
    ProjectileMeshComponent->SetRelativeScale3D(FVector(0.09f, 0.09f, 0.09f));
    ProjectileMeshComponent->SetupAttachment(RootComponent);
}

 

2) ์ŠˆํŒ… ๊ตฌํ˜„ํ•˜๊ธฐ

๋ฐœ์‚ฌ์ฒด ์•กํ„ฐ ์ถ”๊ฐ€๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด, ํ”„๋กœ์ ํŠธ ์„ธํŒ…์—์„œ ๋ฐœ์‚ฌ์ฒด ์ƒ์„ฑ์„ ์œ„ํ•œ ์•ก์…˜ ๋งคํ•‘์„ ๊ตฌ์„ฑํ•œ๋‹ค.

 

์•ก์…˜ ๋งคํ•‘

  • Fire: ์™ผ์ชฝ ๋งˆ์šฐ์Šค ๋ฒ„ํŠผ

 

๊ทธ ํ›„ ์บ๋ฆญํ„ฐ์— ์•ก์…˜ ๋งคํ•‘์— ๋Œ€ํ•ด ๋ฐ”์ธ๋”ฉ์ด ํ•„์š”ํ•˜๋‹ค. ์™ผ์ชฝ ๋งˆ์šฐ์Šค ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด Fire ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

 

void AFPSCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AFPSCharacter::Fire);
}

 

Fire ํ•จ์ˆ˜๋Š” ๋ฐœ์‚ฌ์ฒด ์ƒ์„ฑ์„ ํ•˜๋ฉฐ ์†๋„๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค. ์ด๋•Œ, ์ด๊ตฌ ๋ฐฉํ–ฅ(MuzzleOffset)๊ณผ ๋ฐœ์‚ฌ์ฒด ํด๋ž˜์Šค(ProjectileClass)๋Š” ์บ๋ฆญํ„ฐ๊ฐ€ ๊ฒฐ์ •ํ•˜๋ฉฐ ์ด ๊ฐ’์œผ๋กœ ๋ฐœ์‚ฌ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

 

class FPSPROJECT_API AFPSCharacter : public ACharacter
{
protected:
	// ์Šคํฐํ•  ๋ฐœ์‚ฌ์ฒด ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
	UPROPERTY(EditDefaultsOnly, Category = Projectile)
	TSubclassOf<class AFPSProjectile> ProjectileClass;

public:	
	// ๋ฐœ์‚ฌ์ฒด ๋ฐœ์‚ฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
	UFUNCTION()
	void Fire();

	// ์นด๋ฉ”๋ผ ์œ„์น˜๋กœ๋ถ€ํ„ฐ์˜ ์ด๊ตฌ ์˜คํ”„์…‹์ž…๋‹ˆ๋‹ค.
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
	FVector MuzzleOffset;
};
void AFPSCharacter::Fire()
{
	// ๋ฐœ์‚ฌ์ฒด ๋ฐœ์‚ฌ๋ฅผ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.
	if (ProjectileClass)
	{
		// ์นด๋ฉ”๋ผ ํŠธ๋žœ์Šคํผ์„ ๊ตฌํ•ฉ๋‹ˆ๋‹ค.
		FVector CameraLocation;
		FRotator CameraRotation;
		GetActorEyesViewPoint(CameraLocation, CameraRotation);

		// MuzzleOffset์ด ์นด๋ฉ”๋ผ ์‚ด์ง ์•ž์—์„œ ๋ฐœ์‚ฌ์ฒด๋ฅผ ์Šคํฐํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
		MuzzleOffset.Set(100.0f, 0.0f, 0.0f);

		// MuzzleOffset์„ ์นด๋ฉ”๋ผ ์ŠคํŽ˜์ด์Šค์—์„œ ์›”๋“œ ์ŠคํŽ˜์ด์Šค๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
		FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset);

		// ์กฐ์ค€์ด ์‚ด์ง ์œ„๋ฅผ ํ–ฅํ•˜๋„๋ก ์™œ๊ณกํ•ฉ๋‹ˆ๋‹ค.
		FRotator MuzzleRotation = CameraRotation;
		MuzzleRotation.Pitch += 10.0f;

		UWorld* World = GetWorld();
		if (World)
		{
			FActorSpawnParameters SpawnParams;
			SpawnParams.Owner = this;
			SpawnParams.Instigator = GetInstigator();

			// ์ด๊ตฌ์— ๋ฐœ์‚ฌ์ฒด๋ฅผ ์Šคํฐํ•ฉ๋‹ˆ๋‹ค.
			AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);
			if (Projectile)
			{
				// ๋ฐœ์‚ฌ์ฒด์˜ ์ดˆ๊ธฐ ํƒ„๋„๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
				FVector LaunchDirection = MuzzleRotation.Vector();
				Projectile->FireInDirection(LaunchDirection);
			}
		}
	}
}

 

์ด์ „ ๋‹จ๊ณ„์—์„œ ์ถ”๊ฐ€ํ•œ ๋ฐœ์‚ฌ์ฒด๋ฅผ ์บ๋ฆญํ„ฐ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•˜๋ฉด, ์™ผ์ชฝ ๋งˆ์šฐ์Šค ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ๋ฐœ์‚ฌ์ฒด๊ฐ€ ๋ฐœ์‚ฌ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

์ŠˆํŒ…

 

3) ๋ฐœ์‚ฌ์ฒด ์ˆ˜๋ช… ์ œํ•œํ•˜๊ธฐ

ํ˜„์žฌ ๋ฐœ์‚ฌ์ฒด๋Š” ์˜๊ตฌ ์ง€์†๋˜๊ณ  ์žˆ์–ด ์ˆ˜๋ช…์„ ์ œํ•œํ•ด์•ผ ํ•œ๋‹ค. ์•กํ„ฐ ํด๋ž˜์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” InitialLifeSpan๋กœ ์ƒ์„ฑ์ž์— ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฐœ์‚ฌ์ฒด๋ฅผ 3์ดˆ ํ›„์— ์ œ๊ฑฐํ•  ๊ฒƒ์ด๋‹ค.

 

AFPSProjectile::AFPSProjectile()
{
    // 3์ดˆ ํ›„ ๋ฐœ์‚ฌ์ฒด๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
    InitialLifeSpan = 3.0f;
}

 

4) ๋ฐœ์‚ฌ์ฒด ์ฝœ๋ฆฌ์ „

๋ฐœ์‚ฌ์ฒด๊ฐ€ ์›”๋“œ์˜ ๋‹ค๋ฅธ ์˜ค๋ธŒ์ ํŠธ์™€ ์ถฉ๋Œ๋˜๋„๋ก ์ถ”๊ฐ€ํ•  ๊ฒƒ์ด๋‹ค. ๋จผ์ € ์ฝœ๋ฆฌ์ „ ์„ธํŒ… ํŽธ์ง‘์ด ํ•„์š”ํ•˜๋‹ค. ์–ธ๋ฆฌ์–ผ์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ฝœ๋ฆฌ์ „ ์ฑ„๋„์„ ํ•จ๊ป˜ ์ œ๊ณตํ•˜์ง€๋งŒ, ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅํ•œ ์ฑ„๋„ ๋˜ํ•œ ์ œ๊ณตํ•œ๋‹ค.

 

ํ”„๋กœ์ ํŠธ ์„ธํŒ…์˜ ์ฝœ๋ฆฌ์ „์—์„œ ๋จผ์ € ์ƒˆ ์˜ค๋ธŒ์ ํŠธ ์ฑ„๋„์„ ์ƒ์„ฑํ•œ๋‹ค.

 

์˜ค๋ธŒ์ ํŠธ ์ฑ„๋„

  • Block: ๊ฐ€๋กœ๋ง‰ํž˜

 

 

ํ”„๋ฆฌ์…‹์—์„œ ์ƒˆ ํ”„๋กœํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝœ๋ฆฌ์ „ ํ”„๋ฆฌ์…‹์„ ์„ค์ •ํ•œ๋‹ค.

 

ํ”„๋ฆฌ์…‹

 

์ƒˆ ์ฝœ๋ฆฌ์ „ ์ฑ„๋„์˜ ์„ธํŒ…์„ FPSProjectile ์•กํ„ฐ์— ์ ์šฉํ•˜๋ฉด, ์ด์ œ ๋ฐœ์‚ฌ์ฒด์˜ ์ฝœ๋ฆฌ์ „ ์ธํ„ฐ๋ž™์…˜์„ ํƒ์ง€ํ•  ์ˆ˜ ์žˆ๊ณ  ์ด ์ฝœ๋ฆฌ์ „์ด ๋ฐ˜์‘ํ•˜๋Š” ๋ฐฉ์‹๋„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

AFPSProjectile::AFPSProjectile()
{
    if (!CollisionComponent)
    {    
        // ์Šคํ”ผ์–ด์˜ ์ฝœ๋ฆฌ์ „ ํ”„๋กœํŒŒ์ผ ์ด๋ฆ„์„ 'Projectile'๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
        CollisionComponent->BodyInstance.SetCollisionProfileName(TEXT("Projectile"));    
        // ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋”˜๊ฐ€์— ๋ถ€๋”ชํž ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ด๋ฒคํŠธ์ž…๋‹ˆ๋‹ค.
        CollisionComponent->OnComponentHit.AddDynamic(this, &AFPSProjectile::OnHit);
    }
}

// ๋ฐœ์‚ฌ์ฒด๊ฐ€ ์–ด๋”˜๊ฐ€์— ๋ถ€๋”ชํž ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
void AFPSProjectile::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComponent, FVector NormalImpulse, const FHitResult& Hit)
{
    if (OtherActor != this && OtherComponent->IsSimulatingPhysics())
    {
        OtherComponent->AddImpulseAtLocation(ProjectileMovementComponent->Velocity * 100.0f, Hit.ImpactPoint);
    }
    Destroy();
}

 

ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ฉด, ๋ฐœ์‚ฌ์ฒด๊ฐ€ ํ๋ธŒ์™€ ์ถฉ๋Œํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ ์ถฉ๋Œ๋˜๋Š” ํ๋ธŒ๋Š” ํ”ผ์ง์Šค ์‹œ๋ฎฌ๋ ˆ์ด์…˜(Simulate Physics)์ด ์ฒดํฌ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

 

4. ์บ๋ฆญํ„ฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€ํ•˜๊ธฐ

1) ์บ๋ฆญํ„ฐ ์• ๋‹ˆ๋ฉ”์ดํŒ…ํ•˜๊ธฐ

์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ์ƒ˜ํ”Œ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ž„ํฌํŠธ ํ•œ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ž„ํฌํŠธ๋Š” ์Šค์ผˆ๋ ˆํ†ค ์„ ํƒ์ด ํ•„์š”ํ•œ๋ฐ, ์ด๋•Œ ๋Œ€์ƒ ๋ฉ”์‹œ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ ํƒํ•˜์ง€ ์•Š์œผ๋ฉด ๋‚˜์ค‘์— ๋งต ์• ๋‹ˆ๋ฉ”์ด์…˜์—์„œ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

 

์ž„ํฌํŠธ ๋ฒ„ํŠผ ๋ˆŒ๋ €์„ ๋•Œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด, ์• ๋‹ˆ๋ฉ”์ด์…˜ ํƒญ ๋‚ด ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๋ฐ”์šด๋”๋ฆฌ์— ์Šค๋ƒ…์„ ํ™œ์„ฑํ™”์‹œํ‚ค๋ฉด ๋œ๋‹ค.

์• ๋‹ˆ๋ฉ”์ด์…˜ ์ž„ํฌํŠธ

 

์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ๋„ ์ƒ์„ฑํ•œ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ๋™์ผํ•œ ์Šค์ผˆ๋ ˆํ†ค์„ ์„ ํƒํ•œ ํ›„ ๋ถ€๋ชจ ํด๋ž˜์Šค๋Š” ์• ๋‹˜ ์ธ์Šคํ„ด์Šค(AnimInstance)๋กœ ์„ ํƒํ•œ๋‹ค.

 

์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ์ƒ์„ฑ

 

์ƒ์„ฑํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ๋ฅผ ์—ฐ ๋’ค, IsRunning ์ด๋ฆ„์„ ๊ฐ€์ง„ ๋ถ€์šธ(Boolean) ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ์Šคํ…Œ์ดํŠธ ๋จธ์‹ ์„ ๊ตฌ๋™ํ•  ์• ๋‹ˆ๋ฉ”์ด์…˜ ํŠธ๋žœ์ง€์…˜ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•œ ๊ฒƒ์ด๋‹ค.

 

์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ณ€์ˆ˜ ์ถ”๊ฐ€

 

2) ์ด๋ฒคํŠธ ๊ทธ๋ž˜ํ”„ ๊ตฌ์„ฑํ•˜๊ธฐ

๊ฒŒ์ž„์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ์ƒ์„ฑํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํŠธ๋žœ์ง€์…˜ ๋ณ€์ˆ˜๊ฐ€ ์ œ๋Œ€๋กœ ๋ฐœ๋™ํ•˜๋„๋ก ์• ๋‹ˆ๋ฉ”์ด์…˜์˜ ์ด๋ฒคํŠธ ๊ทธ๋ž˜ํ”„๋ฅผ ํŽธ์ง‘ํ•  ๊ฒƒ์ด๋‹ค. ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ๋‚ด ์ด๋ฒคํŠธ ๊ทธ๋ž˜ํ”„์—์„œ Event Blueprint Update Animation ๋…ธ๋“œ๋ฅผ ์„ ํƒํ•œ๋‹ค. ์ด ๋…ธ๋“œ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์—…๋ฐ์ดํŠธ๋  ๋•Œ๋งˆ๋‹ค ์Šคํ…Œ์ดํŠธ ๋ณ€์ˆ˜๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ํ•ญ์ƒ ๋ณ€์ˆ˜๊ฐ€ ๊ฒŒ์ž„ ์Šคํ…Œ์ดํŠธ์™€ ๋™๊ธฐํ™”๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Event Blueprint Update Animation ๋…ธ๋“œ

 

IsRunning ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ด๋ฒคํŠธ ๊ทธ๋ž˜ํ”„์ด๋‹ค.

 

์ด๋ฒคํŠธ ๊ทธ๋ž˜ํ”„

  1. ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์—…๋ฐ์ดํŠธ๋  ๋•Œ ์‹คํ–‰๋œ๋‹ค.
  2. ์บ๋ฆญํ„ฐ์˜ ์†๋„๋ฅผ ๊ฐ€์ ธ์™€ ์†๋„ ๋ฒกํ„ฐ์˜ ๊ธธ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  3. ๊ทธ ๊ธธ์ด๊ฐ€ 0๋ณด๋‹ค ํฌ๋‹ค๋ฉด ์ •์ง€ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์—, 0๋ณด๋‹ค ํด ๋•Œ IsRunning ๋ณ€์ˆ˜๋Š” true๊ฐ€ ๋˜๊ณ  ์ž‘์„ ๋•Œ false๊ฐ€ ๋œ๋‹ค.

 

3) ์• ๋‹ˆ๋ฉ”์ด์…˜ ์Šคํ…Œ์ดํŠธ ๋จธ์‹  ์ถ”๊ฐ€ํ•˜๊ธฐ

์ด์ œ ๋งŒ๋“  ๋ณ€์ˆ˜๋ฅผ ํ™œ์šฉํ•˜๋Š” ์Šคํ…Œ์ดํŠธ ๋จธ์‹ ์„ ์ƒ์„ฑํ•  ๊ฒƒ์ด๋‹ค. AnimGraph์—์„œ ์Šคํ…Œ์ดํŠธ ๋จธ์‹ ์„ ์ถ”๊ฐ€ํ•˜๊ณ  Final Animation Pose ๋…ธ๋“œ์˜ Result ์ž…๋ ฅ ์‹คํ–‰ ํ•€์— ์—ฐ๊ฒฐํ•œ๋‹ค.

ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” ์ƒˆ ์Šคํ…Œ์ดํŠธ ๋จธ์‹  ์ถ”๊ฐ€...(Add New State Machine...)๋ฅผ ์„ ํƒํ•˜๋ผ๊ณ  ๋˜์–ด ์žˆ๋‹ค.
๋งŒ์•ฝ ์•ˆ ๋ณด์ธ๋‹ค๋ฉด, State Machine์„ ์„ ํƒํ•˜๋ฉด ์ƒ์„ฑ๋œ๋‹ค.

 

์Šคํ…Œ์ดํŠธ ๋จธ์‹  ์ถ”๊ฐ€

 

์ƒ์„ฑํ•œ ์Šคํ…Œ์ดํŠธ ๊ทธ๋ž˜ํ”„๋ฅผ ์—ด๊ณ  ํ•„์š”ํ•œ ์Šคํ…Œ์ดํŠธ๋งŒํผ ์ถ”๊ฐ€ํ•˜๋Š”๋ฐ, ์ด์ „์— ์ž„ํฌํŠธ ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ˆ˜๋งŒํผ ์Šคํ…Œ์ดํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋œ๋‹ค.

 

์Šคํ…Œ์ดํŠธ ์ถ”๊ฐ€

 

์ƒ์„ฑ์ด ์™„๋ฃŒ๋œ ์Šคํ…Œ์ดํŠธ์— ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‹คํ–‰ํ•˜๋Š” ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค. ์ด ๊ณผ์ •์„ ์ถ”๊ฐ€ํ•œ ์Šคํ…Œ์ดํŠธ๋งŒํผ ๋ฐ˜๋ณตํ•œ๋‹ค.

 

์Šคํ…Œ์ดํŠธ ์—ฐ๊ฒฐ

 

์ด์ œ ์Šคํ…Œ์ดํŠธ ๊ทธ๋ž˜ํ”„์—์„œ ์Šคํ…Œ์ดํŠธ ๋…ธ๋“œ ์‚ฌ์ด์˜ ํŠธ๋žœ์ง€์…˜์„ ์—ฐ๊ฒฐํ•ด์•ผ ํ•œ๋‹ค.

 

ํŠธ๋žœ์ง€์…˜ ์—ฐ๊ฒฐ

  • Entry ๋…ธ๋“œ์—์„œ Idle ์Šคํ…Œ์ดํŠธ ๋…ธ๋“œ๋กœ ์—ฐ๊ฒฐํ•œ๋‹ค.
  • Idle ์Šคํ…Œ์ดํŠธ ๋…ธ๋“œ์™€ Run ์Šคํ…Œ์ดํŠธ ๋…ธ๋“œ๋ฅผ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์—ฐ๊ฒฐํ•œ๋‹ค.
    • Idle์—์„œ Run ํŠธ๋žœ์ง€์…˜์€ IsRunning ๋ณ€์ˆ˜๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค.
    • Run์—์„œ Idle ํŠธ๋žœ์ง€์…˜์€ IsRunning ๋ณ€์ˆ˜์˜ Not ๊ฐ’์„ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค.

 

4) ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ฐ ์บ๋ฆญํ„ฐ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ์—ฐ๊ฒฐํ•˜๊ธฐ

์ด์ œ ์บ๋ฆญํ„ฐ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ํด๋ž˜์Šค๋กœ ์ด๋™ํ•˜์—ฌ FPSMesh์˜ ์• ๋‹˜ ํด๋ž˜์Šค์— ๋ฐฉ๊ธˆ ์ž‘์—…ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

 

์• ๋‹ˆ๋ฉ”์ด์…˜ ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ์—ฐ๊ฒฐ

 

์–ด์ƒ‰ํ•˜๊ฒŒ ๊ตณ์–ด์žˆ์–ด ๋ณด์˜€๋˜ FPSMesh๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์›€์ง์ด๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์• ๋‹ˆ๋ฉ”์ด์…˜ ์™„๋ฃŒ

์ €์ž‘์žํ‘œ์‹œ (์ƒˆ์ฐฝ์—ด๋ฆผ)
'๐Ÿ“ Game/โœ Unreal' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [Unreal][C++] ์•„์ดํ…œ ํš๋“, ์ฐฉ์šฉ
  • [Unreal][C++] ํ”Œ๋ ˆ์ด์–ด ์บ๋ฆญํ„ฐ
  • [Unreal][Lyra] ํ–ฅ์ƒ๋œ ์ž…๋ ฅ
  • [Unreal][Lyra] ๊ฒŒ์ž„ํ”Œ๋ ˆ์ด ์–ด๋นŒ๋ฆฌํ‹ฐ ์‹œ์Šคํ…œ
Blxxming
Blxxming
CS ์ง€์‹๊ณผ ๊ณต๋ถ€ํ•˜๋‹ค ๋ฐฐ์šด ๊ฒƒ, ๊ฒฝํ—˜ํ•œ ๊ฒƒ ๋“ฑ์„ ๊ธฐ๋กํ•˜๋Š” ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.
  • Blxxming
    ๐Ÿ’ก๋ฒˆ๋œฉ๐Ÿ’ก
    Blxxming
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
  • ๊ณต์ง€์‚ฌํ•ญ

    • Tech Interview
    • ๐Ÿ“š Tech (246)
      • ๐Ÿ“ Computer Science (96)
        • โœ OS (12)
        • โœ Network & Web (10)
        • โœ Database (11)
        • โœ Data Structure (6)
        • โœ Algorithm (40)
        • โœ Design Pattern (9)
        • โœ Cloud Computing (3)
        • โœ (5)
      • ๐Ÿ“ Language (73)
        • โœ Language (6)
        • โœ C & C++ (11)
        • โœ C# (19)
        • โœ JAVA (37)
      • ๐Ÿ“ Game (43)
        • โœ Computer Graphics (2)
        • โœ Unity (14)
        • โœ Unreal (26)
        • โœ (1)
      • ๐Ÿ“ Book (34)
        • โœ Effective (3)
        • โœ Game Server (16)
        • โœ Clean Code (14)
        • โœ (1)
  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.0
Blxxming
[Unreal][C++] 1์ธ์นญ ์ŠˆํŒ… ํŠœํ† ๋ฆฌ์–ผ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”