You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// ABCharacterStatComponent.h// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include"CoreMinimal.h"
#include"Components/ActorComponent.h"
#include"ABCharacterStatComponent.generated.h"// 델리게이트 발행 위쪽은 매개변수 x, 아래쪽은 매개변수 하나// 컨벤션에 집중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 propertiesUABCharacterStatComponent();
protected:// Called when the game startsvirtualvoidBeginPlay() override;
public:
FOnHpZeroDelegate OnHpZero;
FOnHpChangedDelegate OnHpChanged;
// 간단한 getter, setter라 inline으로 처리
FORCEINLINE floatGetMaxHp() { return MaxHp; }
FORCEINLINE floatGetCurrentHp() { return CurrentHp; }
floatApplyDamage(float InDamage);
protected:// HP변경할 때 사용하는 함수(필수로 입구와 출구를 하나로 만들고 내부에서 훅킹함)voidSetHp(float NewHp);
// VisibleInstanceOnly 인스턴스마다 다르게 설정할 수 있다.UPROPERTY(VisibleInstanceOnly, Category = Stat)
float MaxHp;
// Transient: 디스크에 저장하지 않는다. (공간 낭비 x)UPROPERTY(Transient, VisibleInstanceOnly, Category = Stat)
float CurrentHp;
};
// ABCharacterStatComponent.cpp
#include"CharacterStat/ABCharacterStatComponent.h"// Sets default values for this component's propertiesUABCharacterStatComponent::UABCharacterStatComponent()
{
// 생성자 초기화
MaxHp = 200.0f;
CurrentHp = MaxHp;
}
// Called when the game startsvoidUABCharacterStatComponent::BeginPlay()
{
Super::BeginPlay();
// 시작시 초기화 *(Start)SetHp(MaxHp);
}
floatUABCharacterStatComponent::ApplyDamage(float InDamage)
{
constfloat PrevHp = CurrentHp;
// Clamp: 최소값과 최대값을 설정하여 그 사이의 값만을 반환constfloat ActualDamage = FMath::Clamp<float>(InDamage, 0, InDamage);
SetHp(PrevHp - ActualDamage);
if (CurrentHp <= KINDA_SMALL_NUMBER)
{
OnHpZero.Broadcast();
}
return ActualDamage;
}
voidUABCharacterStatComponent::SetHp(float NewHp)
{
CurrentHp = FMath::Clamp<float>(NewHp, 0.0f, MaxHp);
OnHpChanged.Broadcast(CurrentHp); // Invoke
}
정리하자면 액터를 최종적으로 마무리하고자 할 때는 PostInitializeComponents라는 함수를 통해 초기화를 마무리한다. (에디터 실행 전 마무리 작업) 이후 BeginPlay 함수를 통해 게임 실행 전 초기화 작업을 마무리한다. (게임 실행 전 마무리 작업) 이후에는 Tick 함수를 통해 게임 실행 중 작업을 진행한다. (게임 실행 중 작업)
위젯 컴포넌트와 위젯
위젯 컴포넌트는 Actor 이외의 UI 위젯을 띄워주는 컴포넌트에 불과하다. 내부적으로 2D와 3D모두 지원하며 위젯 컴포넌트는 컨테이너의 역할만 할 뿐, 둘은 서로 독립적으로 동작한다. (위젯과 위젯 컴포넌트)
위젯 컴포넌트의 초기화 과정
(현재 위젯과 실제 스탯의 통신을 위해 초기화 과정을 알아야 한다.) 발행 구독 모델의 구현을 위해 위젯 컴포넌트의 초기화 단계를 파악할 필요가 있다. UI 관련 컴포넌트는 액터의 BeginPlay 이후에 호출되고 있다. 생성시 InitWidget함수와 NativeConstruct함수가 호출되며, 이를 ㅌ오해 차우에 변경될 가능성을 염두해야 한다.
하지만 지금은 소유한 액터의 정보를 알아올 수 없도록 설계가 되어 있다. 따라서 이를 확장하여 설계해야 한다.
실습
// ABCharacterBase.cpp
#include"UI/ABHpBarWidget.h"
#include"UI/ABMyWidgetComponent.h"// .. 생략// 서브 오브젝트 할당을 확장 클래스로 변경 (소유 액터를 알 수 있는 wIdget)
HpBar = CreateDefaultSubobject<UABMyWidgetComponent>(TEXT("Widget"));
// .. 생략voidAABCharacterBase::PostInitializeComponents()
{
Super::PostInitializeComponents();
// 라이프서클중 PostInitializeComponents에서 위젯 초기화 죽음 메서드와 STAT 이벤트와 연결
Stat->OnHpZero.AddUObject(this, &AABCharacterBase::SetDead);
}
// 실제 데미지 주는 동작을 Stat에 일임
Stat->ApplyDamage(DamageAmount);
// .. 생략// 죽으면 위젯을 숨기는 동작
HpBar->SetHiddenInGame(true);
// .. 생략// 사용자 정의 인터페이스 구현체 (캐릭터간 의존성 x)voidAABCharacterBase::SetupCharacterWidget(UABUserWidget* InUserWidget)
{
//확장된 위젯 클래스로 캐스팅하고, 이를 통해 Stat 이벤트와 UI 바인딩
UABHpBarWidget* HpBarWidget = Cast<UABHpBarWidget>(InUserWidget);
if (HpBarWidget)
{
HpBarWidget->SetMaxHp(Stat->GetMaxHp());
HpBarWidget->UpdateHpBar(Stat->GetCurrentHp());
Stat->OnHpChanged.AddUObject(HpBarWidget, &UABHpBarWidget::UpdateHpBar);
}
}
// ABHpBarWidget.cpp// 위 코드에서 사용하게 되는 인터페이스..
#include"Interface/ABCharacterWidgetInterface.h"// 인터페이스로 캐스팅하여 실제 인터페이스의 인스턴스를 가져온다. (해당 함수를 포인팅하여 가져옴)// 확장으로 상위 액터의 정보를 가져올 수 있게 된다. (OwningActor)
IABCharacterWidgetInterface* CharacterWidget = Cast<IABCharacterWidgetInterface>(OwningActor);
if (CharacterWidget)
{
// 해당 인터페이스 함수를 호출하도록 함 (CharacterBase <-> HPBarWidget)
CharacterWidget->SetupCharacterWidget(this);
}
7강: 캐릭터 스탯과 위젯
캐릭터 스탯의 설정
액터 컴포넌트를 활용한 스탯의 설계
액터 컴포넌트란, 액터에 부착할 수 있는 컴포넌트 중 트랜스폼이 없는 컴포넌트이다. 액터의 기능을 확장할 때 컴포넌트로 분리해 모듈화할 수 있기 때문에 액터 컴포넌트를 사용한다. (응집성, 결합도)
이번 강의에선 스탯 데이터를 담당하는 컴포넌트와 UI 위젯을 담당하는 컴포넌트로 분리하는데, 본 액터는 두 컴포넌트가 서로 통신하도록 중개하는 역할로 지정한다. (Manager의 역할)
ex) 외부로부터 피해를 받는다면 액터는 이벤트를 받고 스탯 컴포넌트에 피해량을 전달하고, 스탯 컴포넌트는 피해량을 계산하여 UI 업데이트를 위해 UI 컴포넌트에 전달한다.
언리얼 델리게이트를 활용한 발행 구독 모델의 구현
푸시형태의 알림을 구현하는데 적합한 디자인 패턴으로 느슨한 결합을 위해 사용한다.
실습
액터의 초기화 과정
액터의 라이프 싸이클
정리하자면 액터를 최종적으로 마무리하고자 할 때는
PostInitializeComponents
라는 함수를 통해 초기화를 마무리한다. (에디터 실행 전 마무리 작업) 이후BeginPlay
함수를 통해 게임 실행 전 초기화 작업을 마무리한다. (게임 실행 전 마무리 작업) 이후에는Tick
함수를 통해 게임 실행 중 작업을 진행한다. (게임 실행 중 작업)위젯 컴포넌트와 위젯
위젯 컴포넌트는 Actor 이외의 UI 위젯을 띄워주는 컴포넌트에 불과하다. 내부적으로 2D와 3D모두 지원하며 위젯 컴포넌트는 컨테이너의 역할만 할 뿐, 둘은 서로 독립적으로 동작한다. (위젯과 위젯 컴포넌트)
위젯 컴포넌트의 초기화 과정
(현재 위젯과 실제 스탯의 통신을 위해 초기화 과정을 알아야 한다.) 발행 구독 모델의 구현을 위해 위젯 컴포넌트의 초기화 단계를 파악할 필요가 있다. UI 관련 컴포넌트는 액터의
BeginPlay
이후에 호출되고 있다. 생성시InitWidget
함수와NativeConstruct
함수가 호출되며, 이를 ㅌ오해 차우에 변경될 가능성을 염두해야 한다.하지만 지금은 소유한 액터의 정보를 알아올 수 없도록 설계가 되어 있다. 따라서 이를 확장하여 설계해야 한다.
실습
정리
The text was updated successfully, but these errors were encountered: