728x90
반응형
- 정리
- 게임플로우의 마무리
- 죽는 상태에 대한 플레이어와 NPC의 설정
- 전체 게임 구성 요소의 이해
- 캐릭터 데이터 조정과 다양한 아이템 설정 및 구현
- 게임플로우의 마무리
- 세 개의 레이어를 기준으로 게임을 구성하는 다양한 기능의 구현
- 효과적으로 관리하기 위해 정한 규칙
- 상위 레이어에 있는 객체들은 하위 레이어에 있는 객체들을 자유롭게 참조 가능
- 하위 레이어에 있는 객체들은 상위 레이어에 있는 객체들을 참고하기 위해서는 인터페이스를 거치도록 설정
- 게임 플로우를 위해 보강할 내용
- 죽었을 때의 NPC와 플레이어의 처리
- 이동 속도의 적용
- 포션/스크롤 아이템의 추가 구현과 캐릭터의 적용
- 스탯 기능 및 UI의 기능의 보강
- 죽었을 때의 NPC와 플레이어의 처리
// 죽었을 때
void AABCharacterNonPlayer::SetDead()
{
Super::SetDead();
// 죽으면 AI를 중단시켜준다.
AABAIController* ABAIController = Cast<AABAIController>(GetController());
if (ABAIController)
{
ABAIController->StopAI();
}
FTimerHandle DeadTimerHandle;
GetWorld()->GetTimerManager().SetTimer(DeadTimerHandle, FTimerDelegate::CreateLambda(
[&]()
{
Destroy();
}
), DeadEventDelayTime, false);
}
- ABCharacterNonPlayer.cpp
- NPC가 죽었을 때는 ABAIController에 있는 StopAI함수를 호출해주도록 SetDead함수를 수정해준다.
// Player가 죽었을때 동작하는 함수
virtual void SetDead() override;
- ABCharacterPlayer.h
void AABCharacterPlayer::BeginPlay()
{
Super::BeginPlay();
// 입력을 켜주는 기능 추가
APlayerController* PlayerController = Cast<APlayerController>(GetController());
if (PlayerController)
{
EnableInput(PlayerController);
}
SetChangeCharacterControl(CurrentCharacterControlType);
}
// 죽었을 때 (ABCharacterBase)
// 죽었으니 움직임 제한시켜주면서 죽는 애니메이션 재생 + 콜리전 기능 제한 등의 기능이 구현되어 있다.
void AABCharacterPlayer::SetDead()
{
Super::SetDead();
// + 입력을 끄는 기능 추가
APlayerController* PlayerController = Cast<APlayerController>(GetController());
if (PlayerController)
{
DisableInput(PlayerController);
}
}
- ABCharacterPlayer.cpp
- 플레이어의 경우 SetDead 함수가 없었기 때문에 추가로 오버라이드 해주고, 죽게 되면 입력을 끄는 기능을 추가해준다.
- 추가 안전장치 기능으로 BeginPlay가 실행될 때 입력을 받는 기능을 추가해주도록 하자.
- 포션/스크롤 아이템의 추가 구현과 캐릭터의 적용 + 이동 속도의 적용
#pragma once
#include "ABWeaponItemData.h"
#include "ABScrollItemData.h"
#include "ABPotionItemData.h"
- ABItems.h
- ABItemData들을 관리하기 쉽게 다음과 같은 헤더파일을 만들어주고, ItemData가 필요한 곳에 헤더파일을 추가해주자.
- 기존에는 Weapon만 구현을 했는데, Potion과 Scroll도 함께 구현해주자.
- 앞으로 ItemData들을 추가할 때는 ABItems.h를 추가해서 구현할 수 있도록
// 생성자 ...
// UPrimaryDataAsset 내부의 생성될 에셋의 아이디를 직접 지정해줄 수 있는 GetPrimaryAssetId() 함수를 오버라이드
FPrimaryAssetId GetPrimaryAssetId() const override
{
// 두가지 정보를 바탕으로 유일한 식별자 아이디값을 만들어 낼 수 있다.
return FPrimaryAssetId("ABItemData", GetFName());
}
- ItemData.cpp
- IteamData에 공통적으로 GetPrimaryAssetId()와 생성자를 구현해준다. 생성자에서는 Item의 Type을 설정하도록 하고, GetPrimaryAssetId()을 통해 에셋의 아이디를 직접 지정해주자.
- 이후, 아이템 타입에 맞게 Potion은 float HealAmount를, Scroll은 FABCharacterStat BaseStat 변수들을 선언해주고 아이템 별로 Data Asset의 값들을 설정해준다.
// Potion 획득
void AABCharacterBase::DrinkPostion(UABItemData* InItemData)
{
UABPotionItemData* PotionItemData = Cast<UABPotionItemData>(InItemData);
if (PotionItemData)
{
Stat->HealHp(PotionItemData->HealAmount);
}
}
// ...
// Scroll 획득
void AABCharacterBase::ReadScroll(UABItemData* InItemData)
{
UABScrollItemData* ScrollItemData = Cast<UABScrollItemData>(InItemData);
if (ScrollItemData)
{
Stat->AddBaseStat(ScrollItemData->BaseStat);
}
}
- ABCharacterBase.cpp
- 로그만 찍었던 DrinkPotion과 ReadScroll의 기능을 추가해준다.
- Stat컴포넌트에서 Potion을 획득하면 MaxHp가 증가하도록 해주고, Scroll을 획득하면 데이터에 따라 BaseStat을 변경해주도록 로직을 구성하면 된다.
// 아이템 효과 함수 (포션)
FORCEINLINE void HealHp(float InHealAmount) { CurrentHp = FMath::Clamp(CurrentHp + InHealAmount, 0, GetTotalStat().MaxHp); OnHpChanged.Broadcast(CurrentHp); }
// 아이템 효과 함수 (스크롤)
FORCEINLINE void AddBaseStat(const FABCharacterStat& InAddBaseStat) { BaseStat = BaseStat + InAddBaseStat; OnStatChanged.Broadcast(GetBaseStat(), GetModifierStat()); }
- ABCharacterStatComponent.h
- 전처리를 통해 간단하게 구현하고, Stat이 변경되기때문에 델리게이트를 통해 Broadcast를 해주면 UI에도 반영이 된다.
- 에디터에서 HpBarWidget의 레이아웃을 살짝 수정해주고, 클래스를 수정해준다.
public:
//FORCEINLINE void SetMaxHp(float NewMaxHp) { MaxHp = NewMaxHp; }
void UpdateStat(const FABCharacterStat& BaseStat, const FABCharacterStat& ModifierStat);
void UpdateHpBar(float NewCurrentHp);
- ABHpBarWidget.h
// NativeConstruct 함수가 호출될 때면 UI에 관련된 모든 기능들이 거의 초기화가 완료됐다고 보면 된다.
void UABHpBarWidget::NativeConstruct()
{
Super::NativeConstruct();
// 아까 PbHpBar라고 Canvas에 설정함
HpProgressBar = Cast<UProgressBar>(GetWidgetFromName(TEXT("PbHpBar")));
ensure(HpProgressBar);
// TextBlock
HpStat = Cast<UTextBlock>(GetWidgetFromName(TEXT("TxtHpStat")));
ensure(HpStat);
IABCharacterWidgetInterface* CharacterWidget = Cast<IABCharacterWidgetInterface>(OwningActor);
if (CharacterWidget)
{
CharacterWidget->SetupCharacterWidget(this);
}
}
// Stat이 변경되면 HpBar와 변경된 Stat이 반영되도록
void UABHpBarWidget::UpdateStat(const FABCharacterStat& BaseStat, const FABCharacterStat& ModifierStat)
{
MaxHp = (BaseStat + ModifierStat).MaxHp;
if (HpProgressBar)
{
HpProgressBar->SetPercent(CurrentHp / MaxHp);
}
if (HpStat)
{
HpStat->SetText(FText::FromString(GetHpStatText()));
}
}
// Stat이 변경되면 HpBar와 변경된 Stat이 반영되도록
void UABHpBarWidget::UpdateHpBar(float NewCurrentHp)
{
CurrentHp = NewCurrentHp;
ensure(MaxHp > 0.0f);
if (HpProgressBar)
{
HpProgressBar->SetPercent(CurrentHp / MaxHp);
}
if (HpStat)
{
HpStat->SetText(FText::FromString(GetHpStatText()));
}
}
// HpBar의 Text가 100/100 형태로 나올 수 있도록
FString UABHpBarWidget::GetHpStatText()
{
return FString::Printf(TEXT("%.0f/%.0f"), CurrentHp, MaxHp);
}
- ABHpBarWidget.cpp
- UpdateStat함수를 추가해 HpBar와 Stat이 변경되면 바로 적용될 수 있도록 해준다.
- GetHpStatText를 통해 HpBarText의 형태가 정상적으로 나올 수 있게 변경해준다.
해당 포스트는 인프런의 <이득우의 언리얼 프로그래밍 Part2 -언리얼 게임 프레임웍의 이해>
강의를 수강하고 정리한 내용입니다.
이득우의 언리얼 프로그래밍 Part2 - 언리얼 게임 프레임웍의 이해 | 이득우 - 인프런
청강문화산업대학교에서 언리얼 엔진, 게임 수학, UEFN 게임제작을 가르치고 있습니다. - 이득우의 언리얼 C++ 프로그래밍, 넥슨 코리아 공식 교육 교재 선정 2023 - 스마일게이트 언리얼 프로그래
www.inflearn.com
728x90
'공부 > 이득우의 언리얼 프로그래밍' 카테고리의 다른 글
[Study] Part 3 - 언리얼 네트웍 멀티플레이어 프레임웍 개요 (1/15) (0) | 2024.08.09 |
---|---|
[Study] Part 2 - 게임의 완성 (15/15) (0) | 2024.08.07 |
[Study] Part 2 - 헤드업디스플레이의 구현 (13/15) (0) | 2024.06.21 |
[Study] Part 2 - 행동 트리 모델의 구현 (12/15) (0) | 2024.06.20 |
[Study] Part 2 - 행동 트리 모델의 이해 (11/15) (0) | 2024.06.19 |