P231112이라는 제목으로 C++타입빈프로젝트를 하나 만든다 .
프로젝트명Build.cs에 "EnhancedInput","Niagara" 를 추가하고 언리얼에디터, VS를 끄고 프로젝트실행파일 위를 우클릭후 VS솔루션을 다시만든후 리빌드해준다.
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore",
"EnhancedInput","Niagara" });
EnhancedInput방식이므로 InputAction과 InputContextMapping파일을 만든다.
만드는 법은 이곳을 참조하세요
2023.10.17 - [언리얼레퍼런스/게임플레이프레임워크] - UE5 Enhanced Input
TPSPlayer라는 클래스를 하나 만든다.
TPSPlayer.h 클래스명 앞에 프로젝트명이 붙었다. 나중에 복붙하실분들은 이걸 자신의 프로젝트명으로 바꾸던지 클래스 안쪽만 카피하시길 바란다.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputAction.h"
#include "TPSPlayer.generated.h"
class UInputMappingContext;
class UInputAction;
UCLASS()
class P231113_API ATPSPlayer : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ATPSPlayer();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
public:
UPROPERTY(VisibleAnywhere, Category = "Camera")
class USpringArmComponent* springArmComp;
UPROPERTY(VisibleAnywhere, Category = "Camera")
class UCameraComponent* cameraComp;
UPROPERTY(VisibleAnywhere, Category = "Fire")
class UStaticMeshComponent* weaponMeshComp;
UPROPERTY(EditAnywhere, Category = "FX")
class UNiagaraComponent* niagaraFX;
UPROPERTY(EditAnywhere, Category = "Input")
UInputMappingContext* PlayerMappingContext;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* MoveIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* LookUpIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* TurnIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* JumpIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* FireIA;
public:
void Move(const FInputActionValue& Value);
void LookUp(const FInputActionValue& Value);
void Turn(const FInputActionValue& Value);
void InputJump(const FInputActionValue& Value);
void InputFire(const FInputActionValue& Value);
public:
UPROPERTY(EditAnywhere, Category = "Move")
float moveSpeed;
UPROPERTY(EditAnywhere, Category = "Fire")
TSubclassOf<class APBullet> magazine; //총알오브젝리퍼런스
UPROPERTY(EditAnywhere, Category = "Animation")
UAnimMontage* attackAnimMontage; //공격애니메이션
private:
void Locomotion(); //이동 애니메이션
FVector moveDirection; //이동방향
bool fireReady; //총알준비상태
float fireTimerTime;
public:
UPROPERTY(EditAnywhere, Category = "Fire")
float fireCoolTime;
protected:
void FireCoolTimer(float Duration, float deltaTime);
public:
void SpawnBullet(); //총알 발사
void ShowFX(); //Niagara를 보여주는 효과
};
PBullet.h를 참조하므로 아직 컴파일하며 안된다.
나이아가라FX는 아직 만들지 않았으므로 참조를 막아두었다. 널포인트 체크를 안해 이대로 실행하면 에러가 난다.
TPSPlayer.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "TPSPlayer.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
#include "NiagaraComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "PBullet.h"
// Sets default values
ATPSPlayer::ATPSPlayer()
{
// 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;
// ConstructorHelpers 라는 유틸리티로 에셋 가져오기(찾기)
ConstructorHelpers::FObjectFinder<USkeletalMesh> initMesh(TEXT("/Script/Engine.SkeletalMesh'/Game/MyResource/unitychan.unitychan'"));
if (initMesh.Succeeded()) //제대로 오브젝트를 가져왔다면 ~
{
GetMesh()->SetSkeletalMesh(initMesh.Object);
//Relative - > 상대적 위치값, 회전값
GetMesh()->SetRelativeLocationAndRotation(FVector(0, 0, -88), FRotator(0, -90, 0));
}
//springArm 생성 - 초기화
springArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComp"));
springArmComp->SetupAttachment(RootComponent);
springArmComp->SetRelativeLocationAndRotation(FVector(0, 0, 50), FRotator(-20, 0, 0));
springArmComp->TargetArmLength = 530;
springArmComp->bUsePawnControlRotation = true;
//카메라 생성 - 초기화
cameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
cameraComp->SetupAttachment(springArmComp);
cameraComp->bUsePawnControlRotation = false;
bUseControllerRotationYaw = true;
//moveSpeed = 100;
//메쉬컴포넌트 생성
weaponMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("WeaponMesh"));
//캐릭터 메쉬에 부착
weaponMeshComp->SetupAttachment(GetMesh(), FName("Character1_RightHandSocket"));
fireCoolTime = 1.85f;
fireTimerTime = 0;
fireReady = true;
}
// Called when the game starts or when spawned
void ATPSPlayer::BeginPlay()
{
Super::BeginPlay();
if (APlayerController* PlayerController = Cast<APlayerController>(GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem
= ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(PlayerMappingContext, 0);
}
}
//niagaraFX = GetComponentByClass<UNiagaraComponent>();
//niagaraFX->SetVisibility(false);
}
// Called every frame
void ATPSPlayer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
Locomotion();
if (!fireReady)
{
FireCoolTimer(fireCoolTime, DeltaTime);
}
}
// Called to bind functionality to input
void ATPSPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
//입력 바인딩
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
{
EnhancedInputComponent->BindAction(MoveIA, ETriggerEvent::Triggered, this, &ATPSPlayer::Move);
EnhancedInputComponent->BindAction(LookUpIA, ETriggerEvent::Triggered, this, &ATPSPlayer::LookUp);
EnhancedInputComponent->BindAction(TurnIA, ETriggerEvent::Triggered, this, &ATPSPlayer::Turn);
EnhancedInputComponent->BindAction(JumpIA, ETriggerEvent::Triggered, this, &ATPSPlayer::InputJump);
EnhancedInputComponent->BindAction(FireIA, ETriggerEvent::Triggered, this, &ATPSPlayer::InputFire);
}
}
void ATPSPlayer::Move(const FInputActionValue& Value)
{
const FVector _currentValue = Value.Get<FVector>();
if (Controller)
{
moveDirection.Y = _currentValue.X;
moveDirection.X = _currentValue.Y;
}
}
void ATPSPlayer::LookUp(const FInputActionValue& Value)
{
//mouse y - 한 축의 값 (float)
const float _currentValue = Value.Get<float>();
AddControllerPitchInput(_currentValue);
}
void ATPSPlayer::Turn(const FInputActionValue& Value)
{
//mouse x - 한 축의 값 (float)
const float _currentValue = Value.Get<float>();
AddControllerYawInput(_currentValue);
}
void ATPSPlayer::InputJump(const FInputActionValue& Value)
{
Jump();
}
void ATPSPlayer::InputFire(const FInputActionValue& Value)
{
if (fireReady)
{
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance)
{
AnimInstance->Montage_Play(attackAnimMontage);
}
fireReady = false;
}
}
void ATPSPlayer::Locomotion()
{
//이동방향을 컨트롤 방향 기준으로 변환
moveDirection = FTransform(GetControlRotation()).TransformVector(moveDirection);
/*
//플레이어 이동 - 등속운동
FVector P0 = GetActorLocation(); //현재위치
FVector vt = moveDirection * moveSpeed * DeltaTime; //이동거리
FVector P = P0 + vt;
SetActorLocation(P);
*/
AddMovementInput(moveDirection);
//방향 초기화
moveDirection = FVector::ZeroVector; //ZeroVector; == FVector(0,0,0)
}
void ATPSPlayer::FireCoolTimer(float Duration, float deltaTime)
{
if (fireTimerTime < Duration)
{
fireTimerTime += deltaTime;
}
else
{
fireTimerTime = 0;
fireReady = true;
}
}
void ATPSPlayer::SpawnBullet()
{
FTransform firePostion = weaponMeshComp->GetSocketTransform(TEXT("FirePostion"));
GetWorld()->SpawnActor<APBullet>(magazine, firePostion);
}
void ATPSPlayer::ShowFX()
{
if (niagaraFX == nullptr)
{
niagaraFX = GetComponentByClass<UNiagaraComponent>();
}
bool show = GetCharacterMovement()->IsFalling();
//niagaraFX->SetVisibility(show);
GetMesh()->SetVisibility(!show);
}
'언리얼엔진 > ThirdPersonTemplete' 카테고리의 다른 글
스폰한 캐릭터 안움직이는 이유 (0) | 2023.12.04 |
---|---|
AnimNotify (0) | 2023.11.16 |
언리얼 Animation Montage (0) | 2023.11.14 |
캐릭터 메시 지정하기 (0) | 2023.11.13 |
PBullet 발사체 만들기 (1) | 2023.11.13 |