일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 팀프로젝트
- 가상현실
- 팀 프로젝트
- CGV
- 오브젝트 풀링
- 앱 배포
- 개발일지
- 오큘러스
- 유니티
- HAPTIC
- OVR
- Photon Fusion
- 개발
- 연습
- input system
- 모작
- XR
- 드래곤 플라이트
- 멀티플레이
- 유니티 UI
- 길건너 친구들
- meta
- 드래곤 플라이트 모작
- meta xr
- 포트폴리오
- Oculus
- 유니티 GUI
- VR
- 유니티 Json 데이터 연동
- ChatGPT
Archives
- Today
- Total
EasyCastleUNITY
간단 RPG Test2-2 본문
영웅이 몬스터를 바라봄, 피격 애니메이션 및 이펙트
ParticleDestroyer: 이펙트 삭제
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Test2
{
public class ParticleDestroyer : MonoBehaviour
{
private ParticleSystem ps;
// Start is called before the first frame update
void Start()
{
this.ps = this.GetComponent<ParticleSystem>();
//코루틴 실행
this.StartCoroutine(this.CoWaitForPlayAfterDestroy());
}
private IEnumerator CoWaitForPlayAfterDestroy()
{
//duration 만큼 기다렸다가 (프레임 경과)
yield return new WaitForSeconds(this.ps.main.duration);
Destroy(this.gameObject);
}
}
}
HeroController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Test2
{
public class HeroController : MonoBehaviour
{
public enum eState
{
Idle,Attack
}
[SerializeField]
private float radius = 1.0f;
[SerializeField]
private MonsterController monster;
private Animator anim;
private eState state;
private float impactTime = 0.399f;
private MonsterController target;
public float Radius
{
get
{
return this.radius;
}
}
// Start is called before the first frame update
void Start()
{
this.anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
this.transform.LookAt(monster.transform.position);
}
public void Attack(MonsterController target)
{
this.target = target;
//공격애니메이션을 1회 실행
this.PlayAnimation(eState.Attack);
//Debug.LogError("Stop");
}
private void PlayAnimation(eState state)
{
//this.state : prev 현재, state: current: 미래
//중복막기
if(this.state != state)
{
Debug.LogFormat("State: {0} -> {1}", this.state, state);
this.state = state;
this.anim.SetInteger("State", (int)state);
switch (state)
{
case eState.Attack:
this.StartCoroutine(this.WaitForCompleteAttackAnimation());
break;
}
}
else
{
Debug.LogFormat("{0}은 현재와 동일한 상태입니다.", state);
}
}
//코루틴 함수
//Update와 동일하게 동작 가능
private IEnumerator WaitForCompleteAttackAnimation()
{
yield return null; //1프레임 건너뜀
Debug.Log("공격 애니메이션이 끝날때까지 기다림");
AnimatorStateInfo animStateInfo = this.anim.GetCurrentAnimatorStateInfo(0);
//실제 애니메이션 이름으로 찾아야 한다
bool isAttackState = animStateInfo.IsName("Attack01");
Debug.LogFormat("isAttackState: {0}", isAttackState);
if (isAttackState)
{
Debug.LogFormat("Hero's animStateInfo.length: {0}", animStateInfo.length);
}
else
{
Debug.LogFormat("Attack State가 아닙니다");
}
yield return new WaitForSeconds(this.impactTime);
Debug.Log("<color=red>Impact!!!!</color>");
//대상에게 피해를 입힘
this.target.HitDamage();
yield return new WaitForSeconds(animStateInfo.length-this.impactTime);
//Idle 애니메이션을 함
//this.anim.SetInteger("State", 0);
this.PlayAnimation(eState.Idle);
}
private void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, radius);
}
}
}
MonsterController
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Test2
{
public class MonsterController : MonoBehaviour
{
public enum eMonsterState
{
Idle,GetHit
}
[SerializeField]
private float radius = 1.0f;
private Animator anim;
private eMonsterState monsterState;
private float hitTime = 0.01f;
public Action onHit;
public float Radius
{
get
{
return this.radius;
}
}
// Start is called before the first frame update
void Start()
{
this.anim=GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
public void HitDamage()
{
//피격애니메이션을 1회 실행
//this.PlayAnimation(eMonsterState.GetHit);
this.PlayAnimation(eMonsterState.GetHit);
this.onHit();
}
private void PlayAnimation(eMonsterState monsterState)
{
//중복막기
if(this.monsterState != monsterState)
{
Debug.LogFormat("Monster: {0} -> {1}", this.monsterState, monsterState);
this.monsterState = monsterState;
this.anim.SetInteger("MonsterState", (int)monsterState);
switch(monsterState)
{
case eMonsterState.GetHit:
this.StartCoroutine(this.WaitForCompleteGetHitAnimation());
break;
}
}
else
{
Debug.LogFormat("{0}은 현재와 동일한 상태입니다.", monsterState);
}
}
//코루틴
private IEnumerator WaitForCompleteGetHitAnimation()
{
yield return null;
Debug.Log("피격 애니메이션이 끝날때까지 기다림");
AnimatorStateInfo animStateInfo = this.anim.GetCurrentAnimatorStateInfo(0);
//실제 애니메이션 이름으로 찾아야 한다
bool isGetHit = animStateInfo.IsName("GetHit");
Debug.LogFormat("isGetHit: {0}", isGetHit);
if(isGetHit )
{
Debug.LogFormat("Monster's animStateInfo.length: {0}", animStateInfo.length);
}
else
{
Debug.LogFormat("GetHit State가 아닙니다");
}
yield return new WaitForSeconds(this.hitTime);
Debug.Log("<color=red>Hit!!!!!</color>");
yield return new WaitForSeconds(animStateInfo.length-this.hitTime);
this.PlayAnimation(eMonsterState.Idle);
}
private void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, radius);
}
}
}
Test2_PlayerAttackSceneMain
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Test2
{
public class Test2_PlayerAttackSceneMain : MonoBehaviour
{
[SerializeField]
private Button btnAttack;
[SerializeField]
private HeroController heroController;
[SerializeField]
private MonsterController monsterController;
[SerializeField]
private GameObject hitFxPrefab;
// Start is called before the first frame update
void Start()
{
//이벤트 등록
this.monsterController.onHit = () =>{
Debug.Log("이펙트 생성");
Vector3 offset = new Vector3(0, 0.5f, 0);
Vector3 tpos = this.monsterController.transform.position + offset;
Debug.LogFormat("생성위치: {0}", tpos);
//프리팹 인스턴스 생성
GameObject fxGo = Instantiate(this.hitFxPrefab);
//위치 설정
fxGo.transform.position = tpos;
//파티클 실행
fxGo.GetComponent<ParticleSystem>().Play();
};
this.btnAttack.onClick.AddListener(() =>{
//사거리 체크
//두점과의 거리, 두 오브젝트의 radius의 합을 알아야 한다.
//B-A : C (방향벡터) magnitude (벡터의 길이)
Vector3 b = monsterController.transform.position;
Vector3 a = heroController.transform.position;
Vector3 c = b - a; //정규화되지 않은 방향벡터 (방향과 크기)
float distance = c.magnitude;
Debug.LogFormat("distance:{0}", distance);
Debug.DrawLine(a, b); //영웅과 몬스터 사이의 길이를 출력
//시작위치, 방향 , 출력되는 시간, 색깔, 타입
//DrawArrow.ForDebug(a, c.normalized , 3f,Color.red,ArrowType.Solid);
//Vector3.Distance
//두 컴포넌트의 radius(반지름) 합
float sumRadius = this.heroController.Radius + this.monsterController.Radius;
Debug.LogFormat("sumRadius: {0}", sumRadius);
Debug.LogFormat("<color=yellow>distance: {0}, sumRadius: {1} </color>",
distance, sumRadius);
Debug.LogFormat("isWithinRange: <color=lime>{0}</color>",
this.isWithinRange(distance, sumRadius));
if(this.isWithinRange(distance, sumRadius))
{
//HeroController에게 공격을 명령
this.heroController.Attack(this.monsterController);
}
});
}
//사거리 계산
private bool isWithinRange(float distance, float radius)
{
return radius >= distance; //true
}
// Update is called once per frame
void Update()
{
}
}
}
'유니티 기초' 카테고리의 다른 글
간단 RPG Game Main (몬스터가 전부 죽으면, 포탈 생성) (1) | 2023.08.09 |
---|---|
간단 RPG 게임 메인(수정중) (0) | 2023.08.09 |
간단 RPG Test2-1 (0) | 2023.08.09 |
코드 베이스로 버튼 실행 (0) | 2023.08.09 |
간단 RPG 2-1 (몬스터 피격 애니메이션) (0) | 2023.08.08 |