[Unity] Delegate와 Coroutine사용 영웅과 몬스터 공격/피격 애니메이션

APP 2019. 11. 27. 23:41

delegate는 static으로 선언함.

 

App.cs

using System;
using UnityEngine;
using UnityEngine.UI;
public class App : MonoBehaviour
{
    public Button btnCreateHero;
    public Button btnCreateMonster;
    public Button btnAttack;
    private Hero hero;
    private Monster monster;
    public static Action DelHeroMoveComplete;
    public static Action DelHeroAttackComplete;

    public static Action<int> DelMonsterDamageStart;
    public static Action DelAnimMonsterDamageComplete;

    // Start is called before the first frame update
    void Start()
    {
        this.btnCreateHero.onClick.AddListener(() => {
            CreateHero();
        });

        this.btnCreateMonster.onClick.AddListener(() => {
            CreateMonster();
        });
        this.btnAttack.onClick.AddListener(() =>
        {
            this.hero.SetTarget(this.monster);
            this.hero.StartMoveCo();
        });
        DelHeroMoveComplete = () =>
        {
            Debug.Log("영웅 이동완료");
            this.hero.StartAttackCo();
            Debug.Log("영웅 공격시작");
        };
        DelHeroAttackComplete = () =>
        {
            Debug.Log("영웅 공격완료");
            this.hero.PlayAnimIdle();
        };
        DelMonsterDamageStart = (damage) =>
        {
            Debug.Log("몬스터 피격시작");
            this.monster.StartHitCo(damage);
        };
        DelAnimMonsterDamageComplete = () =>
        {
            Debug.Log("몬스터 피격애니메이션 끝");
            this.monster.PlayAnimIdle();
        };

    }

    public void CreateHero()
    {
        //GameObject생성
        GameObject go = new GameObject("Hero");
        //Hero Script부착
        this.hero = go.AddComponent<Hero>();
        //prefab 로드
        string path = "Prefabs/ch_01_01";
        GameObject prefab = Resources.Load<GameObject>(path);

        //model생성 및 부착
        GameObject model = Instantiate(prefab);
        this.hero.SetModel(model);
        this.hero.transform.position = Vector3.zero;
    }
    public void CreateMonster()
    {
        //GameObject생성
        GameObject go = new GameObject("Monster");
        //Hero Script부착
        this.monster = go.AddComponent<Monster>();
        //prefab 로드
        string path = "Prefabs/ch_02_01";
        GameObject prefab = Resources.Load<GameObject>(path);

        //model생성 및 부착
        GameObject model = Instantiate(prefab);
        this.monster.SetModel(model);
        this.monster.transform.position = new Vector3(2, 0, 0);
    }
}

Hero.cs

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

public class Hero : MonoBehaviour
{
    private GameObject model;
    private Animation anim;
    public int damage = 1;
    public float atkRange = 0.5f;
    public float speed = 0.05f;
    public Coroutine coMove;
    public Coroutine coAttack;
    public Monster monster;
    public void SetModel(GameObject model)
    {
        if (this.model != null)
        {
            Destroy(this.model);
        }
        //Shell에 Model을 자식으로 추가
        this.model = model;
        this.model.transform.SetParent(this.transform, false);
        this.anim = this.model.GetComponent<Animation>();
    }
    public void SetTarget(Monster monster)
    {
        this.monster = monster;
    }
    public void StartMoveCo()
    {
        coMove = StartCoroutine(Move(monster, App.DelHeroMoveComplete));
    }

    IEnumerator Move(Monster monster, Action DelHeroMoveComplete)
    {
        Vector3 v3;
        while (true)
        {
            yield return new WaitForSeconds(0.02f);
            v3 = monster.transform.position - this.transform.position;

            if (v3.magnitude > atkRange)
            {
                this.transform.forward = v3;
                //애니메이션실행
                this.anim.Play("run@loop");
                //위치이동
                this.transform.position += v3.normalized * speed;
            }
            else //(v3.magnitude <= atkRange)
            {
                this.transform.position = monster.transform.position - v3.normalized * atkRange;
                this.anim.Play("idle@loop");
                StopCoroutine(coMove);
                DelHeroMoveComplete();
            }
        }
    }
    public void StartAttackCo()
    {
        coAttack = StartCoroutine(Attack(monster, App.DelMonsterDamageStart, App.DelHeroAttackComplete));
    }
    public void PlayAnimIdle()
    {
        this.anim.Play("idle@loop");
    }
    IEnumerator Attack(Monster monster, Action<int> DelMonsterDamageStart, Action DelHeroAttackComplete)
    {
        while (monster.hp > 0)
        {
            this.anim.Play("attack_sword_01");
            yield return new WaitForSeconds(0.47f);//타격시점
            DelMonsterDamageStart(this.damage);
            yield return new WaitForSeconds(0.4f);
            DelHeroAttackComplete();
            yield return new WaitForSeconds(2f); //공격딜레이
        }
    }
}

Monster.cs

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

public class Monster : MonoBehaviour
{
    public GameObject model;
    public Animation anim;
    public int hp = 3;
    public Coroutine coHit;
    public void SetModel(GameObject model)
    {
        if (this.model != null)
        {
            Destroy(this.model);
        }
        //Shell에 Model을 자식으로 추가
        this.model = model;
        this.anim = this.model.GetComponent<Animation>();
        this.model.transform.SetParent(this.transform, false);
    }
    public void PlayAnimIdle()
    {
        this.anim.Play("idle@loop");
    }
    public void StartHitCo(int damage)
    {
        coHit = StartCoroutine(Hit(damage));
    }
    IEnumerator Hit(int damage)
    {
        this.anim.Play("damage");
        this.hp -= damage;
        Debug.LogFormat("몬스터가 공격받았습니다. {0}", this.hp);
        yield return new WaitForSeconds(0.8f);
        StopCoroutine(coHit);
        if (this.hp > 0)
        {
            App.DelAnimMonsterDamageComplete();
        }
        else //(this.hp <= 0)
        {
            this.anim.Play("die");
        }
    }
}

 

 

 

 

: