오늘
오전 작업: GameMode 데이터 관리, UI 데이터 동기화 로직 최적화 코드 짜기
- 델리게이트(Delegate): 공지사항 게시판
- 바인딩(Bind): 게시판 구독
- 브로드캐스트(Broadcast): 게시판에 알림을 보내기
작성 순서
- 체력
- 탄약
- 킬 카운트
- 미션
- 게임클리어
- 게임오버
GameMode.h 추가사항
위젯 클래스 사용을 위함
#include "Blueprint/UserWidget.h”
델리게이트 추가
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float, NewHealthPercent);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnAmmoChanged, int32, CurrentAmmo, int32, MaxAmmo);
public:
virtual void BeginPlay() override; [추가 사항]
UPROPERTY (EditDefaultsOnly, Category = "UI”)
TSubclassOf<UUserWidget>
StartWidgetClass; / HUDWidgetClass; / ResultWidgetClass; 3개 추가
[3개 추가 후 밑에 추가] [현재 화면에 있는 위젯]
UPROPERTY() UUserWidget* CurrentWidget;
UI 전환 함수
void ChangeWidget(TSubclassOf<UUserWidget> NewWidgetClass);
[UI 업데이트 이벤트 바인딩]
UPROPERTY(BlueprintAssignable, Category = "Game Events")
- FOnHealthChanged OnHealthChanged;
- FOnAmmoChanged OnAmmoChanged;
- FOnKillCountChanged OnKillCountChanged;
- FOnMissionUpdated OnMissionUpdated;
- FOnGameEnded OnGameEnded;
[게임 데이터, 상태 관리]
UPROPERTY(BlueprintReadOnly, Category = "Game Data")
- float Health;
- int32 CurrentAmmo;
- int32 MaxAmmo;
- float CurrentTime;
- int32 KillCount;
- int32 TargetScore;
Category = "Game State")
- bool bIsGameClear;
- bool bIsGameOver;
UFUNCTION(BlueprintCallable, Category = "Game Logic") [추가]
void StartGame(); [StartGame만 추가하기
J_GameMode.cpp 추가사항
BeginPlay
[게임 시작 시 시작 화면 위젯을 띄움]
StartGame(); [삭제]
ChangeWidget(StartWidgetClass); [추가]
void AJ_GameMode::ChangeWidget [추가]
void AJ_GameMode::ChangeWidget(TSubclassOf<UUserWidget> NewWidgetClass)
{
if (CurrentWidget)
{
CurrentWidget->RemoveFromParent();
}
if (NewWidgetClass)
{
CurrentWidget = CreateWidget<UUserWidget>(GetWorld(), NewWidgetClass);
if (CurrentWidget)
{
CurrentWidget->AddToViewport();
}
}
}
StartGame()
Health = 1.0f;
CurrentAmmo = 10;
MaxAmmo = 20;
CurrentTime = 60.0f;
KillCount = 0;
bIsGameClear = false;
bIsGameOver = false;
[데이터 초기화 시 UI 동기화]
OnHealthChanged.Broadcast(Health);
OnAmmoChanged.Broadcast(CurrentAmmo, MaxAmmo);
OnKillCountChanged.Broadcast(KillCount);
[게임 HUD 로드]
ChangeWidget(HUDWidgetClass);
EndGame()
GetWorldTimerManager().ClearTimer(GameTimerHandle);
ChangeWidget(ResultWidgetClass); [게임 HUD 로드]
OnGameEnded.Broadcast(bIsGameClear);
코드 순서
RestartGame()
AddKill()
CheckVictoryCondition()
CheckDefeatCondition()
HandleTimer()
J_UserWidget.h
UPROPERTY(meta = (BindWidget)) UTextBlock* ResultText; [삭제]
UFUNCTION() void ShowResultUI(bool bIsGameClear); [삭제]
J_UserWidget.cpp
void UJ_UserWidget::NativeConstruct()
{
Super::NativeConstruct();
// 초기값 설정
UpdateKillCountUI(0);
if (HealthBar) HealthBar->SetPercent(1.0f);
if (AmmoText) AmmoText->SetText(FText::FromString(TEXT("Ammo: 0")));
AJ_GameMode* GM = Cast<AJ_GameMode>(UGameplayStatics::GetGameMode(GetWorld()));
if (GM)
{
// [수정] 결과 관련 바인딩 제거 및 체력/탄약 이벤트 바인딩 추가
GM->OnKillCountChanged.AddDynamic(this, &UJ_UserWidget::UpdateKillCountUI);
GM->OnMissionUpdated.AddDynamic(this, &UJ_UserWidget::UpdateMissionUI);
// [추가] 델리게이트 바인딩
GM->OnHealthChanged.AddDynamic(this, &UJ_UserWidget::UpdateHealthUI);
GM->OnAmmoChanged.AddDynamic(this, &UJ_UserWidget::UpdateAmmoUI);
}
}
// [전체 삭제]
void UJ_UserWidget::ShowResultUI(bool bIsGameClear)
{
if (ResultText)
{
ResultText->SetVisibility(ESlateVisibility::Visible);
ResultText->SetText(bIsGameClear
? FText::FromString(TEXT("MISSION CLEAR!"))
: FText::FromString(TEXT("..GAME OVER..")));
}
}
오후 작업: 코드 수정 및 테스트 진행


현재는 UI 로직 분리 작업 중..
J_MainMenuWidget
// J_StartWidget.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "J_StartWidget.generated.h"
UCLASS()
class CH3_TEAM6_PROJECT_API UJ_StartWidget : public UUserWidget
{
GENERATED_BODY()
public:
// 블루프린트 버튼에서 호출할 함수 (OnStartClicked)
UFUNCTION(BlueprintCallable, Category = "UI")
void OnStartClicked();
};
// J_StartWidget.cpp
#include "J_StartWidget.h"
#include "J_GameMode.h"
#include "Kismet/GameplayStatics.h"
void UJ_StartWidget::OnStartClicked()
{
// 게임 모드를 가져와서 StartGame() 호출
AJ_GameMode* GM = Cast<AJ_GameMode>(UGameplayStatics::GetGameMode(GetWorld()));
if (GM)
{
GM->StartGame();
}
}
J_ResultWidget [결과 화면]
// J_ResultWidget.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/TextBlock.h"
#include "J_ResultWidget.generated.h"
UCLASS()
class CH3_TEAM6_PROJECT_API UJ_ResultWidget : public UUserWidget
{
GENERATED_BODY()
protected:
// 블루프린트에서 만든 텍스트 컴포넌트와 바인딩할 변수
UPROPERTY(meta = (BindWidget)) UTextBlock* ResultTitle;
public:
// 결과 텍스트를 설정하는 함수
UFUNCTION(BlueprintCallable, Category = "UI")
void SetResultText(bool bIsGameClear);
// 재시작 버튼 클릭 시 호출할 함수
UFUNCTION(BlueprintCallable, Category = "UI")
void OnRestartClicked();
};
// J_ResultWidget.cpp
#include "J_ResultWidget.h"
#include "J_GameMode.h"
#include "Kismet/GameplayStatics.h"
void UJ_ResultWidget::SetResultText(bool bIsGameClear)
{
if (ResultTitle)
{
ResultTitle->SetText(bIsGameClear
? FText::FromString(TEXT("MISSION CLEAR!"))
: FText::FromString(TEXT("..GAME OVER..")));
}
}
void UJ_ResultWidget::OnRestartClicked()
{
AJ_GameMode* GM = Cast<AJ_GameMode>(UGameplayStatics::GetGameMode(GetWorld()));
if (GM)
{
GM->RestartGame();
}
}
WBP_MainMenu 생성 → 부모 클래스 J_MainMenuWidget설정
OnClicked 이벤트에 위에서 만든 OnStartClicked 함수 연결
WBP_Result 생성 → 부모 클래스 J_ResultWidget설정
텍스트 블록의 이름 ResultTitle
Event Construct →GameMode를 캐스팅
bIsGameClear 값을 가져오기, SetResultText를 호출하도록 노드 구성
재시작 버튼의 OnClicked에 OnRestartClicked 함수 연결
BP_GameMode 설정
StartWidgetClass →WBP_StartScreen, ResultWidgetClass
WBP_Result할당
현재 코드까지 다 짜놓은 상태인데 에디터 UI가 말썽이다. 계속 UI가 동시에 뜨기 때문에 문제 해결 필요함
회고
팀플의 중요성은 서로에 대한 배려와 신뢰, 각자의 맡은 바 책임을 다하는 데 있다는 것을 이번 기회에 다시금 깨달았다.
혼자서 많은 부분을 소화하며 언리얼 엔진의 전체적인 파이프라인을 깊게 들여다볼 수 있는 기회가 되었지만,
한편으로는 팀원들과 더 적극적으로 소통하여 프로젝트의 균형을 맞추는 노력이 얼마나 중요한지 배울 수 있었다.
특히, 특정 업무 공백이 발생했을 때,
프로젝트가 유기적으로 굴러갈 수 있게 의존성을 재조정하며 전체 파이프라인을 운영하는 법을 익혔다.
이번 경험을 통해 기술적인 구현뿐만 아니라,
팀 프로젝트에서의 리스크 관리와 소통 방식이 결과물의 퀄리티를 결정짓는 요소임을 체감했다.
24일이라는 데드라인이 설정된 상황에서 팀 전체의 업무 공백을 채우며, 프로젝트를 완수해야 한다는 압박감을 경험했다.
'본 캠프 TIL' 카테고리의 다른 글
| 26.07.10 TIL / 팀플 슈터 게임 8일차, TA 강의 정리 (0) | 2026.07.10 |
|---|---|
| 26.07.09 TIL / 팀플 슈터 게임 7일차 (0) | 2026.07.09 |
| 26.07.07 TIL / 팀플 슈터 게임 5일차 (0) | 2026.07.07 |
| 26.07.06 TIL / 팀플 슈터 게임 4일차, 델리게이트 (1) | 2026.07.06 |
| 26.07.03 TIL / 팀플 슈터 게임 3일차, GitHub Desktop 오류 해결 (0) | 2026.07.03 |