[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;
}
'APP' 카테고리의 다른 글
[Unity] RayCast (0) | 2019.12.06 |
---|---|
[Unity] Delegate와 Coroutine사용 영웅과 몬스터 공격/피격 애니메이션 (0) | 2019.11.27 |
[Unity] Coroutine 사용해서 공격 애니메이션 실행시 문제, 공격 타이밍이 맞지 않음 (0) | 2019.11.15 |
[Unity] 2019-11-14 코루틴 사용 (0) | 2019.11.14 |
[Unity] 코루틴으로 이동하는것 해볼것 (0) | 2019.11.13 |