[Unity] 코루틴을 사용, 캐릭터의 이동과 공격, 몬스터의 피격 애니메이션 실행

APP 2019. 11. 15. 11:45

 

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

public class App : MonoBehaviour
{
    public Button btnStage;
    public Button btnHero;
    public Button btnMonster;
    public Button btnAttack;
    public Dictionary<int, CharacterData> dicCharacterData;
    public Dictionary<int, StageData> dicStageData;
    Dictionary<int, GameObject> dicPrefab;    
    private Dictionary<int, Character> dicCharacter;    
    
    private Stage stage;
    private Hero hero;
    private Monster monster;
    private Animation heroAnim;
    private Animation monsterAnim;
    private float speed = 0.05f;
    Coroutine coMoveHero;
    Coroutine coAttackHero;
    Coroutine coIdleHero;
    Coroutine coDamageMonster;
    Coroutine coIdleMonster;

    private void Awake()
    {

        this.dicCharacterData = new Dictionary<int, CharacterData>();
        this.dicStageData = new Dictionary<int, StageData>();
        this.dicPrefab = new Dictionary<int, GameObject>();
        this.dicCharacter = new Dictionary<int, Character>();

        CharacterData[] arrCharacterData = JsonConvert.DeserializeObject<CharacterData[]>(Resources.Load<TextAsset>("Data/character_data").text);

        foreach (CharacterData data in arrCharacterData)
        {
            this.dicCharacterData.Add(data.id, data);
        }

        StageData[] arrStageData = JsonConvert.DeserializeObject<StageData[]>(Resources.Load<TextAsset>("Data/stage_data").text);
        foreach (StageData data in arrStageData)
        {
            this.dicStageData.Add(data.id, data);
        }

        LoadCharacterPrefabs();
        LoadStagePrefabs();
    }
    public void LoadCharacterPrefabs()
    {
        foreach (KeyValuePair<int, CharacterData> keyValuePair in dicCharacterData)
        {
            this.dicPrefab.Add(keyValuePair.Key, Resources.Load<GameObject>($"Prefabs/{keyValuePair.Value.prefab_name}"));
        }
    }
    public void LoadStagePrefabs()
    {
        foreach (KeyValuePair<int, StageData> keyValuePair in dicStageData)
        {
            this.dicPrefab.Add(keyValuePair.Key, Resources.Load<GameObject>($"Prefabs/{keyValuePair.Value.prefab_name}"));
        }
    }

    void Start()
    {


        btnStage.onClick.AddListener(() =>
        {
            Debug.Log("Stage버튼");
            this.CreateStage(dicStageData[1000]);
        });

        btnHero.onClick.AddListener(() =>
        {
            Debug.Log("Hero버튼");
            this.hero = this.CreateCharacter<Hero>(dicCharacterData[100]);
            this.heroAnim = this.hero.GetComponentInChildren<Animation>();
            dicCharacter[100].transform.SetParent(GameUtils.SearchHierarchyForBone(this.stage.transform, "HeroInitPos"), false);
            this.btnAttack.gameObject.SetActive(true);
        });

        btnMonster.onClick.AddListener(() =>
        {
            Debug.Log("Monster버튼");
            this.monster = this.CreateCharacter<Monster>(dicCharacterData[200]);
            dicCharacter[200].transform.SetParent(GameUtils.SearchHierarchyForBone(this.stage.transform, "MonsterInitPos"), false);
            this.monsterAnim = this.monster.GetComponentInChildren<Animation>();
        });

        btnAttack.onClick.AddListener(() =>
        {
            Debug.Log("Attack버튼");
            //Debug.Log(Time.deltaTime);

            coMoveHero = StartCoroutine(MoveHero());
            Debug.Log("Start---------MoveHero");

        });

    }

    public void CreateStage(StageData stageData)
    {
        GameObject go = new GameObject(stageData.name);
        Stage stage = go.AddComponent<Stage>();
        GameObject model = Instantiate(dicPrefab[stageData.id]);
        model.transform.SetParent(stage.transform, false);
        model.transform.localPosition = Vector3.zero;
        this.stage = stage;
    }
    public T CreateCharacter<T>(CharacterData characterData) where T : Character
    {
        GameObject go = new GameObject(characterData.name);
        T character = go.AddComponent<T>();
        GameObject model = Instantiate(dicPrefab[characterData.id]);
        model.transform.SetParent(character.transform, false);
        model.transform.localPosition = Vector3.zero;
        dicCharacter.Add(characterData.id, character);
        return character;
    }

    IEnumerator MoveHero()
    {
        while (true)
        {
            yield return new WaitForSeconds(0.02f);
            //Debug.Log($"{Time.deltaTime}{Vector3.Distance(hero.transform.position, monster.transform.position) > dicCharacterData[100].atk_range} {Vector3.Distance(hero.transform.position, monster.transform.position)}  {dicCharacterData[100].atk_range}");

            //몬스터와 거리가 사거리보다 크다면
            if (Vector3.Distance(hero.transform.position, monster.transform.position) > dicCharacterData[100].atk_range)
            {
                //히어로가 이동한다
                this.hero.transform.position = Vector3.MoveTowards(this.hero.transform.position, this.monster.transform.position, speed);
                
                //run@loop애니메이션을 실행한다
                this.heroAnim.Play("run@loop");

                //Debug.LogFormat("Distance: {0}", Vector3.Distance(hero.transform.position, monster.transform.position));

                //몬스터와 거리가 사거리보다 작다면  idle@loop애니메이션을 실행하고, MoveCharacter() 코루틴을 종료한다.
                if (Vector3.Distance(hero.transform.position, monster.transform.position) <= dicCharacterData[100].atk_range)
                {
                    this.heroAnim.Play("idle@loop");
                    StopCoroutine(coMoveHero);
                    //Debug.Log("Stop---------MoveHero");
                    coAttackHero = StartCoroutine(HeroAttack(0f));
                }
            }
        }
    }
    IEnumerator HeroAttack(float time)
    {
        while (true)
        {
            yield return new WaitForSeconds(time);
            if (Vector3.Distance(hero.transform.position, monster.transform.position) <= dicCharacterData[100].atk_range)
            {
                this.heroAnim.Play("attack_sword_02");
                coDamageMonster = StartCoroutine(MonsterDamage(0.6f));
                Debug.Log("Start---------MonsterDamage");
                StopCoroutine(coAttackHero);
                coIdleHero = StartCoroutine(HeroIdle(0.8f));
                Debug.Log("Start---------HeroIdle");
            }
        }
    }
    IEnumerator HeroIdle(float time)
    {
        while (true)
        {
            yield return new WaitForSeconds(time);
            this.heroAnim.Play("idle@loop");
            coAttackHero = StartCoroutine(HeroAttack(2f));
            Debug.Log("Start---------HeroAttack");
            StopCoroutine(coIdleHero);
        }
    }
    IEnumerator MonsterDamage(float time)
    {
        while (true)
        {
            yield return new WaitForSeconds(time);
            this.monsterAnim.Play("Anim_Damage");
            StopCoroutine(coDamageMonster);
            coIdleMonster = StartCoroutine(MonsterIdle(0.47f));
        }
    }
    IEnumerator MonsterIdle(float time)
    {
        while (true)
        {
            yield return new WaitForSeconds(time);
            this.monsterAnim.Play("Anim_Idle");
            StopCoroutine(coIdleMonster);
        }
    }

    /*수정 이전의 코드*/
    //IEnumerator MoveCharacter()
    //{

    //    while (true)
    //    {
    //        yield return new WaitForSeconds(0.02f);
    //        //Debug.Log($"Dist:{Vector3.Distance(hero.transform.position, monster.transform.position)}  atk_range:{dicCharacterData[100].atk_range}");
    //        if (Vector3.Distance(hero.transform.position, monster.transform.position) > dicCharacterData[100].atk_range)
    //        {
    //            this.hero.transform.position = Vector3.MoveTowards(this.hero.transform.position, this.monster.transform.position, speed);
    //            if (IsHeroAnimPlaying == false)
    //            {
    //                IsHeroAnimPlaying = true;
    //                this.heroAnim.Play("run@loop");
    //            }
    //        }
    //        else if (Vector3.Distance(hero.transform.position, monster.transform.position) <= dicCharacterData[100].atk_range)
    //        {


    //            if (IsMonsterAnimPlaying == true)
    //            {
    //                elapsedTime2 += Time.deltaTime;
    //            }
    //            if (cnt == 0)
    //            {
    //                cnt++;
    //                this.heroAnim.Play("attack_sword_01");
    //                elapsedTime += Time.deltaTime;
    //            }
    //            elapsedTime += Time.deltaTime;
    //            if (0.256f < elapsedTime && elapsedTime < 0.276f)
    //            {
    //                this.monsterAnim.Play("Anim_Damage");
    //                IsMonsterAnimPlaying = true;
    //                elapsedTime2 += Time.deltaTime;
    //                Debug.LogFormat("맞는시간{0}", elapsedTime2);
    //            }
    //            if (0.447f < elapsedTime2 && elapsedTime2 < 0.477f)
    //            {
    //                Debug.LogFormat("초기화시간{0}", elapsedTime2);
    //                this.monsterAnim.Play("Anim_Idle");
    //                elapsedTime2 = 0;
    //                Debug.LogFormat("Time2초기화되었다");
    //            }
    //            if (0.723f < elapsedTime && elapsedTime < 0.743f)
    //            {
    //                IsHeroAnimPlaying = false;
    //                elapsedTime = 0;
    //                cnt = 0;
    //            }
    //        }
    //    }
    //}
    // Update is called once per frame
    //void Update()
    //{
    //    if (hero != null && monster != null)
    //    {
    //        if (Vector3.Distance(hero.transform.position, monster.transform.position) <= dicCharacterData[100].atk_range)
    //        {
    //            monsterDmgElapsedTime += Time.deltaTime;
    //            this.heroAnim.Play("attack_sword_02");
    //            IsHeroAnimPlaying = true;
    //            elapsedTime += Time.deltaTime;
    //            Debug.Log($"첫번째elapsedTime:{elapsedTime}");
    //            if (IsHeroAnimPlaying == true)
    //            {
    //                Debug.Log(elapsedTime);
    //                elapsedTime += Time.deltaTime;
    //            }
    //            if (IsHeroAnimPlaying == false)
    //            {
    //                if (cnt < 5)
    //                {
    //                    cnt++;
    //                    this.heroAnim.Play("attack_sword_02");
    //                    IsHeroAnimPlaying = true;
    //                    elapsedTime += Time.deltaTime;
    //                    Debug.Log($"첫번째elapsedTime:{elapsedTime}");
    //                }
    //            }
    //            영웅이 칼을 타점에 맞추는 시간
    //            if (0.59f < elapsedTime && elapsedTime < 0.61f)
    //            {
    //                monsterDmgElapsedTime = 0;
    //                IsMonsterAnimPlaying = true;
    //                Debug.LogFormat("몬스터 애니메이션 ElapsedTime2 : {0}", elapsedTime2);
    //            }
    //            if (IsMonsterAnimPlaying)
    //            {
    //                this.monsterAnim.Play("Anim_Damage");
    //                monsterDmgElapsedTime += Time.deltaTime;
    //            }
    //            영웅의 공격 동작이 끝나는 시간
    //            if (0.79f < elapsedTime/* && elapsedTime < 0.81f*/)
    //            {
    //                IsHeroAnimPlaying = false;
    //                elapsedTime = 0;
    //                IsMonsterAnimPlaying = false;
    //            }

    //            몬스터의 피격 동작이 끝나는 시간
    //            if (0.467f < monsterDmgElapsedTime)
    //            {
    //                this.monsterAnim.Play("Anim_Idle");
    //                IsMonsterAnimPlaying = false;
    //                monsterDmgElapsedTime = 0;
    //                if (IsMonsterAnimPlaying != true)
    //                {

    //                    IsMonsterAnimPlaying = true;
    //                }
    //            }
    //        }
    //    }
    //}
}

 

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

public class Character : MonoBehaviour
{    
    public void InitPos(GameObject InitPos)
    {
        this.transform.SetParent(InitPos.transform);
    } 
}

 

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

public class CharacterData
{
    //int string  int int       float       string
    //id  name    hp  damage    atk_range   prefab_name
    public int id;
    public string name;
    public int hp;
    public int damage;
    public float atk_range;
    public string prefab_name;
}

 

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

public class CharacterInfo 
{
   
}

 

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

public static class GameUtils
{
    //HOW TO USE
    //var cube = this.transform.FirstChildOrDefault(x => x.name == "deeply_nested_cube");
    public static Transform FirstChildOrDefault(this Transform parent, Func<Transform, bool> query)
    {
        if (parent.childCount == 0)
        {
            return null;
        }

        Transform result = null;
        for (int i = 0; i < parent.childCount; i++)
        {
            var child = parent.GetChild(i);
            if (query(child))
            {
                return child;
            }
            result = FirstChildOrDefault(child, query);
        }

        return result;
    }


    public static Transform SearchHierarchyForBone(Transform current, string name)
    {
        //sb.Append(current.name + "\n");

        // check if the current bone is the bone we're looking for, if so return it
        if (current.name == name)
            return current;

        // search through child bones for the bone we're looking for
        for (int i = 0; i < current.childCount; ++i)
        {
            // the recursive step; repeat the search one step deeper in the hierarchy
            var child = current.GetChild(i);

            Transform found = SearchHierarchyForBone(child, name);

            // a transform was returned by the search above that is not null,
            // it must be the bone we're looking for
            if (found != null)
                return found;
        }

        // bone with name was not found
        return null;
    }
}

 

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

public class Hero : Character
{
    
}

 

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

public class Monster : Character
{
   
}

 

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

public class Stage : MonoBehaviour
{
    
}

 

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

public class StageData
{
    //int string string
    //id  name prefab_name
    public int id;
    public string name;
    public string prefab_name;
}

 

 

: