Skip to content

develop Enemy Spawn, Movement

Jeon-YJ1004 edited this page Jun 9, 2023 · 11 revisions

리팩토링 이전

로직

  1. 적 sprite 준비. 에셋 스토어 1-1. 추가로 박쥐 sprite를 만들었습니다.
  2. 적 애니메이션 설정하기.
  3. 씬에 프리펩들을 저장할 배열 변수 선언 => PoolManager 생성 3-1. pool manager 스크립트 작성.
  4. 씬에 플레이어나 맵, 몬스터 재배치를 위한 스크립트인 GameManager 생성. PoolManager를 게임 전체에 사용할 수 있게 GameManager에 선언.
  5. --Enemies--에 소환 스크립트인 Enemy Spawner 추가

적 만들기

  1. 플레이어 추적 로직
  • 타겟 위치 - 나의 위치 = 위치 차이
  • 위치 차이의 정규화 = 방향
  • 프레임의 영향으로 결과가 달라지지 않도록 FixedDeltaTime 사용
  • 플레이어의 키 입력 값을 더한 이동 = 적의 방향 값을 더한 이동
 void FixedUpdate()
    {
        //몬스터가 살아 있을 때만 움직이도록 
        if (!isLive) return;

        Vector2 direction = (target.position - rb.position).normalized;
        Vector2 nextVec = direction * speed * Time.fixedDeltaTime; ;

        //플레이어의 키입력 값을 더한 이동=몬스터의 방향 값을 더한 이동
        rb.MovePosition(rb.position + nextVec);

        //물리 속도가 이동에 영향을 주지 않도록 속도 제거
        rb.velocity = Vector2.zero;
    }
  1. 적 스폰하기
  • 플레이어의 위치 값에 랜덤 값을 더해 적 스폰 지점 생성
 private void Spawn()
    {
        //player의 위치 값에 랜덤 pos를 더해 스폰 지점 설정
        Vector3 position = GenerateRandomPos();
        position += player.transform.position;

        GameObject newEnemy= GameManager.instance.pool.Get(0);
        newEnemy.transform.position = position;
        newEnemy.transform.parent = transform;
        newEnemy.GetComponent<Enemy>().Init(spawnData[level]);
    }

    private Vector3 GenerateRandomPos()
    {
        Vector3 position = new Vector3();
        float f = UnityEngine.Random.value > 0.5f ? -1f : 1f;
        if (UnityEngine.Random.value > 0.5f)
        {
            position.x = UnityEngine.Random.Range(-spawnArea.x, spawnArea.x);
            position.y = spawnArea.y * f;
        }
        else
        {
            position.y = UnityEngine.Random.Range(-spawnArea.y, spawnArea.y);
            position.x = spawnArea.x * f;
        }
        position.z = 0;
        return position;
    }
}
  1. 소환 레벨 적용하기
  • GameManager에 게임 시간과 최대게임 시간 변수 선언
 private void Update()
    {

        gameTime += Time.deltaTime;
        if (gameTime >maxGameTime)
        {
            gameTime = maxGameTime;
        }
    }
  • EnemySpawner에 시간에 맞춰 레벨이 올라가도록 작성
  • 적의 타입 클래스 생성 후 직력화하여 --Enemy-- 인스펙터에서 초기화

image

  • Enemy 스크립트에 RuntimeAnimatorController 배열 선언하여 각각의 애니메이션 선택
  • Enemy 스크립트의 Init 함수 생성하여 애니네이션과 SpawnData에서 사용할 변수 초기화
[System.Serializable]
public void Init(SpawnData data)  //각각의 몬스터 데이터 설정 함수
    {
        anim.runtimeAnimatorController = animcon[data.spriteType];
        speed = data.speed;
        maxHealth = data.health;
        health = data.health;
    }
  • EnemySpawner 스크립트에 timer 변수 생성, spawnTime를 이용해 레벨에 따라 소환 시간 바꾸게끔 설정
        timer += Time.deltaTime;
        //float형 시간에 따라 int형 레벨 설정
        level =Mathf.Min(Mathf.FloorToInt( GameManager.instance.gameTime / 10f),spawnData.Length-1);

        //레벨을 활용해 몬스터 각각의 소환 타이밍 변경하기
        if (timer >(spawnData[level].spawnTime))
        {
            Spawn();
            timer = 0;
        }

리팩토링 이후

  • 몬스터 중 꽃 벽은 랜덤한 위치가 아닌 주인공 위치에서 리스폰=> switch 조건문으로 구분
  • stage Manager로 몬스터 스폰 시간과 스폰할 몬스터 종류, 레벨 등 관리
[EnemySpawner.cs]
public void SpawnEnemy(EnemyScriptableObject enemyToSpawn)
    {
        Vector3 position;
        //player의 위치 값에 랜덤 pos를 더해 스폰 지점 설정
        if (enemyToSpawn.SpriteType == 5)//flower wall
        {
            position = player.transform.position;
        }
        else
        {
            position= GenerateRandomPos();
            position += player.transform.position;
        }

        GameObject newEnemy= GameManager.instance.pool.Get("enemy",enemyToSpawn.SpriteType);
        newEnemy.transform.position = position;
        newEnemy.transform.parent = transform;
        switch (enemyToSpawn.SpriteType)
        {
            // 꽃벽과 박쥐 떼는 Empty object의 하위에 몬스터 프리펩을 넣어놨기 때문에 child의 components 호출
            case 4:
            case 5:
                newEnemy.GetComponentsInChildren<Enemy>()[0].InitEnemy(enemyToSpawn);
                break;
            default:
                newEnemy.GetComponent<Enemy>().InitEnemy(enemyToSpawn);
                break;
        }
    }
Clone this wiki locally