04. 캐릭터 이동하기 - Elysia-ff/UE4-Custom_Stencil_Tutorial GitHub Wiki
Place Actors -> Volumes 에서 Nav Mesh Bounds Volume을 Level에 끌어다 놓고 크기를 적당히 맞춰준다.
이제 Viewport 에서 P를 누르거나 Show -> Navigation을 체크하면 액터가 이동할 수 있는 지역이 초록색으로 표시된다.
캐릭터가 Nav Mesh상에서 움직이려면 UE에서 제공하는 네비게이션 시스템을 이용하면 된다.
StealthTutorial.Build.cs
를 다음과 같이 수정한다.
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "AIModule" });
AAIController
를 확장해서 AHitmanAIController
를 생성하고 Hitman.h
에 아래 코드를 추가한다.
public:
AHitman(const FObjectInitializer& ObjectInitializer);
Hitman.cpp
에 방금 추가한 생성자를 정의하고 AHitmanAIController
를 기본 컨트롤러로 등록한다.
#include "Character/Controller/HitmanAIController.h"
AHitman::AHitman(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
AIControllerClass = AHitmanAIController::StaticClass();
}
그다음 StealthPlayerController.cpp
의 BeginPlay
를 다음과 같이 수정한다.
Hitman = GetWorld()->SpawnActor<AHitman>(HitmanBlueprint, FVector(0.0f, 0.0f, 90.0f), FRotator::ZeroRotator, Param);
check(Hitman);
Hitman->SpawnDefaultController();
이제 게임을 시작하면 AHitman
과 함께 AHitmanAIController
가 Level에 생성된다.
AIController
의 MoveToLocation
이나 MoveToActor
를 호출하면 빙의된 Pawn이 해당 지점으로 이동한다.
MoveToLocation
은 목적지 좌표로 이동하고, MoveToActor
는 목표 Actor의 좌표로 이동하되 Actor가 이동하면 따라간다.
여기서는 마우스 오른클릭을 누르고 있으면 마우스를 따라 이동하게 하자.
오른클릭 버튼을 Input에 바인드 하고 StealthPlayerController.h
에 다음 코드를 추가한다.
protected:
virtual void SetupInputComponent() override;
private:
void OnRMBPressed();
void OnRMBReleased();
void MoveHitmanToMouseCursor();
private:
bool bOnRMB;
StealthPlayerController.cpp
에 각 함수를 정의한다.
#include "Character/Controller/HitmanAIController.h"
void AStealthPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
InputComponent->BindAction("RMB", IE_Pressed, this, &AStealthPlayerController::OnRMBPressed);
InputComponent->BindAction("RMB", IE_Released, this, &AStealthPlayerController::OnRMBReleased);
}
void AStealthPlayerController::OnRMBPressed()
{
bOnRMB = true;
}
void AStealthPlayerController::OnRMBReleased()
{
bOnRMB = false;
}
void AStealthPlayerController::MoveHitmanToMouseCursor()
{
FHitResult HitResult;
if (GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility, false, HitResult))
{
FVector TargetLocation = HitResult.ImpactPoint;
check(Hitman && Hitman->GetController<AHitmanAIController>());
Hitman->GetController<AHitmanAIController>()->MoveToLocation(TargetLocation);
}
}
이제 StealthPlayerController.cpp
의 PlayerTick
하단에 다음 코드를 추가하고 실행하면 캐릭터가 마우스를 따라 움직인다.
if (bOnRMB)
{
MoveHitmanToMouseCursor();
}
/Character/Hitman.h
// Copyright 2021. Elysia-ff
#pragma once
#include "CoreMinimal.h"
#include "Character/StealthCharacter.h"
#include "Hitman.generated.h"
/**
*
*/
UCLASS()
class STEALTHTUTORIAL_API AHitman : public AStealthCharacter
{
GENERATED_BODY()
public:
AHitman(const FObjectInitializer& ObjectInitializer);
};
/Character/Hitman.cpp
// Copyright 2021. Elysia-ff
#include "Hitman.h"
#include "Character/Controller/HitmanAIController.h"
AHitman::AHitman(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
AIControllerClass = AHitmanAIController::StaticClass();
}
/Character/Controller/HitmanAIController.h
// Copyright 2021. Elysia-ff
#pragma once
#include "CoreMinimal.h"
#include "AIController.h"
#include "HitmanAIController.generated.h"
/**
*
*/
UCLASS()
class STEALTHTUTORIAL_API AHitmanAIController : public AAIController
{
GENERATED_BODY()
};
/Player/StealthPlayerController.h
// Copyright 2021. Elysia-ff
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "StealthPlayerController.generated.h"
class AHitman;
/**
*
*/
UCLASS()
class STEALTHTUTORIAL_API AStealthPlayerController : public APlayerController
{
GENERATED_BODY()
public:
AStealthPlayerController(const FObjectInitializer& ObjectInitializer);
virtual void PlayerTick(float DeltaTime) override;
protected:
virtual void BeginPlay() override;
virtual void SetupInputComponent() override;
private:
void OnRMBPressed();
void OnRMBReleased();
void MoveHitmanToMouseCursor();
private:
UPROPERTY()
UClass* HitmanBlueprint;
UPROPERTY()
AHitman* Hitman;
bool bOnRMB;
};
/Player/StealthPlayerController.cpp
// Copyright 2021. Elysia-ff
#include "StealthPlayerController.h"
#include "Character/Controller/HitmanAIController.h"
#include "Character/Hitman.h"
#include "Player/StealthPlayerCamera.h"
AStealthPlayerController::AStealthPlayerController(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = true;
bShowMouseCursor = true;
static ConstructorHelpers::FObjectFinder<UClass> HitmanObjectFinder(TEXT("Blueprint'/Game/Blueprint/Character/BP_Hitman.BP_Hitman_C'"));
check(HitmanObjectFinder.Succeeded());
HitmanBlueprint = HitmanObjectFinder.Object;
}
void AStealthPlayerController::PlayerTick(float DeltaTime)
{
Super::PlayerTick(DeltaTime);
AStealthPlayerCamera* PossessedPawn = GetPawn<AStealthPlayerCamera>();
if (PossessedPawn != nullptr && GEngine != nullptr)
{
FVector2D MouseInput;
if (GetMousePosition(MouseInput.X, MouseInput.Y))
{
FVector2D MoveInput;
const FIntPoint ViewportSize = GEngine->GameViewport->Viewport->GetSizeXY();
if (MouseInput.X <= PossessedPawn->EdgePixel)
{
MoveInput.Y = -1.0f;
}
else if (MouseInput.X >= ViewportSize.X - PossessedPawn->EdgePixel)
{
MoveInput.Y = 1.0f;
}
if (MouseInput.Y <= PossessedPawn->EdgePixel)
{
MoveInput.X = 1.0f;
}
else if (MouseInput.Y >= ViewportSize.Y - PossessedPawn->EdgePixel)
{
MoveInput.X = -1.0f;
}
if (!MoveInput.IsZero())
{
PossessedPawn->AddMoveInput(MoveInput);
}
}
}
if (bOnRMB)
{
MoveHitmanToMouseCursor();
}
}
void AStealthPlayerController::BeginPlay()
{
Super::BeginPlay();
check(HitmanBlueprint);
FActorSpawnParameters Param;
Param.Owner = this;
Param.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
Hitman = GetWorld()->SpawnActor<AHitman>(HitmanBlueprint, FVector(0.0f, 0.0f, 90.0f), FRotator::ZeroRotator, Param);
check(Hitman);
Hitman->SpawnDefaultController();
}
void AStealthPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
InputComponent->BindAction("RMB", IE_Pressed, this, &AStealthPlayerController::OnRMBPressed);
InputComponent->BindAction("RMB", IE_Released, this, &AStealthPlayerController::OnRMBReleased);
}
void AStealthPlayerController::OnRMBPressed()
{
bOnRMB = true;
}
void AStealthPlayerController::OnRMBReleased()
{
bOnRMB = false;
}
void AStealthPlayerController::MoveHitmanToMouseCursor()
{
FHitResult HitResult;
if (GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility, false, HitResult))
{
FVector TargetLocation = HitResult.ImpactPoint;
check(Hitman && Hitman->GetController<AHitmanAIController>());
Hitman->GetController<AHitmanAIController>()->MoveToLocation(TargetLocation);
}
}