GURU_unity_2주차 슈팅 게임 제작5

2023. 7. 7. 00:59SWU_프로젝트/GURU - unity

오늘 학습할 내용은 아래와 같다.

1. 싱글톤패턴으로 관리자 만들기
2. 오브젝트풀을 이용한 메모리 관리(기초)
3. 오브젝트풀을 이용한 메모리 관리(고급)

 

1. 싱글톤패턴으로 관리자 만들기

 

 

싱글톤 객체 만들기

public class ScoreManager : MonoBehaviour
{ . . . (생략) . . .
// 싱글톤 객체
public static ScoreManager Instance = null;
// 싱글톤 객체에 값이 없으면 생성된 자기 자신을 할당
void Awake()
 {
         if(Instance == null)
       {
             Instance = this;
       }
  }
. . . (생략) . . .
}
  • 출처가 같은 변수는 단 하나만 선언 할 수 있다”는 규칙을 이용하여 싱글톤 디자인패턴을 만들어 사용한다.
  • 싱글톤 디자인패턴은 단 하나의 객체 인스턴스를 static 으로 등록해 놓고 사용을 하는 방식이다.
  • ScoreManager 가 점수를 관리하는 유일한 매니저가 되기 때문에 싱글톤객체로 만들어 사용한다.
  • public static ScoreManager Instance = null; 전체 오브젝트에서 고유한 값을 가지게 된다.
  • 불필요하게 find과정을 거칠 필요가 없어지고 바로 부를수 다.

 

싱글톤 객체 참조로 변환

public class Enemy : MonoBehaviour
{
//1. 적이 다른 물체와 충돌 했으니까.
private void OnCollisionEnter(Collision collision)
  {
// 에너미를 잡을 때마다 현재 점수 표시하고 싶다. ScoreManager.Instance.SetScore(ScoreManager.Instance.GetScore() + 1);
//2.폭발 효과 공장에서 폭발 효과를 하나 만들어야 한다.
GameObject explosion = Instantiate(explosionFactory);
//3.폭발 효과를 발생(위치) 시키고 싶다.
explosion.transform.position = transform.position;
Destroy(collision.gameObject);
Destroy(gameObject);
      }
 }

Enemy.cs 스크립트로 이동하여 ScoreManager 의 Instance 맴버에 접근 하는 것으로 바꾼다.

find를 쓰지않기때문에 간결해지고 퍼포먼스도 더 좋아진다.

 

get/set 선언 

public class ScoreManager : MonoBehaviour
{ . . . (생략) . . .
public static ScoreManager Instance = null;
public int Score
{
get
{
return currentScore;
}
set
   {
// to do
    }
  }
}
  • 사용법은 변수의 편의성을 가져오고, 제작은 함수의 몸체를 갖도록 만든다. 
  • ScoreManager 에 Score 이름을 갖는 get/set 프로퍼티를 만든다.

get/set 구현

public class ScoreManager : MonoBehaviour
{
     public int Score
{
       . . . (생략) . . .
       set
{
      // 3.ScoreManager 클래스의 속성에 값을 할당 한다.
            currentScore = value;
     // 4.화면에 현재 점수 표시하기
             currentScoreUI.text = "현재점수 : " + currentScore;
     //목표: 최고 점수를 표시하고 싶다.
     //1.현재 점수가 최고 점수 보다 크니까
     //-> 만약 현재 점수가 최고 점수를 초과 하였다면”
     if (currentScore > BestScore)
     {
      //2.최고 점수가 갱신 시킨다.
       BestScore = currentScore;
       //3.최고 점수 UI 에 표시
       BestScoreUI.text = "최고점수 : " + BestScore;
       // 목표 : 최고점수를 저장하고싶다.
       PlayerPrefs.SetInt("Best Score", BestScore);
       }
     }
   }
}
  • Set 의 구현부는 SetScore 함수의 구현 내용을 복사 붙여넣기 해준다.  
  • GetScore 함수와 SetScore 함수는 제거하여 준다.

get/set 프로퍼티로 구현 변경

public class Enemy : MonoBehaviour
{
//1. 적이 다른 물체와 충돌 했으니까.
private void OnCollisionEnter(Collision collision)
{
 // 에너미를 잡을 때마다 현재 점수 표시하고 싶다.
 ScoreManager.Instance.Score++;
//2.폭발 효과 공장에서 폭발 효과를 하나 만들어야 한다.
GameObject explosion = Instantiate(explosionFactory);
//3.폭발 효과를 발생(위치) 시키고 싶다.
explosion.transform.position = transform.position;
Destroy(collision.gameObject);
Destroy(gameObject);
   }
 }

Enemy 스크립트로 이동하여 Score 변경 코드를 다음 코드와 같이 바꾼다.

 

 

2. 오브젝트풀을 이용한 메모리 관리 (기초)

목표 : 총알과 에너미를 오브젝트풀로 관리하고 싶다.
순서 : 1.총알 오브젝트풀 제작
          2. 에너미 오브젝트풀 제작

 

필요속성 추가

public class PlayerFire : MonoBehaviour
{
    public GameObject bulletFactory;
    // 탄창에 넣을 총알 개수
    public int poolSize = 10;
     // 오브젝트풀 배열
     GameObject[] bulletObjectPool;
}

PlayerFire 에 오브젝트 풀 크기 속성과, 오브젝트 풀을 위한 배열을 추가하여 준다.

 

구현 과정

목표 : 태어 날 때 오브젝트풀(탄창) 에 총알을 하나씩 생성하여 넣고 싶다.
순서 : 1. 태어 날 때
          2. 탄창을 총알 담을 수 있는 크기로 만들어 준다.
          3. 탄창에 넣을 총알 개수 만큼 반복하여
          4 총알공장에서 총알 생성한다.
          5. 총알을 오브젝트풀에 넣고싶다.

 

1.태어날 때

public class PlayerFire : MonoBehaviour
{
. . . (생략) . . .
 // 태어 날 때 오브젝트풀(탄창) 에 총알을 하나씩 생성하여 넣고 싶다
 // 1. 태어 날 때
  void Start()
 { 
     // 2. 탄창을 총알 담을 수 있는 크기로 만들어 준다.
     // 3. 탄창에 넣을 총알 개수 만큼 반복하여
     // 4. 총알공장에서 총알 생성한다.
     // 5. 총알을 오브젝트풀에 넣고싶다.
}
  • PlayerFire 객체가 태어날 때 탄창에 총알을 만들어 넣어 주도록 한다. 
  • 라이프사이클 함수 중 Start 에서 그 처리를 한다.

2. 탄창을 총알 담을 수 있는 크기로 만들어 준다.

ublic class PlayerFire : MonoBehaviour
{ . . . (생략) . . .
// 태어 날 때 오브젝트풀(탄창) 에 총알을 하나씩 생성하여 넣고 싶다
// 1. 태어 날 때
void Start()
{
// 2. 탄창을 총알 담을 수 있는 크기로 만들어 준다.
bulletObjectPool = new GameObject[poolSize];
// 3. 탄창에 넣을 총알 개수 만큼 반복하여
// 4. 총알공장에서 총알 생성한다.
// 5. 총알을 오브젝트풀에 넣고싶다.
}

 오브젝트 풀인 bulletObjectPool 배열을 풀사이즈 크기 만큼으로 생성한다.

 

3.탄창에 넣을 총알 개수 만큼 반복하여

public class PlayerFire : MonoBehaviour
{ . . . (생략) . . .
void Start()
{
// 2. 탄창을 총알 담을 수 있는 크기로 만들어 준다.
bulletObjectPool = new GameObject[poolSize];
// 3. 탄창에 넣을 총알 개수 만큼 반복하여
for (int i = 0; i < poolSize; i++)
{
// 4. 총알공장에서 총알 생성한다.
GameObject bullet = Instantiate(bulletFactory);
// 5. 총알을 오브젝트풀에 넣고싶다.
bulletObjectPool[i] = bullet;
// 비활성화 시키자.
bullet.SetActive(false);
    }
}
  • 반복적인 동작을 요하기 때문에 C# 에의 반복문 중 for 문을 사용하여 구현한다.
  • 먼저 풀 크기만큼 반복문의 형체를 잡아 놓는다.
  • 이미 PlayerFire 에 있는 Update 함수의 코드인 bullet 생성 코드를 가져온다.

총알 발사 로직을 수정하자.

오브젝트 풀을 활용하기 위해 기존 총알을 그때그때 만들어 발사하던 로직을 수정해야한다.

목표 : 발사 버튼을 누르면 탄창에 있는 총알 중 비활성화 된 녀석을 발사 하고 싶다.
순서 : 1. 발사 버튼을 눌렀으니까
           2. 탄창 안에 있는 총알들 중에서
           3. 비활성화 된 총알을
           4. 총알을 발사하고 싶다.(활성화시킨다.)
public class PlayerFire : MonoBehaviour
{
. . . (생략) . . .
//목표 : 발사 버튼을 누르면 탄창에 있는 총알 중 비활성화 된 녀석을 발사 하고 싶다.
void Update()
{
//1.발사 버튼을 눌렀으니까
  if (Input.GetButtonDown("Fire1"))
    {
      //2.탄창 안에 있는 총알들 중에서
          for (int i = 0; i < poolSize; i++)
           { //3.비활성화 된 총알을 // - 만약 총알이 비활성화 되었다면
               GameObject bullet = bulletObjectPool[i];
               if (bullet.activeSelf == false)
         { //4.총알을 발사하고 싶다.(활성화시킨다.)
                bullet.SetActive(true); // 총알을 위치 시키기
                bullet.transform.position = transform.position;
                 //총알 발사 하였기 때문에 비활성화 총알 검색 중단
                break;
               }
             }
          }
      }
}

PlayerFire 의 Update 함수의 구현 부를 다음과 같이 변경하여 준다.

총알 10개 생성!

  • 실행을 해보면 적을 맞추었을 때 그 다음부터 총알이 잘 발사되지 않고 콘솔(Console) 창에 다음과 같은 오류 메시지가 표시 된다.
  • 총알을 없애지 말고 다시 비활성화 시켜 탄창에 넣어주어야 하는 작업이 필요하다.
public class Enemy : MonoBehaviour
{ . . . (생략) . . .
private void OnCollisionEnter(Collision other)
{
. . . (생략) . . .
explosion.transform.position = transform.position;
// 만약 부딪힌 객체가 Bullet 인 경우에는 비활성화 시켜 탄창에 다시 넣어준다.
//1.만약 부딪힌 물체가 Bullet 이라면
      if (other.gameObject.name.Contains("Bullet"))
{
//2.부딪힌 물체를 비활성화 other.gameObject.SetActive(false);
}
//3.그렇지 않으면 제거
      else
  {
      Destroy(other.gameObject);
  }
      Destroy(gameObject);
     }
}
  • Enemy 클래스의 OnCollisionEnter 로 이동한다.
  • “1. 만약 부딪힌 물체가 Bullet 이라면” 내용추가. 
  • "2. 부딪힌 물체를 비활성화” 코드 추가 
  • “3. 그렇지 않으면 제거” 의 구현 추가

이래도 나는 여전히 오류가 발생했다.

원인은 DestroyZone때문이었고, 아래와 같이  DestroyZone.cs코드를 수정해주었다.

  • 총알이 날아갈 때 그림처럼 회전되어 이동하는 문제가 발생한다.
  • Bullet 객체에 Rigidbody 컴포넌트가 붙어 있기 때문에 다른 물체와 부딪혀 회전값이 적용된 상태로 발사되기 때문이다.
  • Rigidbody 가 이동 및 회전 처리를 못하도록 막아 해결한다. Bullet 프리팹을 더블 클릭하여 프리팹 편집 창으로 이동
  • Bullet 객체의 Rigidbody 컴포넌트의 Constraints 속성을 체크하여 모두 잠가준다.

   

이렇게 오류없이 잘 실행되는 것을 확인할 수 있다.

 

 

SpawnPoint 만들기

  • EnemyManager 게임오브젝트를 하이어라키에서 선택하고 를 눌러 하나 복제한다.
  • EnemyManager 로 이름이 되어 있는 객체 빼고 나머지 뒤에 숫자가 붙은 EnemyManager 들은 모두 SpawnPoint 로 바꾸어 준다.

  • SpawnPoint 들에 있는 EnemyManager 컴포넌트는 모두 제거한다.

    속성 정의

public class EnemyManager : MonoBehaviour
{
//오브젝트풀 크기
public int poolSize = 10;
//오브젝트풀 배열
GameObject[] enemyObjectPool;
//SpawnPoint 들
public Transform[] spawnPoints;
. . . (생략) . . .
}
  • 적들이 소환될 위치를 기억할 SpawnPoint 배열을 선언한다. 
  • 풀사이즈와 적들을 담을 오브젝트풀 맴버변수를 선언한다.

오브젝트풀 생성

public class EnemyManager : MonoBehaviour
{
. . . (생략) . . .
//1. 태어 날 때
void Start()
{
 creatTime = Random.Range(1.0f, 5.0f);
 //2. 오브젝트풀을 에너미들을 담을 수 있는 크기로 만들어 준다.
 enemyObjectPool = new GameObject[poolSize];
 //3. 오브젝트풀에 넣을 에너미 개수 만큼 반복하여
 for (int i = 0; i < poolSize; i++)
{
    //4. 에너미공장에서 에너미를 생성한다.
    GameObject enemy = Instantiate(enemyFactory);
    //5. 에너미를 오브젝트풀에 넣고싶다.
    enemyObjectPool[i] = enemy;
    // 비활성화 시키자.
     enemy.SetActive(false);
      }
  }

1. Start 함수에서 태어날때 내용을 구성할 수 있도록한다. 

2. 오브젝트풀을 에너미들을 담을 수 있는 크기로 만들어 준다.

3. 오브젝트풀에 넣을 에너미 개수 만큼 반복할 수 있도록 for 반복문을 활용한다.

4. 에너미공장에서 에너미를 생성한다.

5. 에너미를 오브젝트풀에 넣고 비활성화 시킨다.

 

오브젝트풀 활용하기

public class EnemyManager : MonoBehaviour
{
. . . (생략) . . .
void Update()
  {
    currentTime += Time.deltaTime;
    //1.생성 시간이 되었으니까
     if (currentTime > creatTime)
  {
    //2.에너미풀 안에 있는 에너미들 중에서
     for (int i = 0; i < poolSize; i++)
   {
     //3.비활성화 된 에너미를 // - 만약 에너미가 비활성화 되었다면
         GameObject enemy = enemyObjectPool[i];
          if (enemy.activeSelf == false)
    {
     //4.에너미를 활성화 하고 싶다.
           enemy.SetActive(true);
     // 에너미 위치 시키기
           enemy.transform.position = transform.position;
    //에너미 활성화 하였기 때문에 검색 중단
           break;
         }
      }
      creatTime = Random.Range(1.0f, 5.0f);
      currentTime = 0;
    }
 }
  • Update 함수에서 오브젝트 풀을 활용할 수 있도록 수정한다.
  • 에너미풀 안에 있는 적들 중에서 비활성화되어 있는 적을 반복적으로 검사 할 수 있도록 for 를 활용한다. 
  • 비활성화 된 에너미를 찾아 활성화 시켜준다.
public class Enemy : MonoBehaviour
{
. . . (생략) . . .
//1. 적이 다른 물체와 충돌 했으니까.
private void OnCollisionEnter(Collision other)
{
. . . (생략) . . .
//Destory 로 없애는 대신 비활성화 하여 풀에 자원을 반납합니다.
//Destroy(gameObject);
gameObject.SetActive(false);
   }
 }
  • Enemy 클래스의 OnCollisionEnter 으로 이동한다. 
  • 비활성화 해 줌으로써 자원을 반납해 주도록 한다.
public class DestroyZone : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
//1.만약 부딪힌 물체가 Bullet 이거나 Enemy 이라면
     if (other.gameObject.name.Contains("Bullet") ||
         other.gameObject.name.Contains("Enemy"))
      {
             //2.부딪힌 물체를 비활성화
             other.gameObject.SetActive(false);
       }
    }
}

DestroyZone 에서는 Enemy 일 때의 조건을 하나 추가해 주도록 한다.

 

  • 총알에서 처럼 에너미가 충돌하면 회전과 위치가 변화되지 않도록 Rigidbody 부분을 수정한다.
  • [Project – Assets – Prefabs] 폴더에서 Enemy 프리팹을 선택 
  • 인스펙터 창에서 Rigidbody 컴포넌트의 Constraints 속성을 모두 체크하여 잠가 준다.

  SpawnPoint 할당하기

  • EnemyManager 객체를 선택하고 인스펙터 창을 잠가 준다.
  • 하이어라키에서 SpawnPoint 객체를 모두 선택하여 EnemyManager 의 SpawnPoints 속성의 이름으로 드래그앤드롭 하여 할당한다.
  • 등록이 완료되면 인스펙터의 우측 상단 자물쇠는 다시 원래대로 풀어 준다.

 

SpawnPoint 랜덤 할당

public class EnemyManager : MonoBehaviour
{
. . . (생략) . . .
void Update()
{
         currentTime += Time.deltaTime;
          //1.생성 시간이 되었으니까
         if (currentTime > creatTime)
       {
          //2.에너미풀 안에 있는 에너미들 중에서
          for (int i = 0; i < poolSize; i++)
        {
            . . . (생략) . . .
             enemy.SetActive(true);
             // 랜덤으로 인덱스 선택
             int index = Random.Range(0, spawnPoints.Length);
            // 에너미 위치 시키기
             enemy.transform.position = spawnPoints[index].position;
                   . . . (생략) . . .
  • EnemyManager.cs 스크립트로 이동
  • 에너미 배치하는 곳의 코드를 Random.Range 함수를 이용하여 랜덤 인덱스를 뽑아 위치에 적용한다.

3. 오브젝트풀을 이용한 메모리 관리 (고급)

 

총알 오브젝트풀 리스트로 교체

public class PlayerFire : MonoBehaviour
{
     public GameObject bulletFactory;
     // 탄창에 넣을 총알 개수
      public int poolSize = 10;
     // 오브젝트풀 배열
      public List <GameObject> bulletObjectPool;
    . . . (생략) . . .

PlayerFire 스크립트로 이동한다.

기존에 사용하던 GameObject[] 배열 형식을 List로 교체한다.

public class PlayerFire : MonoBehaviour
{
void Start()
{
// 2. 탄창을 총알 담을 수 있는 크기로 만들어 준다.
      bulletObjectPool = new List<GameObject>();
//3. 탄창에 넣을 총알 개수 만큼 반복하여
      for (int i = 0; i < poolSize; i++)
{
// 4. 총알공장에서 총알 생성한다.
      GameObject bullet = Instantiate(bulletFactory);
// 5. 총알을 오브젝트풀에 넣고싶다.
       bulletObjectPool.Add(bullet);
 // 비활성화 시키자.
       bullet.SetActive(false);
    }
}

Start 함수에서 배열로 되어 있는 처리를 모두 List로 바꿔준다.

public class PlayerFire : MonoBehaviour
{
    . . . (생략) . . .
    //목표 : 발사 버튼을 누르면 탄창에 있는 총알 중 비활성화 된 녀석을 발사 하고 싶다.
  void Update()
  {
   //1.발사 버튼을 눌렀으니까
   if (Input.GetButtonDown("Fire1"))
   {
   //2.탄창 안에 있는 총알이 있다면
   if (bulletObjectPool.Count > 0)
   {
   //3.비활성화 된 총알을 하나 가져온다.
   GameObject bullet = bulletObjectPool[0];
   //4.총알을 발사하고 싶다.(활성화시킨다.)
   bullet.SetActive(true);
   //오브젝트풀에서 총알제거
   bulletObjectPool.Remove(bullet);
   // 총알을 위치 시키기
   bullet.transform.position = transform.position;
     }
   }
}
  • Update 함수에서의 발사 코드를 배열에서 List 로 수정한다.
  • 배열은 오브젝트풀을 전수조사 하여 비활성화 객체를 찾아 냈다면 리스트에는 비활성화 객체만 들어있기 때문에 검색이 필요 없다.
  • 리스트에 객체가 있는지 확인하고 있다면 가장 첫번째 요소를 가져와 사용
public class DestroyZone : MonoBehaviour
{
     private void OnTriggerEnter(Collider other)
 {
      //1.만약 부딪힌 물체가 Bullet 이라면
     if (other.gameObject.name.Contains("Bullet") ||
         other.gameObject.name.Contains("Enemy"))
   {
      //2.부딪힌 물체를 비활성화
         other.gameObject.SetActive(false);
      //3. 부딪힌 물체가 총알일 경우 총알 리스트에 삽입
         if (other.gameObject.name.Contains("Bullet"))
     {
       // PlayerFire 클래스 얻어오기
               PlayerFire player =
               GameObject.Find("Player").GetComponent<PlayerFire>();
       // list 에 총알 삽입
                player.bulletObjectPool.Add(other.gameObject);
              }
         }
     }
}

다 사용한 총알을 다시 오브젝트풀에 넣어준다.

DestroyZone 스크립트로 이동하여 총알이 부딪혔을 경우 List 에 총알을 다시 넣는 코드를 추가한다.

public class Enemy : MonoBehaviour
{
   //1. 적이 다른 물체와 충돌 했으니까.
   private void OnCollisionEnter(Collision other)
   { . . . (생략) . . .
        if (other.gameObject.name.Contains("Bullet"))
       {
            //2.부딪힌 물체를 비활성화
            other.gameObject.SetActive(false);
            // PlayerFire 클래스 얻어오기
             PlayerFire player =
             GameObject.Find("Player").GetComponent<PlayerFire>();
            // list 에 총알 삽입 player.bulletObjectPool.Add(other.gameObject);
            }
           . . . (생략) . . .
         }
  }

Enemy 클래스로 이동하여 PlayerFire 객체를 얻어와서 bulletObjectPool 리스트에 값을 넣어준다.

 

 

에너미 오브젝트풀 리스트로 교체

public class EnemyManager : MonoBehaviour
{
    //오브젝트풀 크기
     public int poolSize = 10;
   //오브젝트풀 배열
     public List <GameObject>enemyObjectPool;
enemyObjectPool
  • EnemyManager.cs 스크립트로 이동하여 GameObject[] enemyObjectPool 을 List 로 교체한다. 
  • 접근지시자는 public 으로 수정한다.
public class EnemyManager : MonoBehaviour
{
//1. 태어 날 때
    void Start()
  {
     creatTime = Random.Range(minTime, maxTime);
//2. 오브젝트풀을 에너미들을 담을 수 있는 크기로 만들어 준다.
      enemyObjectPool = new List<GameObject>();
//3. 오브젝트풀에 넣을 에너미 개수 만큼 반복하여
      for (int i = 0; i < poolSize; i++)
{
        //4. 에너미공장에서 에너미를 생성한다.
        GameObject enemy = Instantiate(enemyFactory);
        //5. 에너미를 오브젝트풀에 넣고싶다.
        enemyObjectPool.Add(enemy);
       // 비활성화 시키자.
        enemy.SetActive(false);
     }
}

Start 함수를 수정하여 객체 생성을 List 로 교체를 하고 값 삽입은 Add 함수를 이용하여 처리 한다.

 

public class EnemyManager : MonoBehaviour
{
  void Update()
  {
     currentTime += Time.deltaTime;
      //1.생성 시간이 되었으니까
      if (currentTime > creatTime)
{
       //2.오브젝트풀에 에너미가 있다면
       GameObject enemy = enemyObjectPool[0];
        if (enemyObjectPool.Count > 0)
   {
        //3.에너미를 활성화 하고 싶다.
           enemy.SetActive(true);
       //4.오브젝트풀에서 에너미제거
           enemyObjectPool.Remove(enemy);
       // 랜덤으로 인덱스 선택
            int index = Random.Range(0, spawnPoints.Length);
       // 5.에너미 위치 시키기
            enemy.transform.position = spawnPoints[index].position;
         }
         . . . (생략) . . .
       }
   }
 }

pdate 함수에서 for 문을 이용하여 조사하는 부분을 List 를 사용하도록 수정한다.

public class DestroyZone : MonoBehaviour
  {
     private void OnTriggerEnter(Collider other)
  {
      //1.만약 부딪힌 물체가 Bullet 이라면
       if (other.gameObject.name.Contains("Bullet") ||
           other.gameObject.name.Contains("Enemy"))
      {
         . . . (생략) . . . //3. 부딪힌 물체가 총알일 경우 총알 리스트에 삽입
            if (other.gameObject.name.Contains("Bullet"))
        {
                . . . (생략) . . .
         }
           else if (other.gameObject.name.Contains("Enemy"))
     {
         // EnemyManager 클래스 얻어오기
              GameObject emObject =
                                     GameObject.Find("EnemyManager");
              EnemyManager manager =
                                      emObject.GetComponent<EnemyMAnager>();
               // list 에 총알 삽입
              manager.enemyObjectPool.Add(other.gameObject);
             }
          }
      }
}

DestroyZone 스크립트로 이동하여 부딪힌 객체가 Enemy 일 때 EnemyManager 의 enemyObjectPool 변수를 가져와 그곳에 삽입한다.

 

public class Enemy : MonoBehaviour
{
       //1. 적이 다른 물체와 충돌 했으니까.
        private void OnCollisionEnter(Collision other)
        {
             . . . (생략) . . .
         //Destroy(gameObject);
         gameObject.SetActive(false);
        // EnemyManager 클래스 얻어오기
         GameObject emObject = GameObject.Find("EnemyManager");
         EnemyManager manager =
                                    emObject.GetComponent<EnemyManager> ();
          // list 에 총알 삽입
         manager.enemyObjectPool.Add(gameObject);
       }
}

Enemy 클래스로 이동하여 부딪혔을 때 Enemy 를 EnemyManager 의 List 오브젝트풀에 다시 삽입해 준다.

 

 

 

 

하하 내용이 점점 어려워지는 것 같다!