유니티 기초

몬스터 아이템 드랍 + 장착(?)하고 포탈로 이동하기

송현호 2023. 8. 10. 17:41
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Test3;
using static Test3.GameEnums;

public class ItemGenerator : MonoBehaviour
{
    [SerializeField]
    private List<GameObject> prefabList;
    // Start is called before the first frame update
    public Action onDie;
    void Start()
    {
        
    }

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

    public ItemController Generate(GameEnums.eItemType itemType, Vector3 initPosition)
    {
        int index = (int)itemType;
        Debug.LogFormat("index: {0}", index);
        //프리팹 배열에서 인덱스로 프리팹 가져옴
        GameObject prefab = this.prefabList[index];
        Debug.LogFormat("prefab: {0}", index);
        //프리팹 인스턴스를 생성 
        GameObject go = Instantiate(prefab);    //위치를 결정 하지 않은 상태이기때문 (프리팹의 설정된 위치에 생성됨)
                                                //위치를 설정
        go.transform.position = initPosition;
        return go.GetComponent<ItemController>();
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace Test3
{
    public class ItemController : MonoBehaviour
    {
        public GameEnums.eItemType itemType;
        // Start is called before the first frame update
        void Start()
        {
        }

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

        }

        public void OnTriggerEnter(Collider other)
        {
            if (other.tag == "Hero")
            {
                HeroController heroController = other.gameObject.GetComponent<HeroController>();
                heroController.GetItem(this.gameObject);
                Destroy(this.gameObject);
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace Test3
{
    public class HeroController : MonoBehaviour
    {
        public Animator anim;
        private Coroutine moveRoutine;
        private MonsterController target;
        private Vector3 targetPosition;
        private Action getItem;
        [SerializeField]
        // Start is called before the first frame update
        void Start()
        {
            anim = GetComponent<Animator>();
        }

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

        }

        public void Move(Vector3 targetPosition)
        {
            //타겟을 지움 
            this.target = null;

            //이동할 목표지점을 저장 
            this.targetPosition = targetPosition;
            Debug.Log("Move");

            this.anim.SetInteger("State", 1);

            if (this.moveRoutine != null)
            {
                //이미 코루틴이 실행중이다 -> 중지 
                this.StopCoroutine(this.moveRoutine);
            }
            this.moveRoutine = this.StartCoroutine(this.CoMove());
        }

        private IEnumerator CoMove()
        {
            while (true)
            {
                //방향을 바라봄 
                this.transform.LookAt(this.targetPosition);
                //이미 바라봤으니깐 정면으로 이동 (relateTo : Self/지역좌표)
                this.transform.Translate(Vector3.forward * 1f * Time.deltaTime);
                //목표지점과 나와의 거리를 잼 
                float distance = Vector3.Distance(this.transform.position, this.targetPosition);
                //Debug.Log(distance);
                //0이 될수 없다 가까워질때 도착한것으로 판단 하자 

                //타겟이 있을경우 
                if (this.target != null)
                {
                    if (distance <= (1f + 1f))
                    {
                        break;
                    }
                }
                else
                {
                    if (distance <= 0.1f)
                    {
                        break;
                    }
                }


                yield return null;  //다음 프레임 시작 
            }

            Debug.Log("<color=yellow>도착!</color>");
            this.anim.SetInteger("State", 0);
            //대리자를 호출
        }
        public void GetItem(GameObject item)
        {
            GameObject Sword = Instantiate(item, this.transform);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Test3
{
    public class PortalController : MonoBehaviour
    {
        // Start is called before the first frame update
        void Start()
        {

        }

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

        }

        public void OnTriggerEnter(Collider other)
        {
            if(other.gameObject.tag == "Hero")
            {
                SceneManager.LoadScene("BossScene");
            }
        }
        
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Test3 { 

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

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

namespace Test3
{
    public class MonsterGenerator : MonoBehaviour
    {
        [SerializeField]
        private List<GameObject> prefabList;    //동적 배열
        // Start is called before the first frame update
        public Action onDie;
        void Start()
        {
            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];
            Debug.LogFormat("prefab: {0}", index);
            //프리팹 인스턴스를 생성 
            GameObject go = Instantiate(prefab);    //위치를 결정 하지 않은 상태이기때문 (프리팹의 설정된 위치에 생성됨)
            //위치를 설정
            go.transform.position = initPosition;
            return go.GetComponent<MonsterController>();
        }
    }

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

namespace Test3
{
    public class MonsterController : MonoBehaviour
    {
        private GameEnums.eItemType itemType;
        public Action<GameEnums.eItemType> onDie;
        [SerializeField]
        private Animator anim;
        // Start is called before the first frame update
        void Start()
        {
            anim = GetComponent<Animator>();
        }

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

        }

        public void Die()
        {
            bool state = false;
            AnimationClip[] animationClips = anim.runtimeAnimatorController.animationClips;
            for(int i = 0; i < animationClips.Length; i++)
            {
                if (animationClips[i].name == "Die")
                {
                    state = true;
                }
            }
            if (state)
            {
                StartCoroutine(CoDie());
            }
            else
            {
                this.onDie(this.itemType);
            }
            
        }

        public IEnumerator CoDie()
        {
            this.anim.SetInteger("State", 2);
            yield return new WaitForSeconds(2.5f);
            this.onDie(this.itemType);
        }

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


namespace Test3
{
    public class TestCreatePortalMain : MonoBehaviour
    {
        [SerializeField]
        private GameObject hero;
        private HeroController heroController;
        [SerializeField]
        private MonsterGenerator monsterGenerator;
        private List<MonsterController> monsterList;
        [SerializeField]
        private PortalController portalController;
        [SerializeField]
        private List<ItemController> itemList;
        [SerializeField]
        private ItemGenerator itemGenerator;
        // Start is called before the first frame update
        void Start()
        {
            heroController = CreateHero(new Vector3(-3, 0, -3));
            this.monsterList = new List<MonsterController>();
            MonsterController turtle = this.monsterGenerator.Generate(GameEnums.eMonsterType.Turtle, new Vector3(0,0,3));
            turtle.onDie = (itemType) =>
            {
                this.itemGenerator.Generate(itemType, turtle.transform.position);
                Destroy(turtle.gameObject);
            };
            MonsterController slime = this.monsterGenerator.Generate(GameEnums.eMonsterType.Slime, new Vector3(3, 0, 0));
            slime.onDie = (itemType) =>
            {
                this.itemGenerator.Generate(itemType, slime.transform.position);
                Destroy(slime.gameObject);
            };


            this.monsterList.Add(turtle);
            this.monsterList.Add(slime);

            this.itemList = new List<ItemController>();

            //this.monsterGenerator.onDie = () => {

            //    //아이템을 생성한다 
            //    //Instantiate(ItemList[]);
            //    ItemController item = this.itemGenerator.Generate(dropItemType);
            //    this.itemList.Add(item);

            //};

            


        }

        // Update is called once per frame
        void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                float maxDistance = 100f;
                Debug.DrawRay(ray.origin, ray.direction, Color.red, 3f);
                RaycastHit hit;
                if (Physics.Raycast(ray, out hit, maxDistance))
                {
                    MonsterController controller = hit.collider.gameObject.GetComponent<MonsterController>();
                    if(controller != null)
                    {
                        this.monsterList.Remove(controller);

                        controller.Die();
                        Debug.LogFormat("남은 수: {0}",this.monsterList.Count);
                        if (this.monsterList.Count == 0)
                        {
                            this.CreatePortal();
                        }
                    }
                    else if (hit.collider.tag == "Ground")
                    {
                        Debug.Log(hit.point);
                        this.heroController.Move(hit.point);
                    }
                }
            }

        }

        public void CreatePortal()
        {
            Instantiate(portalController);
        }

        public HeroController CreateHero(Vector3 initPosition)
        {
            GameObject go = Instantiate(hero);
            go.transform.position = initPosition;
            return go.GetComponent<HeroController>();
        }

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

    }
}

 

개선점 - 획득한 아이템 원할 때 장착하기, 장착한 아이템 위치/각도 조정하기, UI꾸미기