๐Ÿ“˜ TIL - MVP ํ”Œ๋ ˆ์ด ์—ฐ๊ฒฐ ๋ฐ Command/Context/Queue ๊ตฌ์กฐ ํ™•์žฅ

HappyCircleยท2026๋…„ 4์›” 7์ผ

Unreal ๊ฐœ๋ฐœ

๋ชฉ๋ก ๋ณด๊ธฐ
102/163

๋ฌธ์ œ

์–ด์ œ๊นŒ์ง€๋Š” ๋‹ค์Œ ๊ตฌ์กฐ๊นŒ์ง€๋Š” ๋งŒ๋“ค์–ด๋‘” ์ƒํƒœ์˜€๋‹ค.

UI โ†’ PlayerController โ†’ Dispatcher โ†’ Server โ†’ Provider โ†’ UI

UI์—์„œ ์‹œ์ž‘ํ•ด์„œ ์„œ๋ฒ„๋ฅผ ๊ฑฐ์ณ ๋‹ค์‹œ UI๋กœ ๋Œ์•„์˜ค๋Š” ํ๋ฆ„ ์ž์ฒด๋Š” ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ์ƒํƒœ์˜€๋‹ค.

๋‹ค๋งŒ ์‹ค์ œ ํ”„๋กœ์ ํŠธ ๊ธฐ์ค€์œผ๋กœ ๋ณด๋ฉด ๋ช‡ ๊ฐ€์ง€ ๋น ์ง„ ๋ถ€๋ถ„์ด ์žˆ์—ˆ๋‹ค.


๊ตฌ์กฐ์  ๋ฌธ์ œ

๊ตฌ๋ถ„๋ฌธ์ œ
ํ…Œ์ŠคํŠธ์‹ค์ œ Actor ๊ธฐ์ค€ ํ…Œ์ŠคํŠธ ๋ถˆ๊ฐ€
CommandPlayerController ํ•˜๋“œ์ฝ”๋”ฉ
Context๊ตฌ์กฐ๋งŒ ์žˆ๊ณ  UI ์ „ํ™˜ ์—†์Œ
์ƒ์‚ฐQueue ๊ฐœ๋… ์—†์Œ
๋ฐ์ดํ„ฐ ํ๋ฆ„UI โ†” Gameplay ์—ฐ๊ฒฐ ๋ถ€์กฑ

๊ธฐ์กด ์ƒํƒœ

Selection โ†’ ViewModel โ†’ UI ํ‘œ์‹œ
Command โ†’ ViewModel โ†’ UI ํ‘œ์‹œ

UI๋Š” ์ •์ƒ์ ์œผ๋กœ ์ถœ๋ ฅ๋˜์ง€๋งŒ
์‹ค์ œ ์œ ๋‹›์ด๋‚˜ ๊ฑด๋ฌผ๊ณผ ์—ฐ๊ฒฐ๋œ ์ƒํƒœ๋Š” ์•„๋‹ˆ์—ˆ๋‹ค.


๋ถ„์„

๊ฒฐ๊ตญ ๋ฌธ์ œ๋Š” ํ•˜๋‚˜์˜€๋‹ค.

๊ตฌ์กฐ๋Š” ๋งŒ๋“ค์–ด๋†จ๋Š”๋ฐ ์‹ค์ œ ๊ฒŒ์ž„ ํ๋ฆ„์œผ๋กœ ์ด์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.


๊ตฌ์กฐ vs ์‹ค์ œ

[๊ธฐ์กด]
UI ๊ตฌ์กฐ โœ”
์‹ค์ œ ๊ฒŒ์ž„ ํ๋ฆ„ โœ–

[๋ชฉํ‘œ]
UI ๊ตฌ์กฐ โœ”
์‹ค์ œ ๊ฒŒ์ž„ ํ๋ฆ„ โœ”

ํ•ด๊ฒฐ


1. Command ์ƒ์„ฑ ๊ตฌ์กฐ ๋ณ€๊ฒฝ (ํ•ต์‹ฌ)


๊ธฐ์กด ๊ตฌ์กฐ

// PlayerController.cpp
OutCommandIds = { TEXT("Move"), TEXT("Attack"), TEXT("Hold") };

Command๋ฅผ PlayerController์—์„œ ์ง์ ‘ ๋งŒ๋“ค์–ด์„œ ๋„ฃ๋Š” ๋ฐฉ์‹์ด์—ˆ๋‹ค.


๋ณ€๊ฒฝ ๊ตฌ์กฐ

// PlayerController.cpp
OutCommandIds = Unit->GetAvailableCommandIds();
// UnitActor.cpp
TArray<FName> ATWTestUnitActor::GetAvailableCommandIds() const
{
    return AvailableCommandIds;
}

๊ตฌ์กฐ ๋ณ€ํ™”

[์ด์ „]
PlayerController โ†’ Command ์ƒ์„ฑ

[์ดํ›„]
Actor โ†’ Command ์ œ๊ณต โ†’ PlayerController ์ „๋‹ฌ

์˜๋ฏธ

Command๋ฅผ ์ง์ ‘ ๋งŒ๋“œ๋Š” ๊ตฌ์กฐ์—์„œ
Actor๊ฐ€ ๋“ค๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๊ตฌ์กฐ๋กœ ๋ฐ”๊พผ ๊ฒƒ์ด๋‹ค.


2. BuildMenu Context ์‹ค์ œ ์ ์šฉ


๊ธฐ์กด

Context ๊ตฌ์กฐ๋งŒ ์กด์žฌ
โ†’ UI ๋ณ€ํ™” ์—†์Œ

์ ์šฉ ์ฝ”๋“œ

if (InCommandId == TEXT("BuildMenu"))
{
    SelectionProvider->PushContext("Build");
}

Context Map

ContextCommandMap.Add(
    TEXT("Build"),
    {
        TEXT("BuildBarracks"),
        TEXT("BuildArcheryRange"),
        TEXT("Back")
    }
);

ํ๋ฆ„

Engineer ์„ ํƒ
โ†’ CommandPanel
โ†’ Build ํด๋ฆญ
โ†’ Context ๋ณ€๊ฒฝ
โ†’ Build ๋ฉ”๋‰ด ํ‘œ์‹œ
โ†’ Back
โ†’ ์ด์ „ ์ƒํƒœ ๋ณต๊ท€

๊ฒฐ๊ณผ

Context๊ฐ€ ์‹ค์ œ UI ์ „ํ™˜๊นŒ์ง€ ์ด์–ด์ง€๋„๋ก ์—ฐ๊ฒฐํ–ˆ๋‹ค.


3. ์ƒ์‚ฐ Queue ์‹œ์Šคํ…œ ์ถ”๊ฐ€


๊ธฐ์กด

Train ๋ฒ„ํŠผ โ†’ ๋ฐ”๋กœ ์ƒ์„ฑ

๋ณ€๊ฒฝ ๊ตฌ์กฐ

์‹œ์ž‘ ์‹œ

++FootmanQueueCount;

์™„๋ฃŒ ์‹œ

FootmanQueueCount--;

ํ๋ฆ„

Command ํด๋ฆญ
โ†’ Queue ์ฆ๊ฐ€
โ†’ Timer ๋™์ž‘
โ†’ Unit ์ƒ์„ฑ
โ†’ Queue ๊ฐ์†Œ

UI ๋ฐ˜์˜

SlotVM.QueueCount = Building->GetQueueCountForCommand(SlotVM.CommandId);

๊ฒฐ๊ณผ

Train Footman x2
Train Archer x1

์˜๋ฏธ

๋ฒ„ํŠผ ํด๋ฆญ โ†’ ์ƒํƒœ ๋ณ€๊ฒฝ โ†’ UI ๊ฐฑ์‹  ํ๋ฆ„์ด ์‹ค์ œ๋กœ ์ด์–ด์ง€๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค.


4. Coordinator ์ฑ…์ž„ ์œ ์ง€


๋ฌธ์ œ

QueueCount๋ฅผ ์–ด๋””์—์„œ ์ฒ˜๋ฆฌํ• ์ง€


์„ ํƒ

Coordinator ์ˆ˜์ • X
PlayerController์—์„œ ํ›„์ฒ˜๋ฆฌ

์ฝ”๋“œ

TArray<FCommandSlotViewModel> BuiltCommands = HUDCoordinator->GetLastBuiltCommandViewModels();

for (FCommandSlotViewModel& SlotVM : BuiltCommands)
{
    SlotVM.QueueCount = Building->GetQueueCountForCommand(SlotVM.CommandId);
}

HUDRootWidget->SetCommandData(BuiltCommands);

์ด์œ 

ํ•ญ๋ชฉ์ด์œ 
์ฑ…์ž„ ๋ถ„๋ฆฌCoordinator๋Š” UI ๊ตฌ์„ฑ๋งŒ ๋‹ด๋‹น
ํ™•์žฅ์„ฑ๊ตฌ์กฐ ๋ณ€๊ฒฝ ์‹œ ์˜ํ–ฅ ์ตœ์†Œํ™”
์†๋„MVP ๋‹จ๊ณ„์—์„œ ๋น ๋ฅด๊ฒŒ ์ ์šฉ ๊ฐ€๋Šฅ

5. ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ ์ „ํ™˜


Actor ๊ตฌ์กฐ

UPROPERTY(EditAnywhere)
TArray<FName> AvailableCommandIds;

๊ฒฐ๊ณผ

BP์—์„œ Command ์ˆ˜์ •
โ†’ UI ๋ฐ”๋กœ ๋ฐ˜์˜

์˜๋ฏธ

ํ•˜๋“œ์ฝ”๋”ฉ ์ œ๊ฑฐํ•˜๊ณ  ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜์œผ๋กœ ์ „ํ™˜ํ•œ ์ƒํƒœ๋‹ค.


6. MVP ๊ฒŒ์ž„ ๋ฃจํ”„ ์™„์„ฑ


์ „์ฒด ํ๋ฆ„

Actor ์„ ํƒ
โ†’ CommandIds ๊ฐ€์ ธ์˜ค๊ธฐ
โ†’ UI ํ‘œ์‹œ
โ†’ ์ž…๋ ฅ ๋ฐœ์ƒ
โ†’ PlayerController ์‹คํ–‰
โ†’ ์ƒํƒœ ๋ณ€๊ฒฝ
โ†’ UI ๊ฐฑ์‹ 

์‹คํ–‰ ํ๋ฆ„ ์ฝ”๋“œ

// 1. ํด๋ฆญ
Widget โ†’ ExecuteCommandById

// 2. ์‹คํ–‰
PlayerController โ†’ ExecuteGameplayCommandById

// 3. ์ƒํƒœ ๋ณ€๊ฒฝ
Building โ†’ Queue ์ฆ๊ฐ€

// 4. UI ๊ฐฑ์‹ 
Coordinator โ†’ CommandPanel ๊ฐฑ์‹ 

ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ ํ•ญ๋ชฉ

๊ธฐ๋Šฅ์ƒํƒœ
์œ ๋‹› ์„ ํƒโœ”
์ด๋™โœ”
๊ณต๊ฒฉ (placeholder)โœ”
BuildMenuโœ”
๊ฑด๋ฌผ ์„ ํƒโœ”
์œ ๋‹› ์ƒ์‚ฐโœ”
Queue ํ‘œ์‹œโœ”

7. ๊ตฌ์กฐ ๋ณ€ํ™” ์š”์•ฝ


Before

UI ์ค‘์‹ฌ ๊ตฌ์กฐ
โ†’ ํ‘œ์‹œ๋งŒ ๋˜๋Š” ์ƒํƒœ

After

Actor ์ค‘์‹ฌ ๊ตฌ์กฐ
โ†’ ์‹ค์ œ ๋™์ž‘ ๊ฐ€๋Šฅ

๋น„๊ต

ํ•ญ๋ชฉ์ด์ „์ดํ›„
Command ์ƒ์„ฑPlayerControllerActor
Context๊ตฌ์กฐ๋งŒ ์กด์žฌ์‹ค์ œ ๋™์ž‘
์ƒ์‚ฐ์ฆ‰์‹œ ์‹คํ–‰Queue ๊ธฐ๋ฐ˜
UI ๊ฐฑ์‹ ์ˆ˜๋™์ƒํƒœ ๊ธฐ๋ฐ˜
ํ…Œ์ŠคํŠธ์ œํ•œ์ ํ”Œ๋ ˆ์ด ๊ฐ€๋Šฅ

1. ๊ตฌ์กฐ โ†’ ์‹ค์ œ ์—ฐ๊ฒฐ

์„ค๊ณ„ โ†’ ์‹ค์ œ ํ”Œ๋ ˆ์ด ํ๋ฆ„๊นŒ์ง€ ์—ฐ๊ฒฐ ์™„๋ฃŒ

2. Command ๊ตฌ์กฐ ๊ฐœ์„ 

ํ•˜๋“œ์ฝ”๋”ฉ ์ œ๊ฑฐ
โ†’ ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์ „ํ™˜

3. Context ์‹œ์Šคํ…œ ์ ์šฉ

BuildMenu โ†’ ์‹ค์ œ UI ์ „ํ™˜ ๋™์ž‘

4. ์ƒ์‚ฐ ์‹œ์Šคํ…œ ๊ธฐ์ดˆ

Queue โ†’ UI ์—ฐ๊ฒฐ

5. MVP ์ƒํƒœ ๋„๋‹ฌ

์„ ํƒ โ†’ ๋ช…๋ น โ†’ ์‹คํ–‰ โ†’ UI ๊ฐฑ์‹ 

์ „์ฒด ๊ตฌ์กฐ

Actor
โ†’ CommandIds ์ œ๊ณต
โ†’ PlayerController
โ†’ ์‹คํ–‰
โ†’ ์ƒํƒœ ๋ณ€๊ฒฝ
โ†’ Provider
โ†’ Coordinator
โ†’ UI

์˜ค๋Š˜์˜ ์ •๋ฆฌ

  • ๊ตฌ์กฐ๋งŒ ์žˆ๋˜ ์ƒํƒœ์—์„œ ์‹ค์ œ ๊ฒŒ์ž„ ํ๋ฆ„๊นŒ์ง€ ์—ฐ๊ฒฐํ–ˆ๋‹ค.
  • Command๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์—์„œ ๋ฐ์ดํ„ฐ๋กœ ๋ฐ›์•„์˜ค๋Š” ๊ตฌ์กฐ๋กœ ๋ฐ”๊ฟจ๊ณ ,
  • Context์™€ ์ƒ์‚ฐ Queue๊นŒ์ง€ UI์— ์‹ค์ œ๋กœ ๋ฐ˜์˜๋˜๋„๋ก ๋ถ™์˜€๋‹ค.
profile
๊ฐœ๋ฐœํ•ฉ์‹œ๋‹ค!

0๊ฐœ์˜ ๋Œ“๊ธ€