using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace GameMain
{
public class PlayerAttackSceneMain : MonoBehaviour
{
[SerializeField]
private Button btnAttack;
[SerializeField]
private HeroController heroController;
[SerializeField]
private MonsterController monsterController;
[SerializeField]
private GameObject hitFxPrefab;
[SerializeField]
private GameObject grave;
// Start is called before the first frame update
void Start()
{
this.heroController.onMoveComplete = (target) =>
{
Debug.LogFormat("<color=cyan>이동을 완료 했습니다. : {0}</color>", target);
//타겟이 있다면 공격 애니메이션 실행
if (target != null)
{
this.heroController.Attack(target);
}
};
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.monsterController.onDie = () =>
{
GameObject grave = Instantiate(this.grave);
grave.transform.position = monsterController.transform.position;
};
this.btnAttack.onClick.AddListener(() => {
Vector3 a = heroController.gameObject.transform.position;
Vector3 b = monsterController.gameObject.transform.position;
Vector3 c = b - a;
//시작위치, 방향
float distance = c.magnitude;
float radius = this.heroController.Radius + this.monsterController.Radius;
Debug.LogFormat("radius: {0}", radius);
Debug.LogFormat("IsWithinRange: <color=lime>{0}</color>", this.IsWithinRange(distance, radius));
if (this.IsWithinRange(distance, radius))
{
this.heroController.Attack(this.monsterController);
}
});
}
private bool IsWithinRange(float distance, float radius)
{
return radius > distance;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float maxDistance = 100f;
Debug.DrawRay(ray.origin, ray.direction * maxDistance, Color.red, 3f);
//Debug.LogFormat("-> {0}", this.transform.position == null);
//if (this.transform.position == null)
//{
//}
//this.transform.position = null;
RaycastHit hit;
if (Physics.Raycast(ray, out hit, maxDistance))
{
//클릭한 오브젝트가 몬스터라면
if (hit.collider.tag == "Monster")
{
//거리를 구한다
float distance = Vector3.Distance(this.heroController.gameObject.transform.position,
hit.collider.gameObject.transform.position);
MonsterController monsterController = hit.collider.gameObject.GetComponent<MonsterController>();
//각 반지름더한거와 비교
float sumRadius = this.heroController.Radius + monsterController.Radius;
Debug.LogFormat("{0}, {1}", distance, sumRadius);
//사거리 안에 들어옴
if (distance <= sumRadius)
{
//공격
}
else
{
//이동
this.heroController.Move(monsterController);
//this.heroController.Move(hit.point);
}
}
else if (hit.collider.tag == "Ground")
{
this.heroController.Move(hit.point);
}
}
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using System;
namespace GameMain
{
public class MonsterController : MonoBehaviour
{
[SerializeField]
private float radius = 1f;
private float hp = 40;
public float Radius
{
get { return this.radius; }
}
private Animator anim;
public Action onHit;
public Action onDie;
private enum eState
{
Idle, Hit, Die
}
eState state;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
public void HitDamage(int atk)
{
this.hp -= atk;
if (this.hp <= 0)
{
this.StartCoroutine(this.WaitForCompleteDieAnimation());
}
else
{
Debug.Log("피해를 입었습니다");
this.onHit();
this.anim.SetInteger("State", (int)eState.Hit);
}
}
private IEnumerator WaitForCompleteDieAnimation()
{
this.anim.SetInteger("State", (int)eState.Die);
yield return new WaitForSeconds(1.66f);
this.onDie();
Destroy(this.gameObject);
}
private void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.radius);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace GameMain
{
public class HeroController : MonoBehaviour
{
public enum eState
{
Idle, Attack, Attack2
}
private Vector3 targetPosition;
private MonsterController target;
public System.Action<MonsterController> onMoveComplete;
private Coroutine moveRoutine;
[SerializeField]
private eState state;
private float radius = 1f;
public float impactTime = 0.4f;
[SerializeField]
private MonsterController monsterController;
private Coroutine attackRoutine;
private int atk = 10;
public float Radius
{
get { return this.radius; }
}
private Animator anim;
// Start is called before the first frame update
void Start()
{
this.anim = this.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
public void Move(MonsterController target)
{
this.target = target;
this.targetPosition = this.target.gameObject.transform.position;
if (this.moveRoutine != null)
{
//이미 코루틴이 실행중이다 -> 중지
this.StopCoroutine(this.moveRoutine);
}
this.moveRoutine = this.StartCoroutine(this.CoMove());
}
public void Move(Vector3 targetPosition)
{
//타겟을 지움
this.target = null;
//이동할 목표지점을 저장
this.targetPosition = targetPosition;
Debug.Log("Move");
if (this.moveRoutine != null)
{
//이미 코루틴이 실행중이다 -> 중지
this.StopCoroutine(this.moveRoutine);
}
this.moveRoutine = this.StartCoroutine(this.CoMove());
}
private IEnumerator CoMove()
{
while (true)
{
//방향을 바라봄
this.transform.LookAt(this.targetPosition);
//이미 바라봤으니깐 정면으로 이동 (relateTo : Self/지역좌표)
this.transform.Translate(Vector3.forward * 1f * Time.deltaTime);
//목표지점과 나와의 거리를 잼
float distance = Vector3.Distance(this.transform.position, this.targetPosition);
//Debug.Log(distance);
//0이 될수 없다 가까워질때 도착한것으로 판단 하자
//타겟이 있을경우
if (this.target != null)
{
if (distance <= (1f + 1f))
{
break;
}
}
else
{
if (distance <= 0.1f)
{
break;
}
}
yield return null; //다음 프레임 시작
}
Debug.Log("<color=yellow>도착!</color>");
this.anim.SetInteger("State", 0);
//대리자를 호출
this.onMoveComplete(this.target);
}
public void Attack(MonsterController target)
{
this.transform.LookAt(target.transform.position);
this.PlayAnimation(eState.Attack);
}
private void PlayAnimation(eState state)
{
if (this.state != state)
{
Debug.LogFormat("{0} => {1}", this.state, state);
this.state = state;
this.anim.SetInteger("State", (int)state);
switch (state)
{
case eState.Attack:
if (this.attackRoutine != null)
{
this.StopCoroutine(this.attackRoutine);
}
this.attackRoutine = this.StartCoroutine(WaitForCompleteAttackAnimation());
// this.WaitForCompleteAnimation(0.833f);
break;
}
}
else
{
if (this.state == eState.Attack)
{
this.state = state;
this.anim.SetInteger("State", (int)eState.Attack2);
}
}
}
private IEnumerator WaitForCompleteAttackAnimation()
{
yield return null;
Debug.Log("공격 애니메이션이 끝날때까지 기다림");
AnimatorStateInfo animStateInfo = this.anim.GetCurrentAnimatorStateInfo(0);
bool isAttackState = animStateInfo.IsName("Attack01");
Debug.LogFormat("isAttackState: {0}", isAttackState);
if (isAttackState)
{
Debug.LogFormat("animStateInfo.length: {0}", animStateInfo.length);
}
else
{
Debug.LogFormat("Attack State가 아닙니다");
}
yield return new WaitForSeconds(this.impactTime);
monsterController.HitDamage(this.atk);
yield return new WaitForSeconds(animStateInfo.length - this.impactTime);
this.PlayAnimation(eState.Idle);
}
private void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, this.radius);
}
}
}
'유니티 기초' 카테고리의 다른 글
보스 추적 및 돌아가기 (1) | 2023.08.14 |
---|---|
몬스터 아이템 드랍 + 장착(?)하고 포탈로 이동하기 (0) | 2023.08.10 |
바구니 게임 (0) | 2023.08.07 |
유닛 이동하여 공격하기 (0) | 2023.08.04 |
유니티짱 마우스로 움직이기 (0) | 2023.08.04 |