언어:
페이지 정보
수준별:
엔진 버전:
언리얼 엔진

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

언리얼 엔진

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