Choose your operating system:
Windows
macOS
Linux
FPS 게임 제작시 흔히 사용되는 접근법이라면, 전신 바디 메시 하나, "무기와 손" 메시 하나, 별개의 캐릭터 메시를 두 개 사용하는 것입니다. 전신 메시는 삼인칭 시점에서 캐릭터를 볼 때 사용되지만, 플레이어가 일인칭 시점에서 게임을 볼 때는 숨깁니다. "무기와 손" 메시는 전형적으로 카메라에 붙여 플레이어가 일인칭 시점에서 맵을 볼 때 플레이어에게만 보이는 것입니다. 이 글에서는 캐릭터에 일인칭 메시를 추가해 보도록 하겠습니다.
일인칭 캐릭터 메시 추가
-
Visual Studio 로 돌아와서
FPSCharacter.h
를 열고 다음 코드를 추가합니다:// 일인칭 메시 (팔), 소유 플레이어에게만 보입니다. UPROPERTY(VisibleDefaultsOnly, Category = Mesh) USkeletalMeshComponent* FPSMesh;
-
FPSCharacter.cpp
를 열고 다음 코드를 추가하여 일인칭 메시를 생성 및 환경설정합니다:// 일인칭 메시 컴포넌트입니다. FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh")); // 소유 플레이어만 이 메시를 볼 수 있습니다. FPSMesh->SetOnlyOwnerSee(true); // FPS 메시를 FPS 카메라에 붙입니다. FPSMesh->SetupAttachment(FPSCameraComponent); // 일부 환경 섀도잉을 꺼 메시가 하나인 듯 보이는 느낌을 유지합니다. FPSMesh->bCastDynamicShadow = false; FPSMesh->CastShadow = false;
SetOnlyOwnerSee
는 이 메시가 이Character
를 빙의한PlayerController
에게만 보임을 나타냅니다. 이 코드는 메시를 카메라에도 붙이고 배경 그림자도 끕니다. 카메라에 붙은 팔이 그림자를 드리우도록 하면 일인칭 캐릭터용 메시가 하나라는 환상이 깨질 것입니다. -
FPSCharacter.cpp
에 다음 코드를 추가하여 소유 캐릭터에서 기존 삼인칭 메시를 숨깁니다:// 자신 이외 모두가 일반 몸통 메시를 볼 수 있습니다. GetMesh()->SetOwnerNoSee(true);
-
Visual Studio 에서
FPSCharacter
헤더 (*.h) 및 CPP (*.cpp) 파일을 저장합니다. -
Solution Explorer 에서 FPSProject 를 찾습니다.
-
FPSProject 에 우클릭하고 Build 를 선택하여 프로젝트를 컴파일합니다.
-
빌드 완료 후, PIE 모드에서 FPSProject 를 열고 실행합니다.
이 시점에서는, 에디터 안에서 캐릭터 메시가 보이지 않을 것입니다.
메시 블루프린트 빌드
계속하기 전, 다음 링크에서 샘플 메시를 다운로드하여 풀어주세요: "일인칭 스켈레탈 메시"
-
콘텐츠 브라우저의 파일창 안에 우클릭 하여 애셋 임포트 대화창을 엽니다.
-
/Game... 으로 임포트 를 클릭하여 임포트 대화창을 엽니다.
-
HeroFPP.fbx 메시 파일을 찾아 선택합니다.
-
열기 를 클릭하여 프로젝트에 메시 임포트를 시작합니다.
-
콘텐츠 브라우저 에서, FBX 임포트 옵션 대화창이 뜹니다. 임포트 를 클릭하면 프로젝트에 메시를 추가합니다.
스무딩 그룹 관련 다음과 같은 오류는 무시합니다:
이 메시는 여전히 일인칭 메시 구성을 나타내며, 나중의 섹션에서 구성하게 될 애니메이션 작업을 할 것입니다. -
저장 을 클릭하여 임포트된 메시를 저장합니다.
-
콘텐츠 브라우저 에서 Blueprints 폴더로 다시 돌아갑니다.
-
BP_FPSCharacter 아이콘에 더블클릭하여 블루프린트 에디터 에서 엽니다.
-
컴포넌트 탭에서 새로운 FPSMesh 컴포넌트를 찾습니다.
FirstPersonMesh 컴포넌트는 FirstPersonCameraComponent 의 자손이라, 카메라에 항상 붙어있다는 뜻입니다.
-
컴포넌트 메뉴에서 FirstPersonMesh 를 클릭합니다.
-
디테일 탭에서 Mesh 섹션으로 스크롤해 내려가 "없음" 이라는 드롭다운 메뉴를 클릭합니다. 이제, HeroFPP 스켈레탈 메시를 선택하여 뷰포트 에 팔을 추가합니다.
-
새로 추가된 HeroFPP 스켈레탈 메시는 뷰포트 안에서 다음과 같아 보일 것입니다.
-
새로 추가된 메시의 트랜스폼이 카메라 앞에 오도록 조절합니다. 위치 를 {240, 0, 35} 로, 회전 을 {-180, 50, -180} 로 설정합니다.
이미지를 클릭하면 확대됩니다.
-
블루프린트 에디터 를 닫기 전 BP_FPSCharacter 블루프린트를 반드시 컴파일 하고 저장 합니다.
게임내 새 메시 확인
-
레벨 에디터 툴바 의 플레이 버튼을 클릭하여 게임내에서 새 메시를 확인합니다.
-
Esc 키를 누르거나 레벨 에디터의 중지 버튼을 눌러 에디터에서 플레이 (PIE) 모드를 빠져나갑니다.
완성 섹션 코드
FPSCharacter.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"
UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AFPSCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// Handles input for moving forward and backward.
UFUNCTION()
void MoveForward(float Value);
// Handles input for moving right and left.
UFUNCTION()
void MoveRight(float Value);
// Sets jump flag when key is pressed.
UFUNCTION()
void StartJump();
// Clears jump flag when key is released.
UFUNCTION()
void StopJump();
// FPS camera.
UPROPERTY(VisibleAnywhere)
UCameraComponent* FPSCameraComponent;
// First-person mesh (arms), visible only to the owning player.
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
USkeletalMeshComponent* FPSMesh;
};
FPSCharacter.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "FPSProject.h"
#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;
// Create a first person camera component.
FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
// Attach the camera component to our capsule component.
FPSCameraComponent->SetupAttachment(GetCapsuleComponent());
// Position the camera slightly above the eyes.
FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
// Allow the pawn to control camera rotation.
FPSCameraComponent->bUsePawnControlRotation = true;
// Create a first person mesh component for the owning player.
FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
// Only the owning player sees this mesh.
FPSMesh->SetOnlyOwnerSee(true);
// Attach the FPS mesh to the FPS camera.
FPSMesh->SetupAttachment(FPSCameraComponent);
// Disable some environmental shadowing to preserve the illusion of having a single mesh.
FPSMesh->bCastDynamicShadow = false;
FPSMesh->CastShadow = false;
// The owning player doesn't see the regular (third-person) body mesh.
GetMesh()->SetOwnerNoSee(true);
}
// Called when the game starts or when spawned
void AFPSCharacter::BeginPlay()
{
Super::BeginPlay();
if (GEngine)
{
// Put up a debug message for five seconds. The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
}
}
// Called every frame
void AFPSCharacter::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
// Called to bind functionality to input
void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// Set up "movement" bindings.
PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
// Set up "look" bindings.
PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
// Set up "action" bindings.
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
}
void AFPSCharacter::MoveForward(float Value)
{
// Find out which way is "forward" and record that the player wants to move that way.
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
void AFPSCharacter::MoveRight(float Value)
{
// Find out which way is "right" and record that the player wants to move that way.
FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
AddMovementInput(Direction, Value);
}
void AFPSCharacter::StartJump()
{
bPressedJump = true;
}
void AFPSCharacter::StopJump()
{
bPressedJump = false;
}
축하합니다! 지금까지 배우신 내용은 다음과 같습니다:
✓ 새 캐릭터 생성 ✓ 축 매핑 구성 ✓ 캐릭터 동작 함수 구현 ✓ 마우스 카메라 컨트롤 구현 ✓ 캐릭터 점프 구현 ✓ 캐릭터에 메시 추가 ✓ 카메라 시점 변경 ✓ 캐릭터에 일인칭 메시 추가
이제 다음 섹션에서는 발사체(projectile) 구현법을 알아보도록 하겠습니다.