[VR] GroundZero 개발

[4Idle - Gazzlers] GameScene에 Wave 별로 Enemy 1,2,3 생성

meltingmelvin 2023. 12. 26. 11:53

https://made-myblog.tistory.com/72

 

Gazzlers 개발일지 - Enemy 관리

이번에는 Enemy의 생성 및 관리를 구현해보려고 한다. 원작에서는 한 화면 안에서 Enemy가 최대 2마리씩 나오며 각 웨이브마다 생성되는 최대 Enemy 수량이 존재한다. 이 수량을 다 채울 때까지 Enemy

made-myblog.tistory.com

-이 포스팅에서는 팀원이 test로 만들어준 Enemy관리 포스팅을 참고하여 GameScene에서 enemy1,2,3을 생성한다.

-enemy들은 wave별로 생겨나며, 각각 HPBar도 가지고 있으므로 연동시켜줘야한다.

 

Enemy생성

 

-EnemyPoolManager.cs에서 Enemy를 생성해두고, 비활성화 시켜두도록한다.

-비활성화 해둔 Enemy들을 필요할 때(Wave가 진행되어 호출할 때) 가져와서 활성화시킨다.

 

-EnableEnemy가 Enemy를 활성화시키는 코드이다. 

-activeSelf를 사용해 enemy가 비활성화상태인지 확인한다.

https://docs.unity3d.com/ScriptReference/GameObject-activeSelf.html

 

Unity - Scripting API: GameObject.activeSelf

 

docs.unity3d.com

 

main의 start에서 호출 / 코루틴 함수

 

-main의 start에서 코루틴을 호출한다. 코루틴함수는 enemy를 나타나게하는 함수이다.

SpawnEnemy()
SpawnEnemy()

-spawnEnemy에서 웨이브 1,2,3 을 확인하도록한다. 웨이브에 따라 나타나는 몬스터가 달라지게된다.

 

Enemy들에게 HPBar 연동

Main에서 this.OnGenerateEnemy호출/ main에서 OnGenerateEnemy/ EnemyMove1.cs

 

-main에서 enemy를 생성할 때, 대리자를 호출해 enemy의 정보를 가져오도록한다.

-정보는 enemyData를 돌며 enemy의 태그를 비교하여 확인한다.

- 가져온 정보를 Enemy1Move에 전달하여 값을 활용하도록 하였다.

=> OnGenerateEnemy에서 slider값을 변경시키고, 데이터를 전달한다.

 

Enemy 충돌처리 수정

righthandController.cs 수정

-플레이어가 공격했을때 Enemy1만 확인되던 문제를 righthandController를 수정하여 해결하였다.

- 태그로 오브젝트를 식별하고 있었는데, enemy1만 받아오고 있었기 때문이다.

 

Enemy2 / Enemy3

 

 

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

    public class EnemyPoolManager : MonoBehaviour
    {
        public static EnemyPoolManager instance;
        //[SerializeField] private GameObject enemyPrefab;
        [SerializeField] private GameObject[] arrEnemyPrefabs;
        // private List<Enemy1Move> enemyPool = new List<Enemy1Move>();
         private List<List<GameObject>> enemyPool = new List<List<GameObject>>();

        void Awake()
        {
            instance = this;
        }


        private void Start()
        {
            this.GenerateEnemy();
        }

        private void GenerateEnemy()
        {
           // for (int i = 0; i < 2; i++)
            for(int i=0;i<this.arrEnemyPrefabs.Length; i++)    
            {
                List<GameObject> list = new List<GameObject>();
                for (int j = 0; j < 2; j++)
                {
                    GameObject go = Instantiate(arrEnemyPrefabs[i], this.transform);
                    go.SetActive(false);
                    list.Add(go);
                    //GameObject go = Instantiate(enemyPrefab, this.transform);
                    //go.SetActive(false);
                    //enemyPool.Add(go.GetComponent<Enemy1Move>());

                }
                this.enemyPool.Add(list);
                }
        }

        public GameObject EnableEnemy(int idx)
        {
            GameObject result = null;

            for (int i = 0; i < enemyPool[idx].Count; i++)
            {
            //  Debug.Log(enemyPool[idx][i]);
            if (enemyPool[idx][i].activeSelf == false)
            {
                result = enemyPool[idx][i];
                //result.gameObject.SetActive(true);
                result.transform.SetParent(null);
                break;
            }
        }
        if (result == null)
        {
            result = Instantiate(arrEnemyPrefabs[idx]);
            enemyPool[idx].Add(result);
        }
        return result;


        }

        public void DisableEnemy(GameObject enemy)
        {
            enemy.SetActive(false);
            enemy.transform.SetParent(this.transform);
        }

    }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;
using System.Linq;
using Newtonsoft.Json;
using System.IO;
public class GameMain : MonoBehaviour
    {
        [SerializeField] Canvas worldCanvas;
        [SerializeField] Canvas rightHandCanvas;
        [SerializeField] TextMeshProUGUI guideText;
        [SerializeField] GameObject uiHPBarPrefab;
        [SerializeField] GameObject uiDamageTextPrefab;
        [SerializeField] GameObject uiEnergyCellPrefab;
        [SerializeField] GameObject gunEnergyCellGo;
        [SerializeField] EnergyCellController energyCellForCharge;
        [SerializeField] RightHandController rightHand;
        [SerializeField] Transform uiEnergyCellTransform;
        [SerializeField] Transform worldUITransform;
        
        public bool isFirstHP = false;

        private GameObject hpBarUIGo;
        private GameObject damageTextUIGo;
        private GameObject energyTextUIGo;

        private Action<Enemy1Move> OnGenerateEnemy;
        private string currGunType;
        private int currGunDamage;
        private int currGunEnergy;
        private int currGunMaxEnergy;
  
    private List<GameObject> enemyHpBarPools = new List<GameObject>();
        private List<GameObject> activeHPBar = new List<GameObject>();


    //----------------------------------SJY Map Main-----------------------------------------------------------
    [SerializeField] private MapController mapController;
    [SerializeField] private CamMove camMove;


    //----------------------------------SJY Enemy1Move Main-----------------------------------------------------------
    public enum eWave
    {
        WAVE1, WAVE2, WAVE3
    }
    private eWave wave;

    [SerializeField] private Transform[] arrTargetPos;
    private List<Enemy1Move> listEnemies = new List<Enemy1Move>();
    private List<bool> isTargeted = new List<bool>();
    private int EnemyCount = 2;

    private int[] maxWaveEnemyCount = new int[3] { 3, 6, 9 };
    private int remainEnemyCount;


    private void Awake()
        {
           
        }
        // Start is called before the first frame update
        void Start()
        {
        Debug.Log("Start");
            this.guideText.gameObject.SetActive(false);
            this.worldCanvas.transform.SetParent(this.worldUITransform);
            this.worldCanvas.transform.localPosition = Vector3.zero;
            this.worldCanvas.transform.localRotation = Quaternion.identity;

            this.energyTextUIGo = this.uiEnergyCellPrefab;
            this.rightHandCanvas.transform.SetParent(this.uiEnergyCellTransform);
            this.rightHandCanvas.transform.localPosition = Vector3.zero;
            this.rightHandCanvas.transform.localRotation = Quaternion.identity;

            DataManager.Instance.LoadPlayerDatas();
            DataManager.Instance.LoadGunrDatas();
            DataManager.Instance.LoadEnemyDatas();

            List<PlayerData> playerData = DataManager.Instance.GetPlayerDatas();
            List<GunData> gunData = DataManager.Instance.GetGunDatas();
            List<EnemyData> enemyData = DataManager.Instance.GetEnemyDatas();

        Debug.LogFormat("player Data Count: {0}",playerData.Count);

              var playerGunId = playerData[0].currGunId;
        //var playerGunId = 1000;

        Debug.LogFormat("Gun Data Count: {0}", gunData.Count);
        for (int i = 0; i < gunData.Count; i++)
            {
                if (playerGunId == gunData[i].gunId)
                {//Find player's current gun's Data on GunData 
                    Debug.Log(gunData[i].gunType);
                    this.currGunType = gunData[i].gunType;
                    this.currGunDamage = gunData[i].gunDamage;
                    this.currGunEnergy = gunData[i].gunEnergyCell;
                    this.currGunMaxEnergy = gunData[i].gunEnergyCell;

                }
            }

            this.enemyHpBarPool();

        

       

            this.damageTextUIGo = Instantiate(this.uiDamageTextPrefab, this.worldCanvas.transform);
            this.damageTextUIGo.SetActive(false);


       



        this.OnGenerateEnemy = (enemy) =>
        {
            var go = this.CreateHpBar(enemy.hpBarPoint.position);
            this.activeHPBar.Add(go);
            for (int j = 0; j < enemyData.Count; j++)
            {
                if (enemy.tag == enemyData[j].enemyType)
                {

                    Debug.Log(enemyData[j].enemyType);
                    var slider = go.GetComponent<Slider>();
                    slider.maxValue = enemyData[j].enemyHp;
                    Debug.Log(slider.maxValue);
                    slider.value = slider.maxValue;//reset slider value as full state
                                                   //this.listEnemies[j].currHP = (int)slider.value; //set EnemyHp
                                                   //Debug.Log(listEnemies[j].gameObject);
                    enemy.OnGetData(enemyData[j]);

                }


            }


        };
        this.rightHand.OnHitEnemy = (hitPos,hitObject) =>
            {
               // Debug.LogFormat("Hit Enemy! Point: {0}", hitPos);
                StartCoroutine(this.CoShowDamageText(hitPos));

                for (int i = 0; i < this.listEnemies.Count; i++)
                {
                    if (hitObject == this.listEnemies[i].gameObject)
                    {
                        Debug.LogFormat("Object: {0} , Damage : {1}",i,currGunDamage);
                        this.activeHPBar[i].GetComponent<Slider>().value -= currGunDamage;
                       
                        hitObject.GetComponent<Enemy1Move>().OnGetHit(currGunDamage);
                        if(this.activeHPBar[i].GetComponent<Slider>().value <= 0)
                        {
                            this.activeHPBar[i].SetActive(false);
                            this.activeHPBar.Remove(this.activeHPBar[i]);
                        }
                    }
            }
                
            };

        this.rightHand.OnShoot = () =>
        {
            this.currGunEnergy -= 1;
        };

        this.energyCellForCharge.OnCharge = () => {

            
            this.currGunEnergy = this.currGunMaxEnergy;//reset energyCell as full state
            this.gunEnergyCellGo.SetActive(true);
            StartCoroutine(this.CoResetEnergyCellItem());
        
        };
        //----------------------------------SJY Map Main-----------------------------------------------------------

        Vector3 camPos = Vector3.zero;
        this.mapController.onInformInitPos = (pos) =>
        {
            camPos = pos;
        };
        this.mapController.onInformRoute = (rail) =>
        {
            this.camMove.UpdateRoute(rail.GetRoute());
        };
        this.mapController.Init();
        this.camMove.Init(camPos);

           //----------------------------------SJY Enemy1Move Main-----------------------------------------------------------
         // EnemyPool.instance.LoadAll();

        for (int i = 0; i < arrTargetPos.Length; i++)
        {
            isTargeted.Add(false);
        }
        this.StartCoroutine(this.CoStartSpawnEnemy1());
    }
    private IEnumerator CoResetEnergyCellItem()
    {
        this.energyCellForCharge.gameObject.SetActive(false);
        yield return new WaitForSeconds(2f);
       // Debug.Log("Rest Energy Item");
        this.energyCellForCharge.transform.SetParent(this.energyCellForCharge.energyCellOriginalPoint);
        this.energyCellForCharge.transform.localPosition = Vector3.zero;
        this.energyCellForCharge.transform.localRotation = Quaternion.identity;
        this.energyCellForCharge.gameObject.SetActive(true);
    }
        private void enemyHpBarPool()
        {
      
        for (int i = 0; i < this.EnemyCount; i++)
        {
                GameObject go = Instantiate(this.uiHPBarPrefab, this.worldCanvas.transform);
                go.SetActive(false);
                this.enemyHpBarPools.Add(go);
            }
        }
        private GameObject GetEnemyHpBarInPool()
        {
            foreach(GameObject hpBar in enemyHpBarPools)
            {
                if(hpBar.activeSelf == false)
                {
                    return hpBar;               
                }
            }
            return null;
        }
        private GameObject CreateHpBar(Vector3 position)
        {
            GameObject go = this.GetEnemyHpBarInPool();
            go.transform.position = position;
            go.SetActive(true);
            return go;
        }
      
        private IEnumerator CoShowDamageText(Vector3 UIPos)
        {
            this.damageTextUIGo.transform.position = UIPos;
            this.damageTextUIGo.SetActive(true);

            var text = this.damageTextUIGo.GetComponent<TextMeshProUGUI>();
            text.text = string.Format("{0}",this.currGunDamage);
            yield return new WaitForSeconds(0.3f);
            this.damageTextUIGo.SetActive(false);
        }
        // Update is called once per frame
        void Update()
        {
      
        if (activeHPBar.Count != 0)
        {
            for (int i = 0; i < this.listEnemies.Count; i++)
            {
                Debug.LogFormat("{0}, {1}", this.activeHPBar[i], this.listEnemies[i]);
                this.activeHPBar[i].transform.position = this.listEnemies[i].hpBarPoint.position;

            }
        }
      
        this.energyTextUIGo.GetComponent<TextMeshProUGUI>().text = string.Format("{0}", this.currGunEnergy);

        this.rightHand.isAttack = true;
        if(this.currGunEnergy <= 0)
        {
            this.gunEnergyCellGo.SetActive(false);
            this.rightHand.isAttack = false;
        }

        if (isFirstHP)
        {
            this.guideText.gameObject.SetActive(true);
            this.guideText.text = "물약을 잡아 HP를 회복하세요.";
        }


    }
    //Methods
    //----------------------------------SJY Enemy1Move Main-----------------------------------------------------------

    private IEnumerator CoStartSpawnEnemy1()
    {
        this.remainEnemyCount = maxWaveEnemyCount[(int)this.wave];
        for (int i = 0; i < this.EnemyCount; i++)
        {
            yield return new WaitForSeconds(5f);
            this.SpawnEnemy1();          
        }
    }

    private void SpawnEnemy1()
    {
        float x = UnityEngine.Random.Range(-3f, 3f);
        float z = UnityEngine.Random.Range(10f, 15f);
        while (true)
        {
            int layer = 1 << 3 | 1 << 6 | 1 << 7;
            //Debug.Log(layer.ToBinaryString());
            //Debug.Log(enemy.gameObject.layer.ToString());
            Collider[] hit = new Collider[10];
            int num = Physics.OverlapSphereNonAlloc(this.arrTargetPos[2].position + Vector3.right * x
                + Vector3.forward * z, 2f, hit, layer);
            if (num == 0)
                break;
            x = UnityEngine.Random.Range(-3f, 3f);
            z = UnityEngine.Random.Range(10f, 20f);
        }

        Vector3 pos = this.arrTargetPos[2].position + Vector3.right * x + Vector3.forward * z;
        int idx = 0;
        int number = UnityEngine.Random.Range(0, 10);
        switch (this.wave)
        {
            case eWave.WAVE1:
                idx = (int)EnemyMove.eEnemyType.Enemy1;
                break;
            case eWave.WAVE2:
                if (number < 3)
                {
                    idx= (int)EnemyMove.eEnemyType.Enemy1;
                }
                else
                    idx=(int)EnemyMove.eEnemyType.Enemy2;
                break;
            case eWave.WAVE3:
                if (number < 2)
                {
                    idx = (int)EnemyMove.eEnemyType.Enemy1;
                }
                else if (number < 4)
                {
                    idx = (int)EnemyMove.eEnemyType.Enemy2;
                }
                else
                {
                    idx = (int)EnemyMove.eEnemyType.Enemy3;
                }
                break;
        }

        GameObject enemyGo = EnemyPoolManager.instance.EnableEnemy(idx);
        Enemy1Move enemy = enemyGo.GetComponent<Enemy1Move>();
        enemy.Init(pos);
        listEnemies.Add(enemy);
        enemy.onChangeTarget = (idx) =>
        {
            Debug.Log("target change!");
            Debug.LogFormat("<color=yellow>{0} preTargetPos: {1}</color>", enemy.name, arrTargetPos[idx]);
            this.SetTargetPos(enemy);
            this.isTargeted[idx] = false;
        };
        enemy.onDieEnemy = (enemy) =>
        {
            this.remainEnemyCount--;
            listEnemies.Remove(enemy);
            this.isTargeted[enemy.target.Key] = false;
            EnemyPoolManager.instance.DisableEnemy(enemy.gameObject);
            if (this.remainEnemyCount >= this.EnemyCount)
            {
                Invoke("SpawnEnemy1", 2f);
            }
            else
            {
                if (this.remainEnemyCount == 0)
                {
                    Debug.LogFormat("{0} completed", this.wave.ToString());
                    if (this.wave == eWave.WAVE3) return;
                    this.wave++;
                    this.StartCoroutine(CoStartSpawnEnemy1());
                }
            }
        };
        this.SetTargetPos(enemy);
        this.OnGenerateEnemy(enemy);
    }

    private void SetTargetPos(Enemy1Move enemy)
    {
        List<int> listIndex = new List<int>();
        for (int i = 0; i < this.isTargeted.Count; i++)
        {
            if (!isTargeted[i])
            {
                listIndex.Add(i);
            }
        }
        int rand = UnityEngine.Random.Range(0, listIndex.Count);
        int idx = listIndex[rand];
        enemy.UpdateTargetPos(idx, this.arrTargetPos[idx]);
        this.isTargeted[idx] = true;
        Debug.LogFormat("<color=magenta>{0} curTargetPos: {1}</color>", enemy.name, arrTargetPos[idx]);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

    public class Enemy1Move : EnemyMove
    {
    public Action<EnemyData> OnGetData;
    public Action<int> OnGetHit;
    public Transform hpBarPoint;
    public int currHP = 0;
    private int maxHP = 0;
    public Action<Enemy1Move> onDieEnemy;
    private void Awake()
    {
        this.OnGetData = (data) =>
        {
            //this.currHP = data.enemyHp; ;//set HP;
            this.maxHP = data.enemyHp; ;//set HP;
            this.currHP = this.maxHP;
        };

    }
    private void Start()
        {
            this.rBody = GetComponent<Rigidbody>();

            
        this.OnGetHit = (damage) =>
        {
            this.currHP -= damage;
        };

    }

        private void FixedUpdate()
        {
            this.Detect();
            this.DecideDir();
            this.Move();

        if(this.currHP <= 0)
        {
            Debug.Log("<color=red>Enemy1 Die!!!!!!!!!</color>");
           // this.gameObject.SetActive(false);
            this.onDieEnemy(this);
        }
        }

        public override void Init(Vector3 pos)
        {
            base.Init(pos);
            this.currHP = this.maxHP;
        }

        public override void Detect()
        {
            base.Detect();
        }

        public override void DecideDir()
        {
            base.DecideDir();
        }

        public override void Move()
        {
            base.Move();
        }

        public override void RecurDrawAndHitRay(Vector3 pos1, Vector3 pos2, int depth)
        {
            base.RecurDrawAndHitRay(pos1, pos2, depth);
        }

        public override void DrawAndHitRay(Ray ray)
        {
            base.DrawAndHitRay(ray);
        }

        public override void UpdateTargetPos(int idx, Transform targetTrans)
        {
            base.UpdateTargetPos(idx, targetTrans);
        }

        public override IEnumerator CoChangeTarget()
        {
            return base.CoChangeTarget();
        }

        public override void OnDrawGizmos()
        {
            base.OnDrawGizmos();
        }
    }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

    public class RightHandController : MonoBehaviour
    {
        public System.Action<Vector3, GameObject> OnHitEnemy;
        public System.Action OnShoot;

        [SerializeField] Transform shootTrans;
        [SerializeField] Transform shootDistance;
        [SerializeField] GameObject gunLaserGo;
        [SerializeField] GameObject impactEffectGo;

        private GameObject gunLaserBeamGo;
        private GameObject laserImpactGo;

        public bool isAttack = false;

        // Start is called before the first frame update
        void Start()
        {

        //this.gunLaserBeamGo = Instantiate<GameObject>(this.gunLaserGo);
            this.gunLaserBeamGo = this.gunLaserGo;
            this.laserImpactGo = Instantiate<GameObject>(this.impactEffectGo);
            this.gunLaserBeamGo.SetActive(false);
            this.laserImpactGo.SetActive(false);
        }

        // Update is called once per frame
        void Update()
        {
        if (isAttack)
        {
            this.gunLaserBeamGo.transform.position = this.shootTrans.position;

            if (OVRInput.GetDown(OVRInput.Button.SecondaryIndexTrigger))
            {
                Debug.Log("right Hand Index Trigger");
                StartCoroutine(this.CoLaserBeam());
                StartCoroutine(this.CoCheckImpact());

                this.OnShoot();
            }



        }
        }

        private IEnumerator CoLaserBeam()
        {
            //this.gunLaserBeamGo.transform.position = this.shootTrans.position;
            this.gunLaserBeamGo.SetActive(true);
            this.gunLaserBeamGo.transform.LookAt(this.shootDistance.position);//hit nothing



            yield return new WaitForSeconds(0.2f);
            this.gunLaserBeamGo.SetActive(false);
            this.laserImpactGo.SetActive(false);
        }
        private IEnumerator CoCheckImpact()
        {
            //-----------------------------check impact---------------------------------------


            Ray ray = new Ray(this.shootTrans.position, this.gunLaserBeamGo.transform.forward);
            Debug.DrawRay(ray.origin, ray.direction * 20f, Color.red, 0.3f);
            var layerMask = 3 << LayerMask.NameToLayer("Monster");
            RaycastHit hit;

            if (Physics.Raycast(ray.origin, ray.direction, out hit, 20.0f))
            {
                // Debug.Log("Hit Monster!!");
                if (!hit.collider.gameObject.CompareTag("Vehicle"))
                { this.CreateImpactEffect(hit.point); }

                if (hit.collider.gameObject.CompareTag("Enemy1")|| hit.collider.gameObject.CompareTag("Enemy2")|| hit.collider.gameObject.CompareTag("Enemy3"))
                {
                    Debug.Log("Enemy");
                    this.OnHitEnemy(hit.point, hit.collider.gameObject);
                }
                var particleSys = this.gunLaserBeamGo.GetComponent<ParticleSystemRenderer>();
                particleSys.lengthScale = hit.distance;
            }
        else
        {
            var particleSys = this.gunLaserBeamGo.GetComponent<ParticleSystemRenderer>();
            particleSys.lengthScale = 12f;
        }
            //-----------------------------------------------------------------------------------
            yield return null;
        }
        private void CreateImpactEffect(Vector3 pos)
        {
            this.laserImpactGo.transform.position = pos;
            this.laserImpactGo.SetActive(true);
        }

    }