개발 일지/2D 타워 디펜스

[Unity] Tower Defense 게임 개발 일지 #1

임녕 2025. 3. 30. 19:49

개요

개발 과정을 간단하게라도 문서화하고 새로 알게 된 정보를 기록하고자 일지를 써보기로 했습니다.

혼자 만들다보니 진행 과정에서 초기 기획과 많이 달라질 수도 있지만

지금 당장 생각하고 있는 컨셉은 '방치 안하는 타워 디펜스' 게임 입니다.

 

* 간단하게 구현해본 예상 게임 화면 입니다.

 

주요 컨셉

- 적은 시작 지점에서 생성되어 도착 지점에 도착하면 사라진다. 이 때 놓친 적의 수가 일정 수치를 초과하면 패배

- 기본적으로 공격은 자동이지만 스킬 사용은 타워마다 특정 키를 눌러서 사용한다. (키 코드는 랜덤하게 부여)

 

우선은 이 두 가지를 핵심으로 개발을 진행할 생각입니다.

 

Tilemap

배경은 타일맵으로 만들었습니다. 최하단 배경, 적이 이동할 길, 최상단에 올라올 오브젝트 이렇게 3단으로 구성했습니다.

 

EnemySpawner (Object Pooling)

적을 스폰하는 스크립트 입니다. 디펜스 게임인 만큼 적이 얼마나 스폰될지 모르기 때문에 과도한 Instantiate를 방지하고자 Object Pooling을 사용했습니다.

 

void Start()
{
    for (int i = 0; i < poolSize; i++)
    {
        GameObject enemy = Instantiate(enemyPrefab, this.transform);
        enemy.SetActive(false);
        enemyPool.Enqueue(enemy);
    }
}

 

최초 poolSize 만큼 GameObject를 생성하여 Queue에 넣어둡니다.

 

public GameObject GetEnemy()
{
    if (enemyPool.Count > 0)
    {
        GameObject enemy = enemyPool.Dequeue();
        enemy.SetActive(true);
        return enemy;
    }
    else
    {
        GameObject enemy = Instantiate(enemyPrefab, this.transform);
        return enemy;
    }
}

 

필요할 때 GetEnemy를 호출하여 Queue에 남아있는 GameObject가 있다면 Queue에서 꺼내어 return 해주고 없다면 새로 생성하여 return 해줍니다.

 

public void ReturnToPool(GameObject enemy)
{
    enemy.SetActive(false);
    enemyPool.Enqueue(enemy);
}

 

동작을 마친 GameObject는 ReturnToPool의 Parameter(매개변수)로 전달되어 다시 Queue에 들어가게 됩니다.

 

위 영상처럼 Object Pool 내에 있는 모든 GameObject를 사용 중이라면 새로운 GameObject를 Intantiate하고 남은 GameObject가 있다면 큐에 들어온 순서대로 다시 재사용합니다.

 

적의 이동

public void Init()
{
    waypointIndex = 0;
    waypoints = EnemySpawner.instance.waypoints;
    gameObject.transform.localPosition = waypoints[0];
}

...

void Update()
{
    if (waypointIndex == waypoints.Count)
    {
        EnemySpawner.instance.ReturnToPool(gameObject);
    }
    if (waypointIndex < waypoints.Count)
    {
        transform.position = Vector3.MoveTowards(transform.position, waypoints[waypointIndex], moveSpeed * Time.deltaTime);
        if (Vector3.Distance(transform.position, waypoints[waypointIndex]) < 0.1f)
        {
            waypointIndex++;
        }
    }
}

 

GameObject가 활성화 될 때 Waypoint 정보를 불러온 후 Waypoint 0번부터 순서대로 따라가도록 만들었습니다. 마지막 Waypoint에 도착하면 Object Pool로 다시 들어가게 됩니다.

 

경로는 현재 Spawner에서 List<Vector3>로 방향 전환이 필요한 점들을 저장하고 있습니다. 추후에 더 나은 방법을 찾으면 수정할 예정입니다.