개요
개발중인 게임은 카드게임이지만 보드가 존재하여 타일기반의 맵에서 게임을 진행한다.
게임에서 보드를 기반으로 할 수 있는 행동은 크게 3가지 이다.
- 카드를 소모해 유닛 소환
- 현재 내 유닛의 주변 타일에만 유닛 소환가능
- 유닛 이동
- 유닛의 주변 타일로 이동가능
- 유닛 공격
- 공격범위에서 상대 유닛이 있을 경우 공격 가능
각각의 행동들마다 제약이 있어서 구현이 까다로웠다.
내가 생각한 방법은 Tile에 State를 만들고 Tile 클릭시 State마다 다른 행동을 하도록 구현했다.
TileState
- None : 클릭 시 아무 행동도 안함
- Spawnable : Spawn 가능한 Tile
- Moveable: 클릭시 Move
- Attackable : 클릭시 공격
기본적으로 None 상태로 있다가 Spawn을 원할때 (카드를 drag하고 있을때) 는 Spawn 가능한 Tile을 Set하고 유닛을 클릭했을 때 해당 유닛이 이동가능한, 공격 가능한 Tile을 Set하도록 했다.
MapManager
MapManager의 경우 GameInstanceSubsystem으로 만들어서 전역접근이 가능하도록 했다.
멀티플레이가 붙는다면 아마 GameState로 들어가지 않을까 한다. -> 맵상황은 모두가 공유해야하나까
MapManager에서는 각 Tile의 State를 조정할 수 있는함수를 선언했다.
행동을 결정할 때 SetSpawnable, SetMoveable을 먼저 호출하고 그 뒤에 SetAllNone을 호출하여 맵을 초기화하도록 함수를 구성했다.
class THEWILDCARD_API UWildMapManager : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
void GenerateMap(TSubclassOf<AWildMapBase> MapClass);
TArray<AWildTileBase*> GetInjectTiles(AWildUnitBase* Unit);
UFUNCTION(BlueprintCallable)
void SetTileSpawnable();
UFUNCTION(BlueprintCallable)
void SetTileMoveable(AWildUnitBase* Unit);
UFUNCTION(BlueprintCallable)
void SetTileAttackable(AWildUnitBase* Unit);
UFUNCTION(BlueprintCallable)
void SetAllTileNone();
UFUNCTION(BlueprintCallable)
AWildTileBase* GetTileWithCord(int x, int y);
void UWildMapManager::SetTileSpawnable()
{
TArray<AWildUnitBase*> Units = GetWorld()->GetGameInstance()->GetSubsystem<UWildUnitManager>()->PlayerUnits;
for (int i = 0; i < Units.Num(); i++)
{
TArray<AWildTileBase*> InjectTiles = GetInjectTiles(Units[i]);
for (int j = 0; j < InjectTiles.Num(); j++)
{
InjectTiles[j]->SetTileState(ETileState::Spawnable);
}
}
}
//선택한 Unit의 주변만 Moveable로 바꿔줌
void UWildMapManager::SetTileMoveable(AWildUnitBase* Unit)
{
TArray<AWildTileBase*> InjectTiles = GetInjectTiles(Unit);
for (int i = 0; i < InjectTiles.Num(); i++)
{
if (InjectTiles[i]->SpawnedUnit) continue;
InjectTiles[i]->SetTileState(ETileState::Moveable);
}
}
void UWildMapManager::SetTileAttackable(AWildUnitBase* Unit)
{
}
void UWildMapManager::SetAllTileNone()
{
for (int x = 0; x < CurrentMap->MapSize; x++)
{
for (int y = 0; y < CurrentMap->MapSize; y++)
{
CurrentMap->Tiles[x].Col[y]->SetTileState(ETileState::None);
}
}
}
UnitBase
Move의 경우 Unit의 행동이기 때문에 UnitBase에 선언한다.
CurrentTile을 비워주고 목표타일의 정보로 Unit 정보를 갱신한다. 실제 Actor의 위치도 Tile 위치로 옮겨준다.
void AWildUnitBase::MoveToTile(AWildTileBase* Tile)
{
CurrentTile->SpawnedUnit = nullptr;
CurrentTile = Tile;
CurrentCord = Tile->Cordinate;
CurrentTile->SpawnedUnit = this;
SetActorLocation(Tile->GetActorLocation());
AddActorLocalOffset(FVector(0.f, 50.f, 0.f));
GetGameInstance()->GetSubsystem<UWildMapManager>()->SetAllTileNone();
}
TileBase
실제 Move를 어디서 호출할지 생각해보면 Moveable인 Tile을 클릭했을때 실제 Move가 이뤄져야한다.
OnClick에서 State가 Moveable일때 Move를 실행하도록 한다.
결과
Spawnable은 카드를 드래그 했을때 활성화 되도록 했다.
'The Wild Card 제작' 카테고리의 다른 글
[프로젝트 관리] 카드게임 - Issue 기반 칸반보드 관리 (0) | 2025.04.16 |
---|---|
[Unreal] 카드게임 - 게임 시작 선택 구현 (0) | 2025.04.16 |
[Unreal] 카드게임 - 멀티플레이 테스트 (0) | 2025.03.30 |
[Unreal] 카드 게임 Phase 만들기(feat. State Pattern) (0) | 2025.03.21 |
[Unreal] 카드게임 - 카드로 유닛 소환 (0) | 2025.03.16 |