3. 폰 무브먼트 컴포넌트의 작동방식 코딩

폰 무브먼트 컴포넌트 조종하는 폰의 매 프레임 위치를 어떻게 결정하는지 정의하는 코드를 작성합니다.

Windows
MacOS
Linux
  1. 이제 Visual Studio 로 돌아가 커스텀 Pawn Movement Component 프로그래밍을 하면 됩니다. 작성해야 할 것은 (Actor 의 Tick 함수와 비슷하게) TickComponent 함수로 각 프레임 어떻게 이동할지를 알려주면 됩니다. CollidingPawnMovementComponent.h 에서, 클래스 정의의 TickComponent 를 덮어써야 합니다:

    public:
        virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;  

    이 함수를 CollidingPawnMovementComponent.cpp 에 정의해 줍니다:

    void UCollidingPawnMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
    {
        Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
    
        // 모든 것이 아직 유효한지, 이동 가능한지 확인합니다.
        if (!PawnOwner || !UpdatedComponent || ShouldSkipUpdate(DeltaTime))
        {
            return;
        }
    
        // ACollidingPawn::Tick 에 설정한 무브먼트 벡터를 구(한 뒤 소거)합니다.
        FVector DesiredMovementThisFrame = ConsumeInputVector().GetClampedToMaxSize(1.0f) * DeltaTime * 150.0f;
        if (!DesiredMovementThisFrame.IsNearlyZero())
        {
            FHitResult Hit;
            SafeMoveUpdatedComponent(DesiredMovementThisFrame, UpdatedComponent->GetComponentRotation(), true, Hit);
    
            // 무언가에 부딛혔으면, 돌아가 봅니다.
            if (Hit.IsValidBlockingHit())
            {
                SlideAlongSurface(DesiredMovementThisFrame, 1.f - Hit.Time, Hit.Normal, Hit);
            }
        }
    };

    이 코드는 적합한 면을 미끄러져 다니며 월드를 부드럽게 움직이도록 을 이동시킵니다. 에는 중력이 적용되지 않으며, 최대 속력은 초당 150 언리얼 유닛 으로 하드코딩되어 있습니다.

    이 TickComponent 함수는 UPawnMovementComponent 클래스에 제공되는 강력한 기능을 몇 가지 활용하고 있습니다.

    ConsumeInputVector 는 미동 입력을 저장하는 데 사용할 내장 변수 값을 보고 및 소거합니다.

    SafeMoveUpdatedComponent언리얼 엔진 피직스를 사용하여 입체 장애물을 피해 Pawn Movement Component 를 이동시킵니다.

    SlideAlongSurface 는 이동하다가 충돌 발생시 그냥 제자리에 멈춰 벽이나 경사로에 "달라붙기" 보다는, 그 표면을 타고 부드럽게 미끄러지도록 하는 데 관련된 물리 계산 처리를 합니다.

    Pawn Movement Components 에는 설명할 만한 기능이 더 있지만, 이 튜토리얼 범위에는 필요치 않습니다. Floating Pawn Movement, Spectator Pawn Movement, Character Movement Component 같은 다른 클래스를 살펴보면 추가적인 용례나 개념을 찾아볼 수 있습니다.

Pawn Movement Component 작동방식을 정의했으니, 이제 모든 것을 커스텀 Pawn 클래스에 묶을 코드를 작성하면 됩니다.

작업중 코드

CollidingPawn.h

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameFramework/Pawn.h"
#include "CollidingPawn.generated.h"

UCLASS()
class HOWTO_COMPONENTS_API ACollidingPawn : public APawn
{
    GENERATED_BODY()

public:
    // Sets default values for this pawn's properties
    ACollidingPawn();

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* InputComponent) override;

    UParticleSystemComponent* OurParticleSystem;
};

CollidingPawn.cpp

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "HowTo_Components.h"
#include "CollidingPawn.h"

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

    // Our root component will be a sphere that reacts to physics
    USphereComponent* SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
    RootComponent = SphereComponent;
    SphereComponent->InitSphereRadius(40.0f);
    SphereComponent->SetCollisionProfileName(TEXT("Pawn"));

    // Create and position a mesh component so we can see where our sphere is
    UStaticMeshComponent* SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
    SphereVisual->SetupAttachment(RootComponent);
    static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
    if (SphereVisualAsset.Succeeded())
    {
        SphereVisual->SetStaticMesh(SphereVisualAsset.Object);
        SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -40.0f));
        SphereVisual->SetWorldScale3D(FVector(0.8f));
    }

    // Create a particle system that we can activate or deactivate
    OurParticleSystem = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("MovementParticles"));
    OurParticleSystem->SetupAttachment(SphereVisual);
    OurParticleSystem->bAutoActivate = false;
    OurParticleSystem->SetRelativeLocation(FVector(-20.0f, 0.0f, 20.0f));
    static ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleAsset(TEXT("/Game/StarterContent/Particles/P_Fire.P_Fire"));
    if (ParticleAsset.Succeeded())
    {
        OurParticleSystem->SetTemplate(ParticleAsset.Object);
    }

    // Use a spring arm to give the camera smooth, natural-feeling motion.
    USpringArmComponent* SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraAttachmentArm"));
    SpringArm->SetupAttachment(RootComponent);
    SpringArm->RelativeRotation = FRotator(-45.f, 0.f, 0.f);
    SpringArm->TargetArmLength = 400.0f;
    SpringArm->bEnableCameraLag = true;
    SpringArm->CameraLagSpeed = 3.0f;

    // Create a camera and attach to our spring arm
    UCameraComponent* Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("ActualCamera"));
    Camera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);

    // Take control of the default player
    AutoPossessPlayer = EAutoReceiveInput::Player0;
}

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

}

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

}

// Called to bind functionality to input
void ACollidingPawn::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
    Super::SetupPlayerInputComponent(InputComponent);

}

CollidingPawnMovementComponent.h

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameFramework/PawnMovementComponent.h"
#include "CollidingPawnMovementComponent.generated.h"

/**
    * 
    */
UCLASS()
class HOWTO_COMPONENTS_API UCollidingPawnMovementComponent : public UPawnMovementComponent
{
    GENERATED_BODY()

public:
    virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;  
};

CollidingPawnMovementComponent.cpp

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "HowTo_Components.h"
#include "CollidingPawnMovementComponent.h"

void UCollidingPawnMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);

    // Make sure that everything is still valid, and that we are allowed to move.
    if (!PawnOwner || !UpdatedComponent || ShouldSkipUpdate(DeltaTime))
    {
        return;
    }

    // Get (and then clear) the movement vector that we set in ACollidingPawn::Tick
    FVector DesiredMovementThisFrame = ConsumeInputVector().GetClampedToMaxSize(1.0f) * DeltaTime * 150.0f;
    if (!DesiredMovementThisFrame.IsNearlyZero())
    {
        FHitResult Hit;
        SafeMoveUpdatedComponent(DesiredMovementThisFrame, UpdatedComponent->GetComponentRotation(), true, Hit);

        // If we bumped into something, try to slide along it
        if (Hit.IsValidBlockingHit())
        {
            SlideAlongSurface(DesiredMovementThisFrame, 1.f - Hit.Time, Hit.Normal, Hit);
        }
    }
};
Select Skin
Light
Dark

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

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

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

네이버 카페
공식 포럼