유니티 심화

HeroShooter - 오브젝트 풀링[총알], 비동기[씬 전환]

다모아 2023. 8. 30. 18:19

1. 총알 오브젝트 풀링
BulletPoolMain에 SetParent로 총알 SetActive(false) 상태로 해놓고
사용할 때 바깥으로 꺼내서 SetActive(true) 상태로 변경
몬스터한테 맞았을 때 SetActive(false) 변경하고 SetParent를 BulletPoolMain으로 변경

1-1. 총알 BulletPoolMain에 넣어두기 --> 총알을 알아야지 [완]
1-2. 총알 Destroy될 때 Release 해주기
2. 씬들 비동기 [완]
3. App, Title [완]

해야할 일 ㅡ> 플레이어가 총을 쏘는건 아니다 플레이어가 애니메이션으로 어택을 하면
메인에다가 알려줘서 총을 쏘고 메인은 Pool에서 총을 빌려온다.


BulletPoolManager

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

public class BulletPoolManager : MonoBehaviour
{
    //다른 스크립트에 사용
    public static BulletPoolManager instance;
    //총알 프리팹
    [SerializeField]
    private GameObject bulletPrefab;
    //총알 몇개?
    private int maxBullets = 40;
    //총알 리스트
    private List<GameObject> bulletPool = new List<GameObject>();

    private void Awake()
    {
        if(BulletPoolManager.instance == null)
        {
            BulletPoolManager.instance = this;
        }
        else if(instance != this)
        {
            Destroy(this.gameObject);
        }
        DontDestroyOnLoad(this.gameObject);
    }

    private void Start()
    {
        for(int i = 0; i < this.maxBullets; i++)
        {
            //총알생성
            GameObject bullet = Instantiate(this.bulletPrefab);
            //총알 위치
            bullet.transform.SetParent(this.transform);
            //총알 비활성화
            bullet.SetActive(false);
            //리스트에 추가
            this.bulletPool.Add(bullet);
        }
    }

    public GameObject GetBullet()
    {
        //순회하면서 총알 찾아보기
        foreach(GameObject bullet in bulletPool)
        {
            if(bullet.activeSelf == false)
            {
                //위치지정
                bullet.transform.SetParent(null);
                return bullet;
            }
        }
        return null;
    }

    public void Release(GameObject bullet)
    {
        //비활성화
        bullet.SetActive(false);
        //위치지정
        bullet.transform.SetParent(this.transform);
    }
}

 

AppMain

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

public class AppMain : MonoBehaviour
{
    private void Awake()
    {
        DontDestroyOnLoad(this.gameObject);
    }

    private void Start()
    {
        //비동기 씬로드
        this.SceneChange(EnumState.eSceneType.Title);
    }

    private void SceneChange(EnumState.eSceneType state)
    {
        AsyncOperation oper = SceneManager.LoadSceneAsync(state.ToString());
        Action<AsyncOperation> onComplete = null;
        switch (state)
        {
            case EnumState.eSceneType.App:
                break;
            case EnumState.eSceneType.Title:
                onComplete = (oper) => {
                    TitleMain titleMain = GameObject.FindObjectOfType<TitleMain>();
                    titleMain.onLoadComplete = () => {
                        this.SceneChange(EnumState.eSceneType.TutorialScene);
                    };
                };
                break;
            case EnumState.eSceneType.TutorialScene:
                onComplete = (oper) => {
                    TutorialSceneMain tutorialSceneMain = GameObject.FindObjectOfType<TutorialSceneMain>();
                    tutorialSceneMain.sceneChange = () => {
                        this.SceneChange(EnumState.eSceneType.Stage1Scene);
                    };
                };
                break;
            case EnumState.eSceneType.Stage1Scene:
                onComplete = (oper) => {
                    Stage1SceneMain stage1SceneMain = GameObject.FindObjectOfType<Stage1SceneMain>();
                    stage1SceneMain.sceneChange = () => {
                        this.SceneChange(EnumState.eSceneType.Stage2Scene);
                    };
                };
                break;
            case EnumState.eSceneType.Stage2Scene:
                break;
        }
        oper.completed += onComplete;
    }
}

 

TitleMain

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

public class TitleMain : MonoBehaviour
{
    [SerializeField]
    private Image loadingBar;
    private float percent = 0f;
    public Action onLoadComplete;

    private void Start()
    {
        this.StartCoroutine(this.CoLoading());
    }

    private IEnumerator CoLoading()
    {
        Debug.Log("Load Start");
        while (true)
        {
            this.percent += Time.deltaTime;
            this.loadingBar.fillAmount = this.percent;
            if (this.percent >= 1)
            {
                break;
            }
            yield return null;
        }
        Debug.Log("Load Complete");
        this.onLoadComplete();
    }
}

 

BulletController

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

public class BulletController : MonoBehaviour
{
    [SerializeField]
    private float bulletSpeed = 500f;
    private Rigidbody rBody;
    private int damage = 1;
    public int Damage
    {
        get
        {
            return this.damage;
        }
    }
    // Start is called before the first frame update
    void Start()
    {
        this.rBody = this.GetComponent<Rigidbody>();
        this.rBody.AddForce(this.transform.forward * this.bulletSpeed);
    }
    public void RemoveBullet()
    {
        BulletPoolManager.instance.Release(this.gameObject);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "Monster")
        {
            this.RemoveBullet();
        }
    }

}

 

PlayerController

해야할 일 ㅡ> 플레이어가 총을 쏘는건 아니다 플레이어가 애니메이션으로 어택을 하면 메인에다가&nbsp;알려줘서&nbsp;총을&nbsp;쏘고&nbsp;메인은&nbsp;Pool에서&nbsp;총을&nbsp;빌려온다.

 

EnumState

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

public class EnumState
{
    public enum ePlayerState
    {
        Idle, RunF, Attack
    }

    public enum eMonsterState
    {
        Idle, GetHit, Die
    }

    public enum eSceneType
    {
        App, Title, TutorialScene, Stage1Scene, Stage2Scene
    }
}