Unity 본캠프 4일차 - 미니 프로젝트

한예준·2025년 4월 10일

오늘은 어제에 이어서 랜덤 타워 디펜스 게임을 모방한 구현을 계속해보려고 한다.


진행 내역

  • 타워 랜덤 생성 시스템

    • 플레이어는 일정 재화를 소모해 노말 등급의 랜덤 타워를 구매할 수 있다.
    • 구매한 타워는 빈 타일에만 배치할 수 있다.
  • 웨이브 시스템 기본 구조

    • 각 웨이브마다 체력 20짜리 적 유닛이 30기 등장한다.
    • 적이 특정 지점에 도달하면 플레이어 체력이 감소하는 시스템(추후 추가 예정)이 있다.
    • 10웨이브마다 보스가 등장하는 기능도 곧 넣을 예정이다.
    • 웨이브 종료 시 일정 재화를 획득할 수 있다.
  • 적 이동 경로 시스템

  • PathManager를 통해 적 이동 경로를 설정하며, 게임 시작 후 지정된 경로대로 적이 이동한다.


오늘 해볼 작업

어제 구현한 내용을 기반으로, 오늘은 다음 작업들을 진행해보겠다.

  • 타워의 공격 로직 구현

    • 범위 내 적 탐지 → 타겟 지정 → 투사체 발사
    • 공격 속도, 사거리, 공격 방식을 설정할 수 있도록 설계
  • 적의 체력/피격 시스템

    • 타워로부터 받은 피해를 누적하여, 체력이 0 이하가 되면 적을 제거
  • 투사체 시스템

    • 기본 투사체를 생성하고, 적과 충돌 시 피해를 전달
    • 공격력 및 추가 기능을 확장할 수 있게 설계
  • 타워 업그레이드 시스템

    • 같은 종류이면서 같은 등급의 타워 2개를 조합하면 다음 등급의 랜덤 타워로 업그레이드
    • 타워 등급은 최대 5등급까지 지원
    • 각 등급별 능력치 조정값은 추후 계산해볼 예정

타워의 공격 로직 구현

  • Tower.cs에서는 매 프레임마다 공격 쿨타임을 체크하고, 범위 내 적이 발견되면 투사체를 생성하여 공격하는 구조를 사용한다. 아래는 핵심 코드와 각 줄에 대한 설명이다.

void Update()
{
    attackCooldown -= Time.deltaTime;

    if (attackCooldown <= 0f)
    {
       GameObject target = FindTarget();
        if (target != null)
        {
            Attack(target);
            attackCooldown = 1f / attackRate;
        }
    }
}

void Attack(GameObject target)
{
    GameObject projectile = Instantiate(projectilePrefab, firePoint.position, Quaternion.identity);
    projectile.GetComponent<Projectile>().SetTarget(target);
}
  • attackCooldown -= Time.deltaTime;
    매 프레임마다 남은 공격 대기 시간을 줄여준다.

  • if (attackCooldown <= 0f)
    쿨타임이 0 이하일 때만 공격을 수행할 수 있게 검사한다.

  • GameObject target = FindTarget();
    사거리 내 있는 적 중 가장 가까운 적을 찾는데, FindTarget() 함수는 과거 범위 공격 투사체 코드를 응용해 구현했다.

즉, 타워는 attackCooldown이 0 이하가 될 때마다 주변 적들을 탐지하고, 타겟이 존재하면 Attack()을 호출해 투사체를 생성해 공격하는 구조다. 공격 속도는 attackRate로 조절하며, 발사 지점은 firePoint를 기준으로 한다.


투사체 시스템

Projectile.cs에서는 투사체가 지정된 타겟을 향해 이동하면서 일정 거리 내 도달하면 적에게 피해를 주고 스스로 소멸된다.

void Update()
{
    if (target == null)
    {
        Destroy(gameObject);
        return;
    }

    Vector2 direction = (target.position - transform.position).normalized;
    transform.position += (Vector3)direction * speed * Time.deltaTime;

    if (Vector2.Distance(transform.position, target.position) < 0.1f)
    {
        target.GetComponent<Enemy>()?.TakeDamage(1);
        Destroy(gameObject);
    }
}
  • if (target == null)
    타겟이 사라지면 투사체는 의미가 없으므로 즉시 파괴한다.

  • Vector2 direction = (target.position - transform.position).normalized;
    타겟 방향으로의 이동 방향을 구한다.

  • transform.position += ...
    구한 이동 방향에 속도와 시간을 곱해 투사체를 타겟쪽으로 이동시킨다.

  • if (Vector2.Distance(transform.position, target.position) < 0.1f)
    투사체와 타겟의 거리가 0.1보다 작아지면 투사체를 파괴한다.


Enemy 오브젝트의 체력/피격/파괴 시스템

Enemy.cs에서는 적의 체력을 관리하며, TakeDamage() 메서드를 통해 피해를 받는다. 체력이 0 이하가 되면 적은 제거된다.


void Start()
{
    currentHealth = maxHealth;
}

public void TakeDamage(int damage)
{
    currentHealth -= damage;
    if (currentHealth <= 0)
    {
        Die();
    }
}

void Die()
{
    Destroy(gameObject);
}
  • currentHealth = maxHealth;
    게임 시작 시 현재 체력을 최대 체력으로 초기화한다.

  • public void TakeDamage(int damage)
    외부에서 호출되어 피해를 받으면 현재 체력을 감소시킨다.

  • if (currentHealth <= 0)
    체력이 0 이하가 되면 사망 처리로 넘어간다.

  • void Die()
    적 오브젝트를 게임에서 제거한다.

이후 Projectile.cs의 충돌 처리 스크립트에 Takedamage()함수를 추가하여 Enemy 오브젝트에 Damage가 가해지도록 추가했다.


타워 업그레이드 시스템(추후 추가 예정)

같은 종류이면서 같은 등급의 타워 2개를 결합하면, 하나로 합쳐져 다음 등급의 랜덤 타워로 업그레이드된다.

타워의 등급은 최대 5등급까지 있으며, 각 등급별 능력치 조정값은 추후에 계산해볼 예정이다.


회고

오늘은 타워 디펜스 게임의 핵심 시스템들을 구현해보았다.

  • 매 프레임마다 타워가 주변 적을 감지한다.

  • 공격 쿨타임이 끝나면, 타겟이 있을 때 투사체를 생성해 공격을 실행한다.

  • 투사체는 타겟을 향해 이동하며 일정 거리 내 도달 시 적에게 피해를 전달하고 소멸한다.

  • 적은 피해를 누적해 체력이 0 이하로 떨어지면 스스로 제거된다.

  • 오늘 작업에서 두 가지 오류를 겪었는데,

    • FindTarget() 함수에서 return 경로가 누락되어 컴파일 에러(CS0161)가 발생했는데, return null;을 추가해 해결했다.
    • TowerSpawner.Instancenull로 잡히는 문제는 싱글톤 설정 시 Awake() 안에서 조건문 내에 Instance = this;를 놓친 것이 원인이었는데, 이를 수정해서 안정적으로 등록되도록 했다.

작은 디테일 하나하나가 실제 게임 플레이에 큰 영향을 준다는 걸 다시 한 번 느낄 수 있었다. Tower가 자동으로 적의 위치를 감지하는 스크립트를 작성할 때는 투사체 발사 프로젝트를 만들 때 범위공격하는 로직을 응용해보았다. 하지만 그 방향으로 투사체를 발사하는 스크립트를 작성할 때는 어떻게 건드려야 할 지 감이 안왔는데, normalized 를 통해 방향을 구할 수 있다는 사실을 배웠다. 이를 통해 자동 감지하여 발사하는 로직을 응용해볼 수 있겠다. (예: 뱀파이어 서바이벌류 게임 시스템, 유도탄 시스템 등)

0개의 댓글