일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- frequency-domain spectrum analysis
- linear difference equation
- MAC
- 운영체제
- 게임개발
- 메카님
- Double free
- DP
- Race condition
- CTF
- AINCAA
- Unity #Indie Game
- dirty cow
- 배경 그림
- Security
- 언리얼 엔진
- TSet
- 유니티
- 언리얼엔진
- STCF
- 유스케이스
- DSP
- ret2libc
- MLFQ
- Rr
- stride
- dtft
- pdlc
- sampling theory
- 게임 개발
- Today
- Total
다양한 기록
[UE Game Framework] #10 Game Data Management 본문
엑셀 csv로 바꾸면 언리얼에서 임포트 가능
같은 이름을 가지는 구조체 필요
액셀 데이터의 임포트
- DataAsset과 유사하게 FTableRowBase를 상속받은 구조체를 선언
- 액셀의 Name 컬럼을 제외한 컬럼과 동일하게 UPROPERTY 속성을 선언
* 엑셀에 Name이라는게 존재는 해야 하는데, 이게 키값이 되기 때문
- 엑셀 데이터를 csv로 익스포트 한 후 언리얼 엔진에 임포트
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "ABCharacterStat.generated.h"
USTRUCT(BlueprintType)
struct FABCharacterStat : public FTableRowBase
{
GENERATED_BODY()
public:
FABCharacterStat() : MaxHp(0.0f), Attack(0.0f), AttackRange(0.0f), AttackSpeed(0.0f), MovementSpeed(0.0f) {}
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stat)
float MaxHp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stat)
float Attack;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stat)
float AttackRange;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stat)
float AttackSpeed;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Stat)
float MovementSpeed;
FABCharacterStat operator+(const FABCharacterStat& Other) const
{
const float* const ThisPtr = reinterpret_cast<const float* const>(this);
const float* const OtherPtr = reinterpret_cast<const float* const>(&Other);
FABCharacterStat Result;
float* ResultPtr = reinterpret_cast<float*>(&Result);
int32 StatNum = sizeof(FABCharacterStat) / sizeof(float);
for (int32 i = 0; i < StatNum; i++)
{
ResultPtr[i] = ThisPtr[i] + OtherPtr[i];
}
return Result;
}
};
ABCharacterStat.h
그냥 전부 float로 해주기
위에서 선언한 구조체로 데이터 테이블 만들고
리임포트로 받아올 수 있음
데이터를 관리할 싱글톤 클래스의 설정
언리얼 엔진에서 제공하는 싱글톤 클래스
- 게임 인스턴스
- 애셋 매니저
- 게임 플레이 관련 액터 (게임 모드, 게임 스테이트)
- 프로젝트에 싱글톤으로 등록한 언리얼 오브젝트
* 언리얼 오브젝트 생성자에서 사용하지 않도록 주의
* 게임 인스턴스는 보통 어플리케이션의 데이터를 관리하는 용도
하나 만들어서 쓸 거임
만들어서
프로젝트 세팅 들어가서 등록해줌
그 후 에디터 재시작
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "ABCharacterStat.h"
#include "ABGameSingleton.generated.h"
DECLARE_LOG_CATEGORY_EXTERN(LogABGameSingleton, Error, All);
/**
*
*/
UCLASS()
class ARENABATTLE_API UABGameSingleton : public UObject
{
GENERATED_BODY()
public:
UABGameSingleton();
static UABGameSingleton& Get();
// Character Set Data
public:
FORCEINLINE FABCharacterStat GetCharacterStat(int32 InLevel) const
{
return CharacterStatTable.IsValidIndex(InLevel) ? CharacterStatTable[InLevel] : FABCharacterStat();
}
UPROPERTY()
int32 CharacterMaxLevel;
private:
TArray<FABCharacterStat> CharacterStatTable;
};
헤더
캐릭터 스탯 테이블에 값을 옮겨받을 거임
그리고 레벨에 따른 스탯을 받는 기능이 있음
// Fill out your copyright notice in the Description page of Project Settings.
#include "GameData/ABGameSingleton.h"
DEFINE_LOG_CATEGORY(LogABGameSingleton);
UABGameSingleton::UABGameSingleton()
{
static ConstructorHelpers::FObjectFinder<UDataTable> DataTableRef(TEXT("/Script/Engine.DataTable'/Game/ArenaBattle/GameData/ABCharacterStatTable.ABCharacterStatTable'"));
if (nullptr != DataTableRef.Object)
{
const UDataTable* DataTable = DataTableRef.Object;
check(DataTable->GetRowMap().Num() > 0);
TArray<uint8*> ValueArray;
DataTable->GetRowMap().GenerateValueArray(ValueArray);
Algo::Transform(ValueArray, CharacterStatTable,
[](uint8* Value)
{
return *reinterpret_cast<FABCharacterStat*>(Value);
}
);
}
CharacterMaxLevel = CharacterStatTable.Num();
ensure(CharacterMaxLevel > 0);
}
UABGameSingleton& UABGameSingleton::Get()
{
UABGameSingleton* Singleton = CastChecked<UABGameSingleton>(GEngine->GameSingleton);
if (Singleton)
{
return *Singleton;
}
UE_LOG(LogABGameSingleton, Error, TEXT("Invalid Game Singleton"));
return *NewObject<UABGameSingleton>();
}
Get은 그냥 싱글톤 가져와서 리턴하는 함수
데이터 테이블에서 데이터 들고오는 코드
uint8* -> Value의 시작 주소임
그거를 기준으로 구조체에 집어넣으면 알아서 들어감 (reinterpret_cast)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameData/ABCharacterStat.h"
#include "ABCharacterStatComponent.generated.h"
DECLARE_MULTICAST_DELEGATE(FOnHpZeroDelegate);
DECLARE_MULTICAST_DELEGATE_OneParam(FOnHpChangedDelegate, float /*CurrentHp*/);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ARENABATTLE_API UABCharacterStatComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UABCharacterStatComponent();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
FOnHpZeroDelegate OnHpZero;
FOnHpChangedDelegate OnHpChanged;
void SetLevelStat(int32 InNewLevel);
FORCEINLINE float GetCurrentLevel() const { return CurrentLevel; }
FORCEINLINE void SetModifierStat(const FABCharacterStat& InModifierStat) { ModifierStat = InModifierStat; }
FORCEINLINE float GetCurrentHp() const { return CurrentHp; }
FORCEINLINE FABCharacterStat GetTotalStat() const { return (BaseStat + ModifierStat); }
float ApplyDamage(float InDamage);
protected:
void SetHp(float NewHp);
UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat)
float CurrentHp;
UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat)
float CurrentLevel;
UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat, Meta = (AllowPrivateAccess = "true"))
FABCharacterStat BaseStat;
UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat, Meta = (AllowPrivateAccess = "true"))
FABCharacterStat ModifierStat;
};
캐릭터 스탯 컴포넌트 헤더
베이스 스탯이랑 변경 스탯을 가짐
// Fill out your copyright notice in the Description page of Project Settings.
#include "CharacterStat/ABCharacterStatComponent.h"
#include "GameData/ABGameSingleton.h"
// Sets default values for this component's properties
UABCharacterStatComponent::UABCharacterStatComponent()
{
CurrentLevel = 1;
}
// Called when the game starts
void UABCharacterStatComponent::BeginPlay()
{
Super::BeginPlay();
SetLevelStat(CurrentLevel);
SetHp(BaseStat.MaxHp);
}
void UABCharacterStatComponent::SetLevelStat(int32 InNewLevel)
{
CurrentLevel = FMath::Clamp(InNewLevel, 1, UABGameSingleton::Get().CharacterMaxLevel);
BaseStat = UABGameSingleton::Get().GetCharacterStat(CurrentLevel);
check(BaseStat.MaxHp > 0.0f);
}
float UABCharacterStatComponent::ApplyDamage(float InDamage)
{
const float PrevHp = CurrentHp;
const float ActualDamage = FMath::Clamp(InDamage, 0.0f, InDamage);
SetHp(PrevHp - ActualDamage);
if ( CurrentHp < KINDA_SMALL_NUMBER )
{
OnHpZero.Broadcast();
}
return ActualDamage;
}
void UABCharacterStatComponent::SetHp(float NewHp)
{
CurrentHp = FMath::Clamp(NewHp, 0.0f, BaseStat.MaxHp);
OnHpChanged.Broadcast(CurrentHp);
}
싱글톤에서 스탯 가져와서 적용시키는 컴포넌트임
캐릭터에서 스탯 컴포넌트에서 뽑아서 사용
이제 스테이지 클리어 시 NPC 레벨이 올라가도록 할 것
기믹 건드려야 함
* OnGateTriggerBeginOverlap 내부
플레이어에 레벨 설정 넣어주고
액터 스폰할 때 레벨 설정해주기
근데 CurrentHp가 제대로 설정되지 않았음
이유
SpawnActor로 액터 생성 시
액터와 액터의 모든 컴포넌트의 BeginPlay 함수가 바로 호출됨
컴포넌트 코드에서 BeginPlay를 보면 SpawnActor가 수행되자마자 SelLevelStat과 SetHp 함수가 호출되는데,
이러면 Hp는 1레벨 만큼 차오름
그 이후 SetLevel을 해봤자 Hp 설정은 이후에 이루어짐
유니티도 마찬가지이긴 한데, 언리얼은 이런 문제 해결을 위해 SpawnActorDefferred 제공 (지연 생성)
마지막에 FinishSpawning 함수를 호출해여 BeginPlay 호출됨
이렇게 해주면 됨
클래스 정보는 필수로 저장해줘야 함
** PostInitializeComponents도 Finishing 이후임
보상 상자 등등 이렇게 설정해줌
이제 무기에다 스탯 넣어주기
아이템에 스탯이 추가됨
공격력 100, 범위 60으로 설정
장착 시 스탯 변화 설정
강해지고 거리 늘어난 것 확인 가능
다음은 NPC가 다른 캐릭터로 스폰되도록 하기
ABCharacterNonPlayer에 NPCMeshes가 선언되어 있으면 경로 따라가서 추가함
Config에 ArenaBattle 설정하면 DefaultArenaBattle.ini 불러 쓰겠다는 의미
속성에 Config 설정하면 해당 설정 이용하겠다는 의미
프로젝트가 로딩될 때 자동으로 값들이 채워지는데, 비동기적으로 처리하고 싶음
* 추가 예정
'언리얼 엔진 > Unreal Game Framework' 카테고리의 다른 글
[UE Game Framework] #9 Infinity Map (0) | 2025.01.06 |
---|---|
[UE Game Framework] #8 Item System (0) | 2025.01.06 |
[UE Game Framework] #7 Character Stat & Widget (0) | 2025.01.05 |
[UE Game Framework] #6 Character Attack Hit Check (0) | 2025.01.05 |
[UE Game Framework] #5 Character Combo Action (0) | 2025.01.04 |