씬의 몬스터 제거시 포탈 생성 연습(동적 데이터 생성 및 관리)
2023. 8. 10.

씬 기본셋팅

-Main이 Generator에게 명령해서 몬스터를 생성한

다.

메인 코드 수정

-몬스터 제너레이터에 Generate함수를 만들어준다. GameEnums는 몬스터 타입을 담고있다.

 

-코드 수정

동적 생성화면

-몬스터가 제거되면 포탈이 나타나는것을 테스트하기 위해 몬스터 클릭시 제거되는 것으로 한 뒤에 구현해 보았다.

Main수정

 

-몬스터가 제거되면 아이템을 생성하기 위해 GameEnums수정

아이템 타입 정의
Main 수정
Main 수정

 

MonsterController 수정

 

ItemGenerator
몬스터 사망 시 아이템 생성, 몬스터 다죽으면 포탈 생성

hero프리팹에 rigidbody달고, iskynematic 체크, 콜라이더도 넣는다.

아이템에도 콜라이더를 넣어 충돌체크하자.

OnTriggerEnter사용

아이템 먹기
이동해서 아이템 먹기
아이템을 먹고 정보를 item 변수에 저장하여 출력해보았다.

그렇다면 아이템을 먹고 그 아이템이 장비아이템이라면 장착은 어떻게 할까?

hero가 착용하고 있던 아이템을 삭제하고, 그 부분에 새로운 아이템이 장착되어야 할 것이다.

코드가 길어졌으므로 다음 포스팅에 이어 작성하겠다.

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

public class GameEnums
{
  public enum eMonsterType
    {
        Tutle,Slime
    }

  public enum eItemType
    {
        Potion,Sword,Shield
    } 
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Test3
{
    public class MonsterController : MonoBehaviour
    {
        public int monsterhp;
        public System.Action<GameEnums.eItemType> onDie; //대리자변수 선언 
        private GameEnums.eMonsterType monstertype;
        [SerializeField]
        private GameEnums.eItemType rewardItemType;
        private Animator anim;
        // Start is called before the first frame update
        void Start()
        {       
            this.anim = GetComponent<Animator>();
        }

        // Update is called once per frame
        void Update()
        {
            

        }

        public void HitDamage()
        {
            //if (monsterhp <=0) //hp 0 이하
            //{
                this.Die();
          //  }
        }
        private void Die()
        {       
            StartCoroutine(this.CoDie());
        }

        private IEnumerator CoDie()
        {        
            this.anim.SetInteger("State", 3);
            yield return new WaitForSeconds(2.0f);
            this.onDie(this.rewardItemType);   //대리자 호출 
            //죽으면 아이템 타입 리턴
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using Test3;
using UnityEngine;

namespace Test3
{
    public class Test_CreatePortalSceneMain : MonoBehaviour
    {
        [SerializeField]
        private MonsterGenerator monsterGenerator;
        private MonsterController monsterController;
        private ItemGenerator itemGenerator;
        private ItemController itemController;
        private List<MonsterController> monsterList = new List<MonsterController>();
        private List<ItemController> itemList = new List<ItemController>();
        private float maxDistance = 100f;
        [SerializeField]
        private GameObject portalPrefab;
        [SerializeField]
        private GameObject heroPrefab;
        // Start is called before the first frame update
        void Start()
        {
           this.monsterGenerator = GameObject.FindObjectOfType<MonsterGenerator>();
           this.monsterController = GameObject.FindObjectOfType<MonsterController>();
           this.itemGenerator = GameObject.FindObjectOfType<ItemGenerator>();
           this.itemController = GameObject.FindObjectOfType<ItemController>();
           MonsterController turtleController = this.monsterGenerator.Generate(GameEnums.eMonsterType.Tutle, new Vector3(-3, 0, 0));
           turtleController.onDie = (rewardItemType) => {
               Debug.Log("거북이 죽음");
               var pos = turtleController.gameObject.transform.position;            
               Destroy(turtleController.gameObject);
               this.CreateItem(rewardItemType, pos);
           };


            MonsterController slimeController = this.monsterGenerator.Generate(GameEnums.eMonsterType.Slime, new Vector3(0, 0, 3));
            slimeController.onDie = (rewardItemType) =>
            {
                Debug.Log("슬라임 죽음");
                Vector3 pos = slimeController.gameObject.transform.position;
                Destroy(slimeController.gameObject);
                this.CreateItem(rewardItemType, pos);
            };
            //만들어진 개체들을 그룹화 관리 
            //배열, 컬렉션 
            //동적 배열 
            this.monsterList.Add(turtleController);
            this.monsterList.Add(slimeController);
            Debug.LogFormat("this.monsterList.Count: {0}", this.monsterList.Count);
            //리스트의 요소를 출력 
            foreach (MonsterController monster in this.monsterList)
            {
                Debug.LogFormat("monster: {0}", monster);
            }

            

        }

        // Update is called once per frame
        void Update()
        {

            //Ray로 클릭해서 몬스터 제거
            if (Input.GetMouseButton(0))//마우스 좌클릭시
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                Debug.DrawRay(ray.origin, ray.direction * maxDistance, Color.red, 3f);//ray 그리기
                RaycastHit hit;// Raycast에서 out 키워드 사용을 위한 변수 선언        
                if (Physics.Raycast(ray, out hit, maxDistance)) //Ray 충돌검사
                { //충돌감지해서 몬스터 제거
                    monsterController = hit.collider.gameObject.GetComponent<MonsterController>();
                    if (monsterController != null)//몬스터 클릭시
                    {
                        this.monsterList.Remove(monsterController);                     
                           Debug.Log("HitMonster");                  
                           monsterController.HitDamage();
                        
                        if (monsterList.Count <= 0)
                        {//몬스터가 다 제거되면 포탈생성
                            
                            Instantiate(this.portalPrefab);
                            this.portalPrefab.transform.position = new Vector3(6, 0, 10);
                            //영웅 생성
                            Instantiate(this.heroPrefab);
                            this.heroPrefab.transform.position = new Vector3(this.transform.position.x+1,0,0);
                        }
                    }

                }
            }

           
        }
        private void CreateItem(GameEnums.eItemType itemType, Vector3 position)
        {
            this.itemGenerator.GenerateItem(itemType, position);
        }

    }

}
using System;
using System.Collections;
using System.Collections.Generic;
using Test3;
using UnityEngine;

namespace Test3
{
    public class Test_CreatePortalSceneMain : MonoBehaviour
    {
        [SerializeField]
        private MonsterGenerator monsterGenerator;
        private MonsterController monsterController;
        private ItemGenerator itemGenerator;
        private ItemController itemController;
        private List<MonsterController> monsterList = new List<MonsterController>();
        private List<ItemController> itemList = new List<ItemController>();
        private float maxDistance = 100f;
        [SerializeField]
        private GameObject portalPrefab;
        [SerializeField]
        private GameObject heroPrefab;
        // Start is called before the first frame update
        void Start()
        {
           this.monsterGenerator = GameObject.FindObjectOfType<MonsterGenerator>();
           this.monsterController = GameObject.FindObjectOfType<MonsterController>();
           this.itemGenerator = GameObject.FindObjectOfType<ItemGenerator>();
           this.itemController = GameObject.FindObjectOfType<ItemController>();
           MonsterController turtleController = this.monsterGenerator.Generate(GameEnums.eMonsterType.Tutle, new Vector3(-3, 0, 0));
           turtleController.onDie = (rewardItemType) => {
               Debug.Log("거북이 죽음");
               var pos = turtleController.gameObject.transform.position;            
               Destroy(turtleController.gameObject);
               this.CreateItem(rewardItemType, pos);
           };


            MonsterController slimeController = this.monsterGenerator.Generate(GameEnums.eMonsterType.Slime, new Vector3(0, 0, 3));
            slimeController.onDie = (rewardItemType) =>
            {
                Debug.Log("슬라임 죽음");
                Vector3 pos = slimeController.gameObject.transform.position;
                Destroy(slimeController.gameObject);
                this.CreateItem(rewardItemType, pos);
            };
            //만들어진 개체들을 그룹화 관리 
            //배열, 컬렉션 
            //동적 배열 
            this.monsterList.Add(turtleController);
            this.monsterList.Add(slimeController);
            Debug.LogFormat("this.monsterList.Count: {0}", this.monsterList.Count);
            //리스트의 요소를 출력 
            foreach (MonsterController monster in this.monsterList)
            {
                Debug.LogFormat("monster: {0}", monster);
            }

            

        }

        // Update is called once per frame
        void Update()
        {

            //Ray로 클릭해서 몬스터 제거
            if (Input.GetMouseButton(0))//마우스 좌클릭시
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                Debug.DrawRay(ray.origin, ray.direction * maxDistance, Color.red, 3f);//ray 그리기
                RaycastHit hit;// Raycast에서 out 키워드 사용을 위한 변수 선언        
                if (Physics.Raycast(ray, out hit, maxDistance)) //Ray 충돌검사
                { //충돌감지해서 몬스터 제거
                    monsterController = hit.collider.gameObject.GetComponent<MonsterController>();
                    if (monsterController != null)//몬스터 클릭시
                    {
                        this.monsterList.Remove(monsterController);                     
                           Debug.Log("HitMonster");                  
                           monsterController.HitDamage();
                        
                        if (monsterList.Count <= 0)
                        {//몬스터가 다 제거되면 포탈생성
                            
                            Instantiate(this.portalPrefab);
                            this.portalPrefab.transform.position = new Vector3(6, 0, 10);
                            //영웅 생성
                            Instantiate(this.heroPrefab);
                            this.heroPrefab.transform.position = new Vector3(this.transform.position.x+1,0,0);
                        }
                    }

                }
            }

           
        }
        private void CreateItem(GameEnums.eItemType itemType, Vector3 position)
        {
            this.itemGenerator.GenerateItem(itemType, position);
        }

    }

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

public class ItemController : MonoBehaviour
{   
    [SerializeField]GameEnums.eItemType itemType;
    public GameEnums.eItemType ItemType
    {
        get
        {
            return this.itemType;
        }
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Test3
{
    public class MonsterGenerator : MonoBehaviour
    {
        //[SerializeField]
        //private GameObject turtlePrefab;
        //[SerializeField]
        //private GameObject slimePrefab;
       [SerializeField] private List<GameObject> prefabList;//동적 배열: 컬렉션은 사용전 반드시 인스턴스화

        // Start is called before the first frame update
        void Start()
        {
            //foreach(GameObject prefab in this.prefabList)
            //{
            //    Debug.LogFormat("index: {0}, prefab: {1}", index++, prefab);
            //}
           
            for (int i = 0; i < this.prefabList.Count; i++)
            {
                GameObject prefab = this.prefabList[i];
                Debug.LogFormat("index: {0}, prefab: {1}", i, prefab);
            }
        }

        // Update is called once per frame
        void Update()
        {
        }
        public MonsterController Generate(GameEnums.eMonsterType monsterType, Vector3 initPosition)
        {//몬스터 타입에 따라 어떤 프리팹으로 복사본(인스턴스)를 생성할지 결정
            Debug.LogFormat("monstertype: {0}", monsterType);
            int index = (int)monsterType;//몬스터 타입 인덱스로 변경
            Debug.LogFormat("index: {0}", index);
            GameObject prefab = this.prefabList[index];

            GameObject go = Instantiate(prefab);//위치를 결정 하지 않은 상태 (프리팹의 설정된 위치에 생성됨)         
            go.transform.position = initPosition;//위치를 설정
            
            //if(go.GetComponent<MonsterController>() != null)
            //{//부착되어 있다면
            //    Destroy(go.GetComponent<MonsterController>());
            //}
            if (go.GetComponent<MonsterController>()== null)
            {
                //동적으로 컴포넌트를 부착 할수 있음 
                MonsterController controller = go.AddComponent<MonsterController>();
            }
            ////몬스터 타입에 따라 프리팹을 골라내야함
            //switch(monsterType){=>프리팹 하나씩 생성해야함
            //    case GameEnums.eMonsterType.Tutle:
            //       // Instantiate(this.turtlePrefab);
            //        break;
            //}

            return go.GetComponent<MonsterController>();
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using Test3;
using TMPro;
using UnityEngine;

namespace Test3
{
    public class HeroController : MonoBehaviour
    {
        private float maxDistance = 100f;
        private Animator anim;
        private Vector3 targetPosition;
       // private GameEnums.eItemType itemType;
        // Start is called before the first frame update
        void Start()
        {
            this.anim = GetComponent<Animator>();
        }

        // Update is called once per frame
        void Update()
        {
            if(Input.GetMouseButtonDown(0))//좌클릭시
            {            
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                Debug.DrawRay(ray.origin,ray.direction*maxDistance,Color.red,3f);//ray그리기
                RaycastHit hit;
                if(Physics.Raycast(ray, out hit, maxDistance)) //충돌검사
                {
                  
                    // this.transform.position = hit.point;
                    if (hit.collider.tag == "Item")// 아이템 클릭시
                    {
                        
                        Debug.LogFormat("tag:{0}", hit.collider.tag);
                        //this.Move();
                        Move(new Vector3(hit.point.x,0,0));
                    }
                    else if(hit.collider.tag == "Ground")// Ground 클릭시
                    {
                        Debug.LogFormat("tag:{0}", hit.collider.tag);

                        Move(hit.point);
                        
                    }
                }

            }
        }

        private void Move(Vector3 targetPos)
        {   this.targetPosition = targetPos;
            Debug.Log("move");
            StartCoroutine(CoMove());
        }

        private IEnumerator CoMove()
        {
            while(true)
            {
                this.transform.LookAt(this.targetPosition);
                anim.SetInteger("State", 1);//Run animation
                this.transform.Translate(Vector3.forward * 2 * Time.deltaTime);//정면으로 이동
                float distance = Vector3.Distance(this.transform.position, this.targetPosition);
                if (distance < 0.1f)
                {
                    Debug.Log("Stop");
                    anim.SetInteger("State", 0);//Idle
                    break;
                }
                yield return null;
            }
            Debug.Log("<color=yellow>도착!</color>");
        }

        private void OnTriggerEnter(Collider other)
        {
            if (other != null)
            {//충돌하면
                if (other.tag == "Item")
                {
                    Debug.Log("아이템과충돌!");
                    Destroy(other.gameObject);
                    var item = other.gameObject.GetComponent<ItemController>();
                    
                    if (item != null)
                    {
                        Debug.LogFormat("<color=red>ItemType: {0}</color>", item.ItemType);
                    }
                }
            }
        }
    }
}
myoskin