2.8 - 캐릭터에 일인칭 메시 추가

일인칭 슈팅 캐릭터에 일인칭 메시를 추가하는 법을 배워봅니다.

Windows
MacOS
Linux

FPS 게임 제작시 흔히 사용되는 접근법이라면, 전신 바디 메시 하나, "무기와 손" 메시 하나, 별개의 캐릭터 메시를 두 개 사용하는 것입니다. 전신 메시는 삼인칭 시점에서 캐릭터를 볼 때 사용되지만, 플레이어가 일인칭 시점에서 게임을 볼 때는 숨깁니다. "무기와 손" 메시는 전형적으로 카메라에 붙여 플레이어가 일인칭 시점에서 맵을 볼 때 플레이어에게만 보이는 것입니다. 이 글에서는 캐릭터에 일인칭 메시를 추가해 보도록 하겠습니다.

일인칭 캐릭터 메시 추가

  1. Visual Studio 로 돌아와서 FPSCharacter.h 를 열고 다음 코드를 추가합니다:

    // 일인칭 메시 (팔), 소유 플레이어에게만 보입니다.
    UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
    USkeletalMeshComponent* FPSMesh;
  2. FPSCharacter.cpp 를 열고 다음 코드를 추가하여 일인칭 메시를 생성 및 환경설정합니다:

    // 일인칭 메시 컴포넌트입니다.
    FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
    // 소유 플레이어만 이 메시를 볼 수 있습니다.
    FPSMesh->SetOnlyOwnerSee(true);
    // FPS 메시를 FPS 카메라에 붙입니다.
    FPSMesh->SetupAttachment(FPSCameraComponent);
    // 일부 환경 섀도잉을 꺼 메시가 하나인 듯 보이는 느낌을 유지합니다.
    FPSMesh->bCastDynamicShadow = false;
    FPSMesh->CastShadow = false;

    SetOnlyOwnerSee 는 이 메시가 이 Character 를 빙의한 PlayerController 에게만 보임을 나타냅니다. 이 코드는 메시를 카메라에도 붙이고 배경 그림자도 끕니다. 카메라에 붙은 팔이 그림자를 드리우도록 하면 일인칭 캐릭터용 메시가 하나라는 환상이 깨질 것입니다.

  3. FPSCharacter.cpp 에 다음 코드를 추가하여 소유 캐릭터에서 기존 삼인칭 메시를 숨깁니다:

    // 자신 이외 모두가 일반 몸통 메시를 볼 수 있습니다.
    GetMesh()->SetOwnerNoSee(true);
  4. Visual Studio 에서 FPSCharacter 헤더 (*.h) 및 CPP (*.cpp) 파일을 저장합니다.

  5. Solution Explorer 에서 FPSProject 를 찾습니다.

  6. FPSProject 에 우클릭하고 Build 를 선택하여 프로젝트를 컴파일합니다.

    BuildProject.png

  7. 빌드 완료 후, PIE 모드에서 FPSProject 를 열고 실행합니다.

    HiddenMeshInGame.png

    이 시점에서는, 에디터 안에서 캐릭터 메시가 보이지 않을 것입니다.

메시 블루프린트 빌드

계속하기 전, 다음 링크에서 샘플 메시를 다운로드하여 풀어주세요: "일인칭 스켈레탈 메시"

  1. 콘텐츠 브라우저의 파일창 안에 우클릭 하여 애셋 임포트 대화창을 엽니다.

  2. /Game... 으로 임포트 를 클릭하여 임포트 대화창을 엽니다.

    RightClickImport.png

  3. HeroFPP.fbx 메시 파일을 찾아 선택합니다.

  4. 열기 를 클릭하여 프로젝트에 메시 임포트를 시작합니다.

  5. 콘텐츠 브라우저 에서, FBX 임포트 옵션 대화창이 뜹니다. 임포트 를 클릭하면 프로젝트에 메시를 추가합니다.

    스무딩 그룹 관련 다음과 같은 오류는 무시합니다: FBXWarning.png
    이 메시는 여전히 일인칭 메시 구성을 나타내며, 나중의 섹션에서 구성하게 될 애니메이션 작업을 할 것입니다.

  6. 저장 을 클릭하여 임포트된 메시를 저장합니다.

  7. 콘텐츠 브라우저 에서 Blueprints 폴더로 다시 돌아갑니다.

  8. BP_FPSCharacter 아이콘에 더블클릭하여 블루프린트 에디터 에서 엽니다.

  9. 컴포넌트 탭에서 새로운 FPSMesh 컴포넌트를 찾습니다.

    LocateFPSMeshComponent.png

    FirstPersonMesh 컴포넌트는 FirstPersonCameraComponent 의 자손이라, 카메라에 항상 붙어있다는 뜻입니다.

  10. 컴포넌트 메뉴에서 FirstPersonMesh 를 클릭합니다.

  11. 디테일 탭에서 Mesh 섹션으로 스크롤해 내려가 "없음" 이라는 드롭다운 메뉴를 클릭합니다. 이제, HeroFPP 스켈레탈 메시를 선택하여 뷰포트 에 팔을 추가합니다.

    SelectHeroFPPSkeletalMesh.png

  12. 새로 추가된 HeroFPP 스켈레탈 메시는 뷰포트 안에서 다음과 같아 보일 것입니다.

    HeroFPPMesh_Viewport.png

  13. 새로 추가된 메시의 트랜스폼이 카메라 앞에 오도록 조절합니다. 위치 를 {240, 0, 35} 로, 회전 을 {-180, 50, -180} 로 설정합니다.

    이미지를 클릭하면 확대됩니다.

  14. 블루프린트 에디터 를 닫기 전 BP_FPSCharacter 블루프린트를 반드시 컴파일 하고 저장 합니다.

게임내 새 메시 확인

  1. 레벨 에디터 툴바플레이 버튼을 클릭하여 게임내에서 새 메시를 확인합니다.

    NewMeshInGame.png

  2. 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) 구현법을 알아보도록 하겠습니다.

Select Skin
Light
Dark

새로운 언리얼 엔진 4 문서 사이트에 오신 것을 환영합니다!

문서 사이트에 대한 의견을 모을 수 있는 피드백 시스템을 포함해서 여러가지 새로운 기능을 준비하고 있습니다. 아래 Documentation Feedback 포럼(영문) 또는 언리얼 엔진 네이버 공식 카페(한글) 중 편하신 곳에 의견이나 문제점을 알려 주세요.

새 시스템이 준비되면 알려 드리겠습니다.

네이버 카페
공식 포럼