[2일차] 직접 TPS 캐릭터 만들어보기

칼든개구리·2024년 12월 4일
0

[언리얼TO리얼]

목록 보기
6/42

오늘은~~ 직접 TPS 캐릭터를 만들어보는 시간을 가지도록 하겠습니다
1. 먼저 c++하나를 MyCharacter 이름으로 만들어 줍니다. 해당 클래스는 나와 적을 만들때 사용하는 클래스이기도 합니다!

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"

UCLASS()
class BASIS_API AMyCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AMyCharacter();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
public:
	virtual void Attack(); //상속 받는 자식이 다르게 때릴 수 있게 virtual 적어준다
	virtual void Hit(int32 Damage);
	virtual void IncreaseKillCount();


public:
	UPROPERTY(EditAnywhere)
	int32 FullHP;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
	int32 AttackCount;
	UPROPERTY(EditAnywhere)
	int32 Strength;

private:

	int32 CurrentHP;
	int32 KillCount;

};

MyCharacter.h 파일의 내용입니다
가장 먼저 변수들을 선언 했는데, int값은 처리하는 값이 달라질 수 있으므로 int32를 사용해 선언하였습니다.
FullHP, AttackCount, Strength는 UPROPERTY로 처리해주었고 나머지는 private에 CurrentHP, KillCount를 선언해주었습니다.
다음은 함수를 3개 선언 해주었는데요, MyCharacter에서 나와 적을 상속하여, 같은 함수들을 다르게 처리하기 위해 virtual로 처리하였습니다.

MyCharacter.cpp 파일의 내용입니다

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyCharacter.h"

// Sets default values
AMyCharacter::AMyCharacter()
{
 	// 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; // tick 함수가 매 프래임 화면에 나타날지
	FullHP = 100;
	Strength = 10;
	KillCount = 0;
}

// Called when the game starts or when spawned
void AMyCharacter::BeginPlay()
{
	Super::BeginPlay();
	SpawnDefaultController(); //캐릭터 생성 시 그에 맞는 컨트롤러를 자동으로 인식시킨다
	CurrentHP = FullHP;
	KillCount = 0;
}

void AMyCharacter::Attack()
{
	AttackCount++;
}

void AMyCharacter::Hit(int32 Damage)
{
	CurrentHP -= Damage;
	if (CurrentHP < 0)
	{
		CurrentHP = 0;
	}
}

void AMyCharacter::IncreaseKillCount()
{
	KillCount++;

}

생성자 부분에서 캐릭터 생성 할 때 그에 맞는 컨트롤러를 자동으로 인식시켜주는 SpawnDefaultController() 함수를 사용하고, 각각의 변수들을 초기화 하였습니다.
Attack() 함수는 기본적으로 AttackCount 값만 증가시키게 해두었고 , Hit()함수에서는 맞았을 때 현재 hp에서 맞은 damage 만큼 줄이고, 만약 현재 hp가 0보다 작으면 0으로 값을 설정하였습니다.
IncreaseKillCount()함수 또한 KillCount 값만 증가하도록설정하였습니다.


플레이어를 만들기 위해서 새 c++ 클래스 만들기 -> 이전에 만든 MyCharacter을 부모로 선택합니다.
PlyerBase로 이름을 짓고, 해당 헤더 파일의 내용입니다

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "MyCharacter.h"
#include "PlayerBase.generated.h"

class UInputAction;
struct FInputActionValue;

UCLASS()
class BASIS_API APlayerBase : public AMyCharacter
{
	GENERATED_BODY()

public:
	APlayerBase();
	virtual void BeginPlay() override;
	virtual void Hit(int32 Damage, AActor& Bywho) override;
	virtual void IncreaseKillCount() override;
	virtual void Attack() override;
private:
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<class USpringArmComponent> CameraBoom;//USpringArmComponent의 전방선언, TObjectPtr은 언리얼이 USpringArmConponent * a 를 TObjectPtr<USpringArmComponent>로 쓰기를 권하고 있음
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<class USpringArmComponent> CameraFollow;
	UPROPERTY(EditAnywhere)
	TObjectPtr<UInputAction> MoveAction;
	UPROPERTY(EditAnywhere)
	TObjectPtr<UInputAction> ZoomAction;
	UPROPERTY(EditAnywhere)
	TObjectPtr<UInputAction> LookAction;
	UPROPERTY(EditAnywhere)
	TObjectPtr<UInputAction> FireAction;

	//움직임,보기,발사 줌에 대해 입력값이 들어왔을 때 처리 
	void Move(const FInputActionValue& Value);
	void Look(const FInputActionValue& Value);
	void Fire(const FInputActionValue& Value);
	void Zoom(const FInputActionValue& Value);
};

다음은 PlayerBase.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "PlayerBase.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "EnhancedInputComponent.h"

APlayerBase::APlayerBase()
{
	//컴포넌트들의 배치
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);

	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom);

}

void APlayerBase::BeginPlay()
{
	Super::BeginPlay(); //상속받는 것이니 super로 처리해줘야함

}

void APlayerBase::Hit(int32 Damage, AActor& Bywho)
{
	Super::Hit(Damage, Bywho);
	if (CurrentHP > 0)
	{
		return;
	}
	Destroy();
}

void APlayerBase::IncreaseKillCount()
{
	Super::IncreaseKillCount();
}

void APlayerBase::Attack()

{
	Super::Attack();
	//Todo: 무기 완료 후 작성
}

void APlayerBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
	{
		EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &APlayerBase::Move);
		EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &APlayerBase::Look);
		EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Started, this, &APlayerBase::Fire);
		EnhancedInputComponent->BindAction(ZoomAction, ETriggerEvent::Triggered, this, &APlayerBase::Zoom);
	}
}

void APlayerBase::Move(const FInputActionValue& Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();

	if (Controller != nullptr)
	{
		AddMovementInput(GetActorForwardVector(), MovementVector.Y);
		AddMovementInput(GetActorRightVector(), MovementVector.X);
	}
}

void APlayerBase::Look(const FInputActionValue& Value)
{
	FVector2D LookAxisVector = Value.Get<FVector2D>();
	if (Controller != nullptr)
	{
		AddControllerYawInput(LookAxisVector.X);
		AddControllerYawInput(LookAxisVector.Y);

	}
}

void APlayerBase::Fire(const FInputActionValue& Value)
{
	//무기 완성 후 작성
}

void APlayerBase::Zoom(const FInputActionValue& Value)
{
	if(!IsValid(CameraBoom)) //IsValid: 널 포인터인지 삭제될 건지 진짜 존재하는지 체크하는 용도
	{
		return;
	}
	if (Value.Get<bool>())
	{
		CameraBoom->TargetArmLength = 40;
		CameraBoom->SocketOffset = FVector(0, 40, 60);

	}
	else
	{
		CameraBoom->TargetArmLength = 120;
		CameraBoom->SocketOffset = FVector(0, 60, 60);
	}
}

cpp코드는 1인칭 코드 볼 때 나오는 친구들 다시 나온 것 같은데 다시 봐도 어렵다 무슨말일가..
1인칭 코드 메모를 다시 봐야겠다!

다음은 총과 총알을 만들어 본다.

profile
메타쏭이

0개의 댓글