일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- local prediction
- gameplay tag
- map design
- attribute
- Replication
- Unreal Engine
- gas
- animation
- 게임개발
- gameplay ability system
- unity
- gameplay effect
- 유니티
- 게임 개발
- 언리얼 엔진
- 언리얼엔진
- os
- Multiplay
- ability task
- nanite
- photon fusion2
- rpc
- MAC
- gravity direction
- ret2libc
- listen server
- CTF
- UI
- Aegis
- dirty cow
- Today
- Total
Replicated
[Drag Down] 멀티 환경에서 스테미나 UI 제작 및 GAS 연결 본문

일단 UI는 플레이어 컨트롤러에다가 달아둘 거다
일단 만들어만 주자
그리고 GAS와 연결해야 하니, 세팅을 좀 많이 해줘야 한다
정확히는, 위젯과 위젯 컴포넌트를 확장해야 한다

일단 위젯을 확장하자
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "AbilitySystemInterface.h"
#include "DDGASUserWidget.generated.h"
/**
*
*/
UCLASS()
class DRAGDOWN_API UDDGASUserWidget : public UUserWidget, public IAbilitySystemInterface
{
GENERATED_BODY()
public:
virtual void SetOwner(AActor* InOwner);
virtual void SetAbilitySystemComponent(AActor* InOwner);
virtual class UAbilitySystemComponent* GetAbilitySystemComponent() const override;
protected:
UPROPERTY(EditAnywhere, Category = GAS)
TObjectPtr<class UAbilitySystemComponent> ASC;
UPROPERTY()
TObjectPtr<AActor> Owner;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/DDGASUserWidget.h"
#include "AbilitySystemBlueprintLibrary.h"
void UDDGASUserWidget::SetOwner(AActor* InOwner)
{
if (IsValid(InOwner))
{
Owner = InOwner;
}
}
void UDDGASUserWidget::SetAbilitySystemComponent(AActor* InOwner)
{
if (IsValid(InOwner))
{
ASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(InOwner);
}
}
UAbilitySystemComponent* UDDGASUserWidget::GetAbilitySystemComponent() const
{
return ASC;
}
일단 위젯에 오너를 설정할 수 있도록 하고, 해당 오너에서 어빌리티 시스템 컴포넌트를 뜯어올 수 있도록 한다

다음은 위젯 컴포넌트를 확장한다
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/WidgetComponent.h"
#include "DDGASWidgetComponent.generated.h"
/**
*
*/
UCLASS()
class DRAGDOWN_API UDDGASWidgetComponent : public UWidgetComponent
{
GENERATED_BODY()
public:
void ActivateGAS();
protected:
virtual void InitWidget() override;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/DDGASWidgetComponent.h"
#include "UI/DDGASUserWidget.h"
#include "DragDown.h"
void UDDGASWidgetComponent::ActivateGAS()
{
UDDGASUserWidget* GASUserWidget = Cast<UDDGASUserWidget>(GetWidget());
if (GASUserWidget)
{
GASUserWidget->SetAbilitySystemComponent(GetOwner());
}
else
{
UE_LOG(LogDD, Log, TEXT("ActivateGAS Failed - No GASUserWidget"));
}
}
void UDDGASWidgetComponent::InitWidget()
{
Super::InitWidget();
//UE_LOG(LogCS, Log, TEXT("InitWidget IS Called"));
UDDGASUserWidget* GASUserWidget = Cast<UDDGASUserWidget>(GetWidget());
if (GASUserWidget)
{
GASUserWidget->SetOwner(GetOwner());
}
else
{
UE_LOG(LogDD, Log, TEXT("InitWidget Failed - No GASUserWidget"));
}
}
위젯 컴포넌트다
InitWidget에서 처음에 위젯에 오너를 설정하고, ActivateGAS에서 ASC 설정.. 인데,
캐릭터에 붙어 다니는 거면 위젯 컴포넌트가 필요한데 단순히 화면에 붙여서 띄우는 건 필요가 없다
그냥 만들어놓고 나중에 쓰자 (이름같은 거 넣을 때는 필요할 것)

어찌 되었든, 위에서 만든 GAS 위젯 기반으로 위젯을 새로 만들자
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UI/DDGASUserWidget.h"
#include "GameplayEffectTypes.h"
#include "DDGASStaminaBarUserWidget.generated.h"
/**
*
*/
UCLASS()
class DRAGDOWN_API UDDGASStaminaBarUserWidget : public UDDGASUserWidget
{
GENERATED_BODY()
public:
virtual void SetAbilitySystemComponent(AActor* InOwner) override;
void UpdateStaminaBar();
protected:
virtual void OnStaminaChanged(const FOnAttributeChangeData& ChangeData);
virtual void OnMaxStaminaChanged(const FOnAttributeChangeData& ChangeData);
protected:
UPROPERTY(meta = (BindWidget))
TObjectPtr<class UProgressBar> PbStaminaBar;
float CurrentStamina = 0.0f;
float CurrentMaxStamina = 0.1f;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "UI/DDGASStaminaBarUserWidget.h"
#include "AbilitySystemComponent.h"
#include "Attribute/DDAttributeSet.h"
#include "Components/ProgressBar.h"
#include "DragDown.h"
void UDDGASStaminaBarUserWidget::SetAbilitySystemComponent(AActor* InOwner)
{
Super::SetAbilitySystemComponent(InOwner);
if (ASC)
{
ASC->GetGameplayAttributeValueChangeDelegate(UDDAttributeSet::GetStaminaAttribute()).AddUObject(this, &UDDGASStaminaBarUserWidget::OnStaminaChanged);
ASC->GetGameplayAttributeValueChangeDelegate(UDDAttributeSet::GetMaxStaminaAttribute()).AddUObject(this, &UDDGASStaminaBarUserWidget::OnMaxStaminaChanged);
//UE_LOG(LogCS, Log, TEXT("[NetMode : %d] SetAbilitySystemComponent"), GetWorld()->GetNetMode());
const UDDAttributeSet* CurrentAttributeSet = ASC->GetSet<UDDAttributeSet>();
if (CurrentAttributeSet)
{
CurrentStamina = CurrentAttributeSet->GetStamina();
CurrentMaxStamina = CurrentAttributeSet->GetMaxStamina();
if (CurrentMaxStamina > 0.0f)
{
UpdateStaminaBar();
}
else
{
UE_LOG(LogDD, Warning, TEXT("CurrentMaxEnergy is 0"));
}
}
else
{
UE_LOG(LogDD, Warning, TEXT("CurrentAttributeSet is null!"));
}
}
else
{
UE_LOG(LogDD, Warning, TEXT("ASC is null! Ensure that the Ability System Component is properly initialized before calling this function."));
}
}
void UDDGASStaminaBarUserWidget::UpdateStaminaBar()
{
if (PbStaminaBar)
{
UE_LOG(LogDD, Log, TEXT("UpdateEnergyBar : %f / %f"), CurrentStamina, CurrentMaxStamina);
PbStaminaBar->SetPercent(CurrentStamina / CurrentMaxStamina);
}
}
void UDDGASStaminaBarUserWidget::OnStaminaChanged(const FOnAttributeChangeData& ChangeData)
{
UE_LOG(LogDD, Log, TEXT("[NetMode %d]OnEnergyChanged"), GetWorld()->GetNetMode());
CurrentStamina = ChangeData.NewValue;
UpdateStaminaBar();
}
void UDDGASStaminaBarUserWidget::OnMaxStaminaChanged(const FOnAttributeChangeData& ChangeData)
{
CurrentMaxStamina = ChangeData.NewValue;
UpdateStaminaBar();
}
GAS랑 연동해서 Stamina가 변경되면 알아서 변경되도록 델리게이트에 연결해둔다
그렇게 만든 클래스 기반으로 위젯을 만들어보자

패널 밑에 스테미나 바 위치 (이름 반드시 코드와 일치 필요)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "DDPlayerController.generated.h"
/**
*
*/
UCLASS()
class DRAGDOWN_API ADDPlayerController : public APlayerController
{
GENERATED_BODY()
public:
ADDPlayerController();
protected:
virtual void BeginPlayingState() override;
protected:
void InitGASWidget();
// UMG 위젯 클래스 (블루프린트에서 설정)
UPROPERTY(EditDefaultsOnly, Category = "UI")
TSubclassOf<class UDDGASStaminaBarUserWidget> StaminaBarWidgetClass;
UPROPERTY()
TObjectPtr<class UDDGASStaminaBarUserWidget> StaminaBarWidget;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "Player/DDPlayerController.h"
#include "UI/DDGASStaminabarUserWidget.h"
#include "AbilitySystemComponent.h"
#include "DragDown.h"
ADDPlayerController::ADDPlayerController()
{
}
void ADDPlayerController::BeginPlayingState()
{
Super::BeginPlayingState();
if (IsLocalController())
{
InitGASWidget();
}
}
void ADDPlayerController::InitGASWidget()
{
UE_LOG(LogDD, Log, TEXT("InitGASWidget Start"));
if ( StaminaBarWidgetClass == nullptr || StaminaBarWidget != nullptr) return;
UE_LOG(LogDD, Log, TEXT("InitGASWidget Start - 2"));
StaminaBarWidget = CreateWidget<UDDGASStaminaBarUserWidget>(this, StaminaBarWidgetClass);
if (StaminaBarWidget == nullptr)
{
UE_LOG(LogDD, Log, TEXT("InitGASWidget: StaminaBarWidget Creation Is Failed"));
return;
}
StaminaBarWidget->AddToViewport();
APawn* ControlledPawn = GetPawn();
if (!ControlledPawn)
{
UE_LOG(LogDD, Log, TEXT("InitGASWidget: No Pawn"));
return;
}
StaminaBarWidget->SetAbilitySystemComponent(ControlledPawn);
}
플레이어 컨트롤러에선 InitGASWidget에서 위젯을 만들고 어빌리티 시스템을 설정해준다
BeginPlayingState에서 설정해주면 되는데, 이 시점은 컨트롤러가 폰에 빙의하고, 본격적으로 시작 가능한 시점에서 생성된다. 즉, 클라이언트가 설정하기 최적의 타이밍이다.
동기화까지 잘 되어 실행되는 것을 알 수 있다.
다음은 일정 시간마다 자동으로 스테미나를 회복하도록 하자.

'언리얼 엔진 > Drag Down (캡스톤 디자인)' 카테고리의 다른 글
[Drag Down] 스테미나 자동 회복 시스템 (문제.. 동기화가 느림) (0) | 2025.04.03 |
---|---|
** [Drag Down] Local Prediction시 외부 컴포넌트의 동기화 ** (0) | 2025.04.03 |
[Drag Down] 이펙트로 어트리뷰트 사용 처리, 어트리뷰트 부족 시 어빌리티 사용 제한하기 (0) | 2025.04.02 |
[Drag Down] Gameplay Tag로 어빌리티 꼬임 방지 (0) | 2025.04.02 |
[Drag Down] 회피 만들기 (0) | 2025.04.01 |