
가디언 앤 시커는 퍼즐과 RPG의 융합을 통해 전략적 성장의 재미를 제공합니다. 씨커 플레이어는 클래스 별 아케인 보드에 다양한 모양의 룬을 배치하여 스탯을 커스터마이징하고, 자신만의 빌드를 구축할 수 있습니다. 제한된 공간에서 최적의 조합을 찾는 전략적 선택이 승패를 좌우합니다.
- 그리드 보드에 테트리스 모양의 룬 블록 배치
- 각 룬은 고유한 스탯 효과를 제공 (ATK, DEF, HP, AGL, ATS)
- 드래그 앤 드롭 방식의 직관적인 룬 배치 시스템
- 특수 셀과 연결된 룬은 추가 보너스 스탯 획득
- 실시간 스탯 계산 및 UI 업데이트
- 클래스별 전용 그리드 레이아웃으로 차별화된 전략 제공
- 로컬 저장/로드 시스템으로 빌드 유지
이 시스템을 통해 씨커 플레이어들은 단순한 스탯 강화를 넘어서, 자신만의 독특한 전략과 플레이 스타일을 구현할 수 있는 깊이 있는 성장 시스템을 경험할 수 있습니다.
컨텐츠 진화 과정
프로토타입: 마우스 위치 기준 단순 좌표 계산
→ 마우스 아래 그리드 셀을 (0,0)으로 하여 룬 Shape 오프셋 계산
중간 발표: 스마트 배치 시스템 도입
→ 마우스 위치에서 가능한 모든 배치 후보 중 최적 위치 자동 선택
최종 구현: 직관적 드래그 비주얼 시스템
→ 드래그 위젯을 룬 모양대로 생성된 그리드로 구현하여 배치 예측성 향상
→ 룬별 마우스 커서 제어와 복잡한 배치 검증 로직 문제 완전 해결
룬 시스템은 아케인 보드 매니저(UGS_ArcaneBoardManager), UI 위젯들, 로컬 플레이어 서브시스템(UGS_ArcaneBoardLPS)로 구성됩니다.


→ 마우스 아래 그리드 셀을 (0,0)으로 하여 룬 Shape 오프셋 계산
룬의 모양은 TMap<FIntPoint, UTexture2D*> 구조로 저장되어 있습니다. 예를 들어 L자 형태의 룬은 3개의 Fragment로 구성됩니다: (0,0), (1,0), (1,1) 좌표에 각각 다른 텍스처 조각이 할당되어 있습니다.
// 룬 배치 검증 로직
FIntPoint CellPos = TargetCell->GetCellPos(); // 마우스 클릭 위치
for (const FIntPoint& Offset : RuneShape)
{
FIntPoint FinalPos = CellPos + Offset; // 기준점 + 오프셋
if (!IsValidCell(FinalPos)) return false; // 유효성 검사
}
플레이어가 마우스로 룬을 그리드 위에 드래그하면, 마우스 커서 아래 그리드 셀을 기준점(0,0)으로 잡고 Offset을 계산합니다:
배치가 가능한 그리드 셀을 클릭하면 각 그리드 셀의 텍스처 이미지를 해당 룬의 텍스처로 렌더링합니다.
![]() | ![]() |
|---|
![]() | ![]() | ![]() |
|---|
→ 마우스 위치에서 가능한 모든 배치 후보 중 최적 위치 자동 선택
클릭한 셀을 포함할 수 있는 모든 가능한 배치 위치를 계산하고, 그 중 가장 직관적인 위치를 자동 선택하는 시스템을 구현했습니다.
bool FindOptimalPlacementPosition(uint8 RuneID, const FIntPoint& ClickedCell, FIntPoint& OutBestPosition)
{
TArray<FIntPoint> ValidPositions;
// 룬의 각 셀에 대해 클릭한 셀이 해당 위치에 올 수 있는지 확인
for (const FIntPoint& ShapeOffset : RuneShape)
{
FIntPoint CandidatePosition = ClickedCell - ShapeOffset;
if (CanPlaceRuneAt(RuneID, CandidatePosition))
{
ValidPositions.Add(CandidatePosition);
}
}
// 우선순위 선택: 룬의 좌상단([0,0])에 가까운 순서
for (const FIntPoint& Position : ValidPositions)
{
FIntPoint ShapeOffset = ClickedCell - Position;
// Y좌표가 작을수록, 같다면 X좌표가 작을수록 우선
if (ShapeOffset.Y < BestShapeOffset.Y ||
(ShapeOffset.Y == BestShapeOffset.Y && ShapeOffset.X < BestShapeOffset.X))
{
OutBestPosition = Position;
}
}
}

![]() | ![]() |
|---|
→ 드래그 위젯을 룬 모양대로 생성된 그리드로 구현하여 클릭한 보드 그리드 셀과 룬 드래그 위젯의 커서가 위치한 셀을 일치시켜서 보이는 그대로 배치
기존의 단일 이미지 + 복잡한 오프셋 계산 방식을 버리고, 드래그 비주얼 자체를 룬 모양에 맞는 그리드로 생성하는 방식으로 전환했습니다.
// 기존: 단일 이미지
UImage* RuneImage;
// 새로운: 룬 모양 그리드
UUniformGridPanel* RuneGridPanel;
TMap<FIntPoint, UImage*> GridCellWidgets; // 각 셀별 위젯
룬의 기준셀(0,0)이 항상 마우스 커서에 위치되도록 구현했습니다.
void UGS_DragVisualWidget::CalculateInitReferenceCellOffset()
{
if (CachedRuneShape.Contains(ReferenceCellPos) && CellToGridPosMap.Contains(ReferenceCellPos))
{
FIntPoint ActualGridPos = CellToGridPosMap[ReferenceCellPos];
FVector2D ActualCellSize = BaseCellSize * CurrentScaleFactor;
// 기준셀의 중심점을 마우스 커서에 맞춤
FVector2D BaseOffset = FVector2D(
ActualGridPos.Y * ActualCellSize.X + ActualCellSize.X * 0.5f,
ActualGridPos.X * ActualCellSize.Y + ActualCellSize.Y * 0.5f
);
ReferenceCellOffset = BaseOffset;
}
}
룬 테이블에서 마우스 커서가 위치하길 원하는 룬의 그리드 위치 좌표를 0,0으로 설정해주면 어떤 모양의 룬이 생성되더라도 0,0으로 지정해준 룬의 그리드 위치에 마우스 커서가 위치합니다.
복잡한 예측 계산을 제거하고 직관적인 배치 로직으로 변경했습니다.
// 기존: 복잡한 예측 계산
FIntPoint OptimalPos;
if (BoardManager->FindOptimalPlacementPosition(SelectedRuneID, ClickedCellPos, OptimalPos))
// 새로운: 단순한 직접 배치
FIntPoint PlacementPos = TargetCell->GetCellPos(); // 마우스 위치 = 배치 위치
if (BoardManager->CanPlaceRuneAt(SelectedRuneID, PlacementPos))

✅ 시각적으로 보이는 그대로 기능하여 배치 예측성 향상
✅ 룬별 드래그 위젯의 마우스 커서 위치 문제와 복잡한 배치 검증 로직 문제 완전 해결