반응형

Paint War에서 텔레포트는 단순히 캐릭터 위치를 바꾸는 이동기가 아닙니다. 격자 규칙을 지키면서 순간 이동하고, 이동 경로에 있는 상대의 폭탄도 아군 소유로 바꾸도록 구성했습니다.

 

1. 텔레포트 거리는 타일 개수로 계산하기

격자 게임에서 월드 좌표 기준으로만 이동 거리를 정하면 타일 크기가 바뀌었을 때 결과가 어긋날 수 있습니다. 그래서 그리드가 준비되어 있으면 TileSize를 사용해 이동 거리를 계산하고, 레벨에 따라 이동할 타일 수도 달라지도록 했습니다.

private int GetCurrentTeleportTileSteps()
{
    int level = levelStats != null ? levelStats.Level : 1;
    int steps = Mathf.Max(1, teleportBaseTileSteps);
    if (level >= 3) steps++;
    if (level >= 5) steps++;
    return steps;
}

기본값이 2칸인 설정에서는 레벨 1에서 2칸, 레벨 3에서 3칸, 레벨 5에서 4칸이 됩니다. 방향 입력이 없으면 플레이어가 바라보는 방향을 대신 사용합니다.

2. 착지할 수 있는 타일을 뒤에서부터 찾기

목표 4칸 앞이 막혔다면 텔레포트를 그대로 취소해야 할까요? 현재 구현은 가장 먼 칸부터 한 칸씩 줄여 검사합니다.

for (int step = Mathf.Max(1, teleportSteps); step >= 1; step--)
{
    Vector2Int targetIndex = currentIndex + gridDirection * step;
    if (!TilePaintManager.Instance.IsTileWalkable(targetIndex) ||
        tileManager.IsHomeProtected(targetIndex) ||
        BombMine.IsBlockingTile(targetIndex))
        continue;

    if (GameRoundManager.HasInstance &&
        !GameRoundManager.Instance.CanOwnerClaimTile(owner, targetIndex))
        continue;

    targetPosition = tileManager.GetTileCenterWorldPosition(targetIndex);
    return true;
}

이렇게 하면 이동할 수 없는 타일, 보호된 본진, 폭탄이 막고 있는 타일, 현재 소유자가 접근할 수 없는 구역을 착지 후보에서 제외합니다. 착지 위치를 적용할 때는 CharacterController를 잠깐 비활성화했다가 다시 켜고, NetworkTransform.Teleport()를 호출해 순간 이동임을 알립니다.

3. 시작점과 끝점 사이의 폭탄도 검사하기

텔레포트에서 특히 중요한 부분은 도착 타일만 확인하면 중간에 통과한 폭탄을 놓친다는 점입니다. BombMine.ConvertMinesAlongTeleportPath()는 시작점과 끝점 사이를 일정 간격으로 보간하고, 경유한 타일 인덱스를 조사합니다.

float sampleDistance = Mathf.Max(0.05f, tileManager.TileSize * 0.25f);
int steps = Mathf.Max(1, Mathf.CeilToInt(distance / sampleDistance));
for (int i = 0; i <= steps; i++)
{
    Vector3 sample = Vector3.Lerp(startWorldPosition,
        endWorldPosition, i / (float)steps);
    Vector2Int sampleIndex = tileManager.GetGridIndex(sample);
    if (sampleIndex == previousIndex) continue;
    previousIndex = sampleIndex;
    convertedCount += ConvertMineAt(sampleIndex, newOwner) ? 1 : 0;
}

한 타일 안에서 여러 번 샘플링했더라도 previousIndex로 중복 처리를 피합니다. 폭탄 자체는 착지 차단 대상으로 두되, 지나가는 경로에서는 소유권 전환 대상으로 취급한 것입니다.

4. 멀티플레이어에서는 결과도 공유해야 합니다

로컬에서만 폭탄 소유자를 변경하면 다른 클라이언트에는 이전 소유자가 남을 수 있습니다. 그래서 서버에서는 경로의 폭탄을 변환한 뒤, 변경된 경우 ObserversConvertTeleportPathBombMines()를 통해 관찰 클라이언트에 알립니다. 이동 이펙트 역시 서버 RPC와 Observers RPC 경로가 구분되어 있습니다.


정리

텔레포트의 핵심은 단순한 위치 이동보다 어디에 착지할 수 있는지, 지나간 타일에서 어떤 효과를 적용할지, 그 결과를 누가 결정해 공유할지에 있었습니다. 거리·타일 검증·폭탄 전환·네트워크 표시를 서로 다른 함수로 나누어 처리했습니다.


참고한 구현 코드

반응형