Unity/게임 엔진 응용 프로그래밍

[Unity 3D] MiniRPG : 랜덤한 위치에 몬스터 생성

치명적흑형 2021. 10. 22. 12:04

버튼 클릭시 몬스터 생성

 

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

public class TestMonsterGenerator : MonoBehaviour
{
    public Button btn;

    public int amount;
    public string[] monsterPrefabNames;
    public List<GameObject> monsterPrefabs;
    public List<Monster> monsters;

    void Start()
    {
        this.monsterPrefabs = new List<GameObject>();
        this.monsters = new List<Monster>();
        this.monsterPrefabNames = new string[] { "SlimePrefab", "TurtleShellPrefab", "ChestMonsterPrefab", "BeholderPrefab"};
        //Debug.Log(this.monsterPrefabNames.Length);

        this.LoadMonsterPrefabs();

        //this.btn.onClick.AddListener(() =>
        //{
        //    Debug.Log("hello!");
        //    for (int i = 0; i < this.amount; i++)
        //    {
        //        CreateMonster();
        //    }
        //});
    }
    private void Update()
    {
        if (this.monsters.Count <= 0)
        {
            for (int i = 0; i < this.amount; i++)
            {
                CreateMonster();
            }
        }
    }
    private void LoadMonsterPrefabs()
    {
        foreach (var prefabName in this.monsterPrefabNames)
        {
            //리소스 폴더 경로설정
            string path = string.Format("Prefabs/Monster/{0}", prefabName);
            GameObject prefab = Resources.Load<GameObject>(path);

            //해당 이름을 가진 프리팹이 리소스 폴더에 바로 있다면
            //GameObject prefab = Resources.Load<GameObject>(prefabName);
            this.monsterPrefabs.Add(prefab);
        }
        Debug.Log(this.monsterPrefabs.Count);
    }
    private void CreateMonster()
    {
        float x = Random.Range(-3f, 3f);
        float z = Random.Range(-3f, 3f);
        Vector3 initPos = new Vector3(x, 0, z);

        GameObject go = new GameObject();
        go.name = "monster";
        go.tag = "Monster";
        int monsterPrefabsIndex = Random.Range(0, this.monsterPrefabs.Count);
        GameObject prefab = this.monsterPrefabs[monsterPrefabsIndex];
        GameObject model = Instantiate<GameObject>(prefab, go.transform);
        model.name = "model";
        Monster monster = go.AddComponent<Monster>();
        this.monsters.Add(monster);

        monster.OnDie = () =>
        {
            Destroy(monster.gameObject);

            //반드시 관리되는 컬렉션에서 제거 
            this.monsters.Remove(monster);
        };

        monster.Init(initPos);
    }
}
//데이터 테이블에서 불러올 프리팹이름
public string[] monsterPrefabNames;

//몬스터 프리팹리스트
public List<GameObject> monsterPrefabs;

//프리팹을 통해 생성된 몬스터 들을 관리    //사망시 리스트에서 제거해줘야된다
public List<Monster> monsters;



//리소스 폴더의 프리팹 경로
string path = string.Format("Prefabs/Monster/{0}", prefabName);
//해당 경로의 프리팹 파일
GameObject prefab = Resources.Load<GameObject>(path);
//리스트에 추가
this.monsterPrefabs.Add(prefab);



//몬스터 사망 이벤트를 받으면
monster.OnDie = () =>
        {
            Destroy(monster.gameObject);

            //반드시 관리되는 컬렉션에서 제거 
            this.monsters.Remove(monster);
        };

 

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

public class Monster : MonoBehaviour
{
    public float hp;
    public float maxHp;
    public float damage;
    public float range;
    public float moveSpeed;

    public GameObject model;
    private Animator anim;

    Coroutine hitRoutin;
    Coroutine attackRoutin;

    bool isHit;
    bool isAttack;
    public bool isDie;

    public UnityAction OnDie;

    private void Start()
    {
        this.model = this.transform.GetChild(0).gameObject;
        this.anim = this.model.GetComponent<Animator>();
    }
    public void Init(Vector3 initPos)
    {
        this.transform.position = initPos;

        this.moveSpeed = 0.5f;
        this.maxHp = 15;
        this.hp = this.maxHp;
        this.damage = 5;
        this.range = 0.3f;
    }

    public void Hit(GameObject hero)
    {
        this.hp -= hero.GetComponent<Hero>().damage;

        //때린 적을 바라본다.
        this.transform.LookAt(hero.transform.position);

        if (this.hitRoutin != null)
        {
            StopCoroutine(this.hitRoutin);
        }
        this.hitRoutin = StartCoroutine(HitAnimImpl());
        if (this.hp <= 0)
        {
            this.OnDie();
            StopCoroutine(this.hitRoutin);
            StartCoroutine(DieAnimImpl());
        }

        //피격이 끝나면
        Attack(hero);
    }
    IEnumerator HitAnimImpl()
    {
        this.isHit = true;
        this.anim.SetBool("isHit", this.isHit);
        yield return new WaitForSeconds(1/30*25);   //1초에 30프레임, 25 애니메이션 프레임
        this.isHit = false;
        this.anim.SetBool("isHit", this.isHit);
        yield return null;
    }
    IEnumerator DieAnimImpl()
    {
        this.isDie = true;
        this.anim.SetBool("isDie", this.isDie);
        yield return new WaitForSeconds(this.anim.GetCurrentAnimatorStateInfo(0).length);
        Destroy(this.gameObject);
    }
    public void Attack(GameObject target)
    {
        //this.transform.LookAt(target.transform.position);
        if (this.attackRoutin != null)
        {
            StopCoroutine(this.attackRoutin);
        }
        this.attackRoutin = StartCoroutine(AttackAnimImpl(target));
        if (this.hp <= 0)
        {
            StopCoroutine(this.attackRoutin);
            StartCoroutine(DieAnimImpl());
        }
    }


    IEnumerator AttackAnimImpl(GameObject target)
    {
        //this.anim.Play("run@loop");
        while (true)
        {
            this.transform.LookAt(target.transform.position);
            float distance = Vector3.Distance(target.transform.position, this.transform.position);
            if (distance <= this.range)
            {
                break;
            }
            this.transform.Translate(Vector3.forward * this.moveSpeed * Time.deltaTime);
            yield return null;
        }



        this.isAttack = true;
        this.anim.SetBool("isAttack", this.isAttack);
        yield return new WaitForSeconds(1 / 30 * 9);

        target.GetComponent<Hero>().Hit(this.gameObject);

        yield return new WaitForSeconds(1 / 30 * 16);
        this.isAttack = false;
        this.anim.SetBool("isAttack", this.isAttack);
        yield return null;
        //this.anim.Play("idle@loop");
    }
}
using UnityEngine.Events;
public UnityAction OnDie;

//사망하면 이벤트를 전달해줘야됨
this.OnDie();

 

 


몬스터가 0마리면 자동생성

 

업데이트에서 몬스터리스트의 카운트가 0이면 생성

 


랜덤한 몬스터가 0마리면 자동생성

 

몬스터 생성시 몬스터 프리팹 리스트의 랜덤한 인덱스를 넣어서 랜덤한 몬스터 생성.

int monsterPrefabsIndex = Random.Range(0, this.monsterPrefabs.Count);