[타워디펜스게임] #12. 몬스터 공격 범위

치치·2025년 2월 15일
0

타워디펜스게임

목록 보기
12/18
post-thumbnail

오늘의 목표

몬스터의 공격범위를 구현한다.
몬스터의 공격범위에 유닛이 있을경우, 공격이 활성화되어 유닛에게 데미지를 입히고 애니메이션이 실행된다.
몬스터의 공격범위에 유닛이 없어질 경우, 다시 공격 비활성화 상태, 애니메이션 중지



몬스터들의 공격 범위

몬스터가 현재는 2마리 뿐이므로, 일단 공격범위 1칸짜리인 몬스터들만 적용하였다
-> 나중에 더 추가 될 예정이다

구현 방법

처음에 공격범위를 어떤 방식으로 설정할 지 고민하였다. 기획자님이 주신 아이디어로는 그리드 단위로 되어있기 때문에, 유닛이 배치된 타일을 기준으로 앞에 칸들을 다 공격범위로 설정해보라고 했다

하지만 타일맵으로 구성된 게 아니고, 몬스터도 그리드에 배치되는 느낌이 아니기 때문에 공격범위에 들어온 유닛들을 판단하기 위해 더 찾아보았다.

그리고 선택한 것이 Overlap

공격범위에 유닛이 있는지를 확인하기 위해 Overlap메서드를 사용하였다

Overlap

지정된 범위 내부에 있는 원하는 오브젝트를 찾을 수 있는 기능이다

Overlap의 모양은 다양하지만, 이 게임은 그리드 단위이기 때문에 Box형을 택했다

  • 몬스터의 공격범위에 있는 모든 유닛들을 찾아야하기 때문에 OverlapBoxAll을 사용하겠다

  • 사용방법 : Physics2D.OverlapBoxAll(플레이어,범위,레이어 선택(해당 레이어만 감지));
    -> 현재 레이어 10은 Object로 유닛으로 지정되있음

  • 감지된 유닛들을 배열에 저장한다
    -> 감지된 유닛의 태그가 Unit이 맞다면 공격!
    -> 데미지를 입힐 수 있다. 이 데미지는 각각의 UnitStat 클래스의 TakeDamage 함수를 호출하고 스탯에 영향을 미친다

  • 실제 Scene 창에서 공격범위를 보이기 위해서 Gizmo를 사용하였다
    -> Gizmo는 Scene창에서만 보인다. 공격범위 확인을 위해서 사용



Monster1Gizmo 스크립트 전체 코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


// 쿠션더미(일반형) (범위 한칸)
public class Monster1Gizmo : MonoBehaviour
{
    public Transform Pos;
    private Vector2 BoxSize = new Vector2(2.8f, 1.3f);
    private Vector2 Offset = new Vector2(-0.8f, 0f);

    Monster1Anime Monster1Anime;

    public float attackCooldown = 5.0f; // 공격 주기 (초 단위)
    private float lastAttackTime = -1.0f; // 마지막 공격 시점


    bool previousState = false; // 이전 상태를 저장

    public int damage = 6;
    private void Start()
    {
        Monster1Anime = GetComponent<Monster1Anime>();
    }
    void Update()
    {
        Vector2 boxCenter = (Vector2)Pos.position + Offset;

        // 카메라의 뷰포트 좌표를 가져오기
        Camera mainCamera = Camera.main;
        Vector3 viewportPosition = mainCamera.WorldToViewportPoint(boxCenter);

        if (viewportPosition.x >= 0 && viewportPosition.x <= 1 && viewportPosition.y >= 0 && viewportPosition.y <= 1)
        {

            // OverlapBoxAll(시작위치, 박스크기, 레이어)
            Collider2D[] collider2Ds = Physics2D.OverlapBoxAll(boxCenter, BoxSize, 10);
            
            bool unitDetected = false;

            foreach (Collider2D collider in collider2Ds)
            {
                if (collider.CompareTag("Unit"))
                {
                    Debug.Log("유닛과 충돌");

                    // 공격 쿨다운 확인
                    if (Time.time - lastAttackTime >= attackCooldown)
                    {
                        // 충돌된 대상에서 UnitStat 가져오기
                        UnitStat unitStat = collider.GetComponent<UnitStat>();

                        if (unitStat != null)
                        {
                            if (unitStat is Unit00010 unit1Stat)
                            {
                                unit1Stat.TakeDamage(damage);
                                Debug.Log("Unit00010에게 데미지 전달됨");
                            }
                            else if (unitStat is Unit00020 unit2Stat)
                            {
                                unit2Stat.TakeDamage(damage);
                                Debug.Log("Unit00020에게 데미지 전달됨");
                            }
                        }

                        // 마지막 공격 시간 갱신
                        lastAttackTime = Time.time;
                    }

                    unitDetected = true; // 유닛을 감지한 상태로 변경
                    break; // 한 번만 처리 후 루프 탈출
                }
            }
            // 이전 상태와 현재 상태가 다를 경우에만 애니메이션 호출
            if (unitDetected != previousState)
            {
                if (unitDetected)
                {
                    Monster1Anime.StartAttack(); // 공격 애니메이션
                }
                else
                {
                    Monster1Anime.EndAttack(); // Idle 애니메이션
                }

                previousState = unitDetected; // 상태 업데이트
            }
        }
        else
        {
            //Debug.Log("충돌 범위가 카메라 화면 밖입니다.");
        }
    }

    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube((Vector2)Pos.position + Offset, BoxSize);
    }
}
  • Monster2Gizmo 스크립트도 내용은 동일하다

아쉬운 점

지금 유닛과 충돌하여 데미지를 입히는 부분이 모든 유닛에 관해 따로따로 설정하고 있어서 유닛이 많아질수록, 이부분에 계속 추가되야한다,,,
유닛이 막 10개 이렇게 되버리면 코드가 너무 길어지고 지저분해진다

profile
뉴비 개발자

0개의 댓글