계속 빌드하다보면, 연결해놨던 것들이 (ex. Move, Rotation 등)깨진다
이런 점을 개선하기 위해, 정보도 하나의 에셋(리소스화시킴)으로서 활용되게 한다.
사용할 액션의 종류들을 묶어서 에셋화
global.h
#pragma once
// 자주 사용하는 헤더 배치
#include "EngineMinimal.h"
#include "enum.h"
#include "struct.h"
enum.h
#pragma once
// 게임 개발에 필요한 enum 값 정리
// 언리얼에서 사용하는 규칙이 있음
// enum은 앞에다 E, 구조체는 F, action으로 만들어진것은 A 를 붙여야한다
// 액션 하나에 이넘 타입 하나씩 대응
UENUM(BlueprintType)
enum class EInputActionType : uint8
{
MOVE,
ROTATION,
JUMP,
SPRINT_TOGGLE,
ATTACK,
FIRE,
RELOAD,
};
struct.h 생성
#pragma once
// enum 값 타입에 대응하는 action 하나씩 구조체로 만들어서 배열에 저장하여 셋팅
#include "enum.h"
// input 액션의 타입을 알아야한다
#include "InputAction.h"
// 매크로
// 항상 제일 밑에 있어야 한다
#include "struct.generated.h"
USTRUCT(Atomic, BlueprintType)
struct FIAData
{
// 매크로
// 기본 구현들이 추가된다
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
EInputActionType Type;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSoftObjectPtr<UInputAction> Action;
};
* 한글 나오게 하는 방법
제어판 -> 국가 또는 지역 -> 관리자 옵션 -> 시스템 로캘 변경
* 데이터 에셋 만들기
c++ 클래스 -> system -> DataAsset 을 상속받는 IADataAsset 생성
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "../Header/global.h"
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "IADataAsset.generated.h"
/**
*
*/
UCLASS()
class UNREAL_3TH_API UIADataAsset : public UDataAsset
{
GENERATED_BODY()
public:
// EditDefaultOnly -> 에셋 페이지에서만 수정
// DisplayName -> 변수 설명정보
UPROPERTY(EditDefaultsOnly, Category = "Input", meta = (DisplayName = "InputAction 세팅"))
TArray<FIAData> IADataArr;
};
Input -> 기타 -> 데이터 에셋 -> DA_PlayerSetting
* 오전 시간에 한 것 개념 정리
1. enum 값 추가
-> 타입 하나하나가 실제 인풋 액션과 연결을 시키려고 enum 을 여러 종류 추가
2. struct
-> 구조체 하나 생성
3. IADataAsset
-> 구조체를 여러 가지 가질 수 있는 동적배열
4. Character_Base 에서 바인딩 코드 개선
ACharacter_Base.h
#pragma once
#include "../Header/global.h"
#include "InputMappingContext.h"
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "../System/IADataAsset.h"
#include "Character_Base.generated.h"
UCLASS()
class UNREAL_3TH_API ACharacter_Base : public ACharacter
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
UCameraComponent* m_Cam;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
USpringArmComponent* m_Arm;
private:
UPROPERTY(EditAnywhere, Category = "Input")
TSoftObjectPtr<UInputMappingContext> InputMapping;
UPROPERTY(EditAnywhere, Category = "Input")
TSoftObjectPtr<UIADataAsset> InputActionSetting;
public:
// Sets default values for this character's properties
ACharacter_Base();
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;
private:
void Move(const FInputActionInstance& _Instance);
void Rotation(const FInputActionInstance& _Instance);
void SprintToggle(const FInputActionInstance& _Instance);
void Jump(const FInputActionInstance& _Instance);
};
ACharacter_Base.cpp
// 컨트롤러가 빙의할때, 컨트롤러의 인풋 컴포넌트를 인자로 넣어주면서 빙의대상 액터에게 호출해주는 함수
void ACharacter_Base::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
UEnhancedInputComponent* InputCom = Cast<UEnhancedInputComponent>(PlayerInputComponent);
if (nullptr == InputCom)
return;
// null 이 아니다 => 로딩은 안되어 있지만 경로는 문제 없다
if (!InputActionSetting.IsNull())
{
// 로딩 되어있으면 된 것을 주고, 아니면 로딩해라
UIADataAsset* pDA = InputActionSetting.LoadSynchronous();
// 배열 형태로
for (int32 i = 0; i < pDA->IADataArr.Num(); ++i)
{
switch (pDA->IADataArr[i].Type)
{
case EInputActionType::MOVE:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Move);
break;
case EInputActionType::ROTATION:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Rotation);
break;
case EInputActionType::JUMP:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Jump);
break;
case EInputActionType::SPRINT_TOGGLE:
InputCom->BindAction(pDA->IADataArr[i].Action.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::SprintToggle);
break;
case EInputActionType::ATTACK:
break;
case EInputActionType::FIRE:
break;
case EInputActionType::RELOAD:
break;
default:
break;
}
}
}
}
1. 왼쪽 클릭을 했을 때, 총을 쏘는 애니메이션
class UNREAL_3TH_API ACharacter_Base : public ACharacter
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
bool IsFire;
protected:
UPROPERTY(EditAnywhere, Category = "Animation")
TSoftObjectPtr<UAnimMontage> FireMontage;
private:
void Fire(const FInputActionInstance& _Instance);
}
ACharacter_Base::ACharacter_Base()
: m_Cam(nullptr)
, m_Arm(nullptr)
, IsFire(false)
{
// 발사 몽타주를 찾아서 참조한다.
ConstructorHelpers::FObjectFinder<UAnimMontage> montage(TEXT("/Script/Engine.AnimMontage'/Game/BlueprintClass/Player/Animation/AM_Fire.AM_Fire'"));
if (montage.Succeeded())
{
FireMontage = montage.Object;
}
}
void ACharacter_Base::Fire(const FInputActionInstance& _Instance)
{
// 기본 C++ 매크로 구문
//__FUNCTION__; // 1 바이트
// 몇번째 라인인지
//__LINE__;
// 2byte 로 관리
//FString str = FString::Printf(TEXT("%s : {#d} : %s"), *FString(__FUNCTION__), __LINE__,TEXT("Fire!!"));
// 오퍼레이터 앞에 * 을 붙여주면,
// UE_LOG : 가변 매크로
//UE_LOG(Player, Log, TEXT("%s", *str));
bool bToggle = _Instance.GetValue().Get<bool>();
LOG(Player, Error, TEXT("!! Fire !!"));
if (!IsValid(GetMesh()->GetAnimInstance()) || FireMontage.IsNull())
{
return;
}
if (bToggle)
{
GetMesh()->GetAnimInstance()->Montage_Play(FireMontage.LoadSynchronous());
IsFire = true;
}
else
{
GetMesh()->GetAnimInstance()->Montage_Stop(0.3f, FireMontage.LoadSynchronous());
IsFire = false;
}
}
class UNREAL_3TH_API UAnimInstance_Base : public UAnimInstance
{
GENERATED_BODY()
public:
UPROPERTY(Editanywhere, BlueprintReadWrite, Category = "데이터")
bool IsFire;
UPROPERTY(Editanywhere, BlueprintReadWrite, Category = "데이터")
float FireBlendWeight;
}
void UAnimInstance_Base::NativeUpdateAnimation(float _fDeltaTime)
{
// 캐릭터가 총을 쏘는지 확인
IsFire = Character->IsFire;
if (IsFire)
{
FireBlendWeight = 1.f;
}
else
{
FireBlendWeight = 0.f;
}
}
define.h 에 매크로 구현
#pragma once
//Verbosity 로그 수준
#define LOG(Category, Verbosity, String) UE_LOG(Category, Verbosity, \
TEXT("%s"), *FString::Printf(TEXT("%s : {%d} : %s"), \
*FString(__FUNCTION__), __LINE__, String));
1-1 총쏘면서 움직이는 애니메이션
* 걷다가 총쏘는 애니메이션으로 교체될 때 끊기는 현상 개선
ABP_Player_C
class UNREAL_3TH_API ACharacter_Base : public ACharacter
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
bool IsFire;
}
//////////////////////////////////////////////////////////////////////////////////////////
class UNREAL_3TH_API UAnimInstance_Base : public UAnimInstance
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
bool IsFire;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Component")
float FireBlendWeight;
}
* 총쏘는 모션을 하다가 땠을 때 ( 총 쏘는 모션 -> 걷거나 일반 모션으로 변경) 끊기는 현상 개선
=> visual studio 에서 강제로
2. 커스텀 카테고리 만들기 (define.h / define.cpp 생성)
define.h
// 나만의 커스텀 카테고리 추가를 위해 매크로구문 선언
DECLARE_LOG_CATEGORY_EXTERN(Player, Log, All);
define.cpp
#include "define.h"
// 만든 카테고리 선언
DEFINE_LOG_CATEGORY(Player);
3. 애니메이션 몽타주
-> 섹션을 나눠서 관리가 가능하다
-> 조합을 해서 섞어주는 역할
3-1 몽타주의 슬롯
3-2 ABP_Player_C -> 본 별로 레이어드 블렌딩
Blend Weights => 가중치
아래거는 영향을 0 받게 된다.
디테일 -> 레이어 설정 -> 인덱스 -> 본이름 추가
디테일 -> 레이어 설정 -> 메시 스페이스 회전 블렌드 true 로 변경 ==> 고유의 회전값을 사용하겠다는 의미
'언리얼 5' 카테고리의 다른 글
230906 Effect_Base 구조 변경 / EffectMgr 싱글톤 / 투사체 생성 (0) | 2023.09.11 |
---|---|
230905 애니메이션, 리로드 노티파이 / 파티클 이펙트 / Effect_Base (0) | 2023.09.09 |
230901 (0) | 2023.09.01 |
230831 애니메이션 스테이트 머신 / 지금까지 한거 블루프린트 대신 c++ 로 작업해보기 (0) | 2023.08.31 |
230830 회전 블루프린트 / 애니메이션 (0) | 2023.08.30 |