728x90
Main
using System.Collections;
using System.Collections.Generic;
using test;
using UnityEngine;
using UnityEngine.UI;
public class Test_PlayerControlSceneMain : MonoBehaviour
{
[SerializeField]
private HeroController heroController;
void Start()
{
this.heroController.onMoveComplete = (target) =>
{
Debug.LogFormat("<color=cyan>이동을 완료했습니다.: {0}</color>",target);
//타겟이 있다면 공격 애니메이션 실행
if(target != null)
{
this.heroController.Attack(target);
}
};
}
// Update is called once per frame
void Update()
{
//화면을 클릭하면 위치로 Hero가 이동
if (Input.GetMouseButtonDown(0))
{
Debug.Log("Down");
//Ray를 만든다
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float maxDistance = 100f;
//화면에 출력
Debug.DrawRay(ray.origin, ray.direction*maxDistance, Color.red, 3f);
//Ray 충돌검사
RaycastHit hit;
if(Physics.Raycast(ray, out hit, maxDistance))
{
//클릭한 오브젝트가 몬스터라면
if(hit.collider.tag == "Monster")
{
//거리를 구한다
float distance = Vector3.Distance(this.heroController.transform.position, hit.collider.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)
{
//공격
this.heroController.Attack(monsterController);
}
else
{
//이동
this.heroController.Move(monsterController);
//this.heroController.Move(hit.point); 둘이 같은 말
}
}
//클릭한 오브젝트가 몬스터가 아니면(땅이면)
else if(hit.collider.tag == "Ground")
{
this.heroController.Move(hit.point);
}
}
}
}
}
HeroController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace test {
public class HeroController : MonoBehaviour
{
private Vector3 targetPosition;
private Coroutine moveRoutine;
public Animator anim;
public System.Action<MonsterController> onMoveComplete;
public float radius = 1f;
private MonsterController target;
void Start()
{
this.anim = this.GetComponent<Animator>();
}
//Method Overload : 똑같은 이름의 함수일지라도 받아오는 매개변수에 따라 다르게 동작하는 함수
public void Move(MonsterController target)
{
this.target = target;
this.targetPosition = this.target.gameObject.transform.position;
this.anim.SetInteger("State", 1);
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");
//애니메이션 적용하여 달려가기
this.anim.SetInteger("State", 1);
if (this.moveRoutine != null)
{
//이미 코루틴이 실행중이다 -> 이미 실행중인 코루틴 중지
this.StopCoroutine(this.moveRoutine);
}
this.moveRoutine = this.StartCoroutine(this.CoMove());
}
private IEnumerator CoMove()
{
while (true)
{
//방향을 바라봄
this.transform.LookAt(this.targetPosition);
//바라봤으니까 정면으로 이동
this.transform.Translate(Vector3.forward * 2f * Time.deltaTime);
//목표지점과 나와의 거리를 잼
float distance = Vector3.Distance(this.transform.position, this.targetPosition);
Debug.Log(distance);
//0이 될 수 없다. 가까워질때 도착한 것으로 하자
//타겟이 있을경우
if(this.target != null)
{
if(distance <= (1f + 1f)) //hero와 monster의 반지름의 합
{
break;
}
}
else
{
//타겟이 없을 경우
if (distance <= 0.1f)
{
//도착
break;
}
}
yield return null; //다음 프레임 시작
}
Debug.Log("<color = yellow>도착!</color>");
this.anim.SetInteger("State", 0);
//대리자를 호출
this.onMoveComplete(this.target);
}
//기즈모 생성 메서드
private void OnDrawGizmos()
{
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, 1, 40);
}
//공격 메서드
public void Attack(MonsterController target)
{
this.anim.SetInteger("State", 2);
//코루틴 함수 호출
this.StartCoroutine(this.CoAttack());
}
//hero가 무기로 몬스터를 칠때까지(0.1초 이후) 이펙트 효과 생성
private IEnumerator CoAttack()
{
//yield return null; : 다음 프레임 시작
yield return new WaitForSeconds(0.1f); //0.1초 이후
//float elapsedTime = 0; //흐른 시간
//while (true)
//{
// elapsedTime += Time.deltaTime;
// if(elapsedTime > 0.1f)
// {
// break;
// }
// yield return null;
//} :여기까지가 위에 한 줄이랑 결과 같음
Debug.Log("<color=red>Impact!!!!!</color>");
//0.83 - 0.1
yield return new WaitForSeconds(0.73f);
Debug.Log("Attack 애니메이션 종료");
this.anim.SetInteger("State", 0); //공격 후 기본동작으로 전환
}
}
}
MonsterController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonsterController : MonoBehaviour
{
public float radius = 1f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
//기즈모 생성 메서드
private void OnDrawGizmos()
{
GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, 1, 40);
}
}
GizmosExtensions
using UnityEngine;
public class GizmosExtensions
{
private GizmosExtensions() { }
/// <summary>
/// Draws a wire arc.
/// </summary>
/// <param name="position"></param>
/// <param name="dir">The direction from which the anglesRange is taken into account</param>
/// <param name="anglesRange">The angle range, in degrees.</param>
/// <param name="radius"></param>
/// <param name="maxSteps">How many steps to use to draw the arc.</param>
public static void DrawWireArc(Vector3 position, Vector3 dir, float anglesRange, float radius, float maxSteps = 20)
{
var srcAngles = GetAnglesFromDir(position, dir);
var initialPos = position;
var posA = initialPos;
var stepAngles = anglesRange / maxSteps;
var angle = srcAngles - anglesRange / 2;
for (var i = 0; i <= maxSteps; i++)
{
var rad = Mathf.Deg2Rad * angle;
var posB = initialPos;
posB += new Vector3(radius * Mathf.Cos(rad), 0, radius * Mathf.Sin(rad));
Gizmos.DrawLine(posA, posB);
angle += stepAngles;
posA = posB;
}
Gizmos.DrawLine(posA, initialPos);
}
static float GetAnglesFromDir(Vector3 position, Vector3 dir)
{
var forwardLimitPos = position + dir;
var srcAngles = Mathf.Rad2Deg * Mathf.Atan2(forwardLimitPos.z - position.z, forwardLimitPos.x - position.x);
return srcAngles;
}
}
'KDT > 유니티 기초' 카테고리의 다른 글
23/08/09 SimpleRPG 몬스터 공격 및 데미지 받기 (0) | 2023.08.09 |
---|---|
23/08/08 복습 - 내용정리 (0) | 2023.08.08 |
23/08/07 과제-복습 (0) | 2023.08.07 |
23/08/07 AppleCatch (0) | 2023.08.07 |
23/08/06 [주말과제] 캐릭터 위치 이동 및 몬스터 공격(수정) (1) | 2023.08.06 |