타워배치, 타워 공격(연습)

suhan cho·2022년 8월 4일
0

타워를 놓을 자리 생성

  • TileWall 오브젝트 생성 후 나중에 3차원 충돌을 위해 Box Collider놓는다
  • 타일팔레트로 prefeb brush인 TileWall생성
  • 외곽부분 색칠

  • 스프라이트 에디터에서 원 부분이 중심에 갈 수 있도록 피벗을 설정

  • 트랜스폼 초기화 후 크기 바꿔주고 order in layer 1로 설정

spawner작성

  • spwanTower을 Instatiate로 작성 후

  • 오브젝트 생성후 집어넣는다

  • add tag로 Tile 테그 생성
  • Tile wall prefeb의 태그를 Tile로 변경

마우스 클릭으로 오브젝트 선택


타워의 공격대상 설정

  • 충돌범위 수정(radius)
  • 순서 1로 , 중력 0으로

EnemySpawner 수정

  • 리스트 변수 선언 private List ~
  • 메모리 할당 listName = new List\() 등 리스트 함수 볼것
  • 적의 정보를 리스트에 담고 적이 죽었을 때 리스트에서 삭제

Enemy수정

  • 기존의 Destroy를 주석처리하고 OnDie()를 만든다.
  • EnemySpanwer에서 관리하므로 EnemySpawner에 있는 DestroyEnemy메소드를 이용

발사체 나가게 수정

  • Fish1 프리펩에 빈오브젝트 생성하고 이걸로 발사 위치를 조정

TowerWeapon 작성

//공격 대상을 찾는 searchtarget, 대상을 공격하는 attacktotarget 생성
public enum WeaponState {  SearchTarget = 0, AttackToTarget }

public class TowerWeapon : MonoBehaviour
{
    [SerializeField]
    private GameObject projectilePrefeb;    //발사체 프리펩
    [SerializeField]
    private Transform spawnPoint;   // 발사체 생성 위치
    [SerializeField]
    private float attackRate = 0.5f;    // 공격속도
    [SerializeField]
    private float attackRange = 2.0f;   //공격범위
    private WeaponState weaponState = WeaponState.SearchTarget; // 타워 무기의 상태
    private Transform attackTarget = null;  // 공격 대상
    private EnemySpawner enemySpawner;  // 게임에 존재하는 적 정보 흭득용

    public void Setup(EnemySpawner enemySpawner)
    {
        this.enemySpawner = enemySpawner;
        // 최초 상태를 WeaponState.SearchTarget으로 생성
        ChangeState(WeaponState.SearchTarget);

    }
    
    // 이전에 실행중인 코루틴을 종료하고 새로운 상태의 코루틴 실행
    public void ChangeState(WeaponState newState)
    {
        //이전에 재생중이던 상태 종료
        StopCoroutine(weaponState.ToString());
        //상태 변경
        weaponState = newState;
        // 새로운 상태 재생
        StartCoroutine(weaponState.ToString());

    }

    private void Update()
    {
        //target이 null아니면 target을 바라보게 한다
        if (attackTarget != null)
        {
            RotateToTarget();
        }
    }

    private void RotateToTarget()
    {
        // 원점으로부터의 거리와 수평축으로부터의 각도를 이용해 위치를 구하는 극 좌표계 이용
        // 각도 = arctan(y/x)
        // x,y 변위값 구하기
        float dx = attackTarget.position.x - transform.position.x;
        float dy = attackTarget.position.y - transform.position.y;

        // x,y 변위값을 바탕으로 각도 구하기
        // 각도가 radian 단위이기 떄문에 Mathf.Rad2Deg를 곱해 도 단위를 구함
        float degree = Mathf.Atan2(dy, dx) * Mathf.Rad2Deg;
        transform.rotation = Quaternion.Euler(0, 0, degree);
    }

    private IEnumerator SearchTarget()
    {
        while(true)
        {
            // 제일 가까이 있는 적을 찾기 위해 최초 거리를 최대한 크게 설정
            float closesDistSqr = Mathf.Infinity;
            //EnemySpanwer의 EnemyList에 있는 현재 맵에 존재한느 모든 적 검사
            for(int i =0; i < enemySpawner.EnemyList.Count; ++i)
            {
                float distance = Vector3.Distance(enemySpawner.EnemyList[i].transform.position, transform.position);
                // 현재 검사중인 적과의 거리가 공격범위 내에 있고, 현재 검사한 적보다 거리가 가까우면
                if( distance <= attackRange && distance <= closesDistSqr)
                {
                    closesDistSqr = distance;
                    attackTarget = enemySpawner.EnemyList[i].transform;
                }

            }
            
            if(attackTarget != null)
            {
                ChangeState(WeaponState.AttackToTarget);
            }

            yield return null;
        }
    }

    private IEnumerator AttackToTarget()
    {
        while(true)
        {
            // 1. target이 있는지 검사 (다른 발사체에 의해 제거, Goal 지점까지 이동해 삭제 등)
            if (attackTarget == null)
            {
                ChangeState(WeaponState.SearchTarget);
                break;
            }

            // 2. target이 공격 범위 안에 있는지 검사 (공격 범위를 벗어나면 새로운 적 탐색)
            float distance = Vector3.Distance(attackTarget.position, transform.position);
            if(distance > attackRange)
            {
                attackTarget = null;
                ChangeState(WeaponState.SearchTarget);
                break;
            }

            // 3. attackRate 시간만큼 대기
            yield return new WaitForSeconds(attackRate);

            // 4. 공격(발사체 생성)
            SpawnProjectile();
        }
    }

    private void SpawnProjectile()
    {
        //스폰포인트 위치에서 발사체 생성
        Instantiate(projectilePrefeb, spawnPoint.position, Quaternion.identity);
    }
}

Tile 작성

TowerSpanwer수정(타일 위에 중복 안되게)

Projectile 작성

TowerWeapon수정

public class TowerWeapon : MonoBehaviour
{
    [SerializeField]
    private GameObject projectilePrefeb;    //발사체 프리펩
    [SerializeField]
    private Transform spawnPoint;   // 발사체 생성 위치
    [SerializeField]
    private float attackRate = 0.5f;    // 공격속도
    [SerializeField]
    private float attackRange = 2.0f;   //공격범위
    private WeaponState weaponState = WeaponState.SearchTarget; // 타워 무기의 상태
    private Transform attackTarget = null;  // 공격 대상
    private EnemySpawner enemySpawner;  // 게임에 존재하는 적 정보 흭득용

    public void Setup(EnemySpawner enemySpawner)
    {
        this.enemySpawner = enemySpawner;
        // 최초 상태를 WeaponState.SearchTarget으로 생성
        ChangeState(WeaponState.SearchTarget);

    }
    
    // 이전에 실행중인 코루틴을 종료하고 새로운 상태의 코루틴 실행
    public void ChangeState(WeaponState newState)
    {
        //이전에 재생중이던 상태 종료
        StopCoroutine(weaponState.ToString());
        //상태 변경
        weaponState = newState;
        // 새로운 상태 재생
        StartCoroutine(weaponState.ToString());

    }

    private void Update()
    {
        //target이 null아니면 target을 바라보게 한다
        if (attackTarget != null)
        {
            RotateToTarget();
        }
    }

    private void RotateToTarget()
    {
        // 원점으로부터의 거리와 수평축으로부터의 각도를 이용해 위치를 구하는 극 좌표계 이용
        // 각도 = arctan(y/x)
        // x,y 변위값 구하기
        float dx = attackTarget.position.x - transform.position.x;
        float dy = attackTarget.position.y - transform.position.y;

        // x,y 변위값을 바탕으로 각도 구하기
        // 각도가 radian 단위이기 떄문에 Mathf.Rad2Deg를 곱해 도 단위를 구함
        float degree = Mathf.Atan2(dy, dx) * Mathf.Rad2Deg;
        transform.rotation = Quaternion.Euler(0, 0, degree);
    }

    private IEnumerator SearchTarget()
    {
        while(true)
        {
            // 제일 가까이 있는 적을 찾기 위해 최초 거리를 최대한 크게 설정
            float closesDistSqr = Mathf.Infinity;
            //EnemySpanwer의 EnemyList에 있는 현재 맵에 존재한느 모든 적 검사
            for(int i =0; i < enemySpawner.EnemyList.Count; ++i)
            {
                float distance = Vector3.Distance(enemySpawner.EnemyList[i].transform.position, transform.position);
                // 현재 검사중인 적과의 거리가 공격범위 내에 있고, 현재 검사한 적보다 거리가 가까우면
                if( distance <= attackRange && distance <= closesDistSqr)
                {
                    closesDistSqr = distance;
                    attackTarget = enemySpawner.EnemyList[i].transform;
                }

            }
            
            if(attackTarget != null)
            {
                ChangeState(WeaponState.AttackToTarget);
            }

            yield return null;
        }
    }

    private IEnumerator AttackToTarget()
    {
        while(true)
        {
            // 1. target이 있는지 검사 (다른 발사체에 의해 제거, Goal 지점까지 이동해 삭제 등)
            if (attackTarget == null)
            {
                ChangeState(WeaponState.SearchTarget);
                break;
            }

            // 2. target이 공격 범위 안에 있는지 검사 (공격 범위를 벗어나면 새로운 적 탐색)
            float distance = Vector3.Distance(attackTarget.position, transform.position);
            if(distance > attackRange)
            {
                attackTarget = null;
                ChangeState(WeaponState.SearchTarget);
                break;
            }

            // 3. attackRate 시간만큼 대기
            yield return new WaitForSeconds(attackRate);

            // 4. 공격(발사체 생성)
            SpawnProjectile();
        }
    }

    private void SpawnProjectile()
    {
        //스폰포인트 위치에서 발사체 생성
        GameObject clone = Instantiate(projectilePrefeb, spawnPoint.position, Quaternion.identity);
        // 셍성된 발사체에게 공격대상(attackTarget)정보 제공
        clone.GetComponent<Projectile>().Setup(attackTarget);
    }
}

출처: https://www.youtube.com/watch?v=UIxzwEnjkqg&list=PLC2Tit6NyVicvqMTDJl8e-2IB4v_I7ddd&index=10

profile
안녕하세요

0개의 댓글