-Test_PlayerControlScene을 만들어주었다.
3dObject-Plane ,Player 생성. 플레이어는 에셋의 프리팹을 가져오고 unpack해주었다.
-Player의 애니메이션 컨트롤러를 복사해 (수정시 문제가 생기는것을 막기위해) 새로 만들어주고 넣어주었다.(MyDogControl)
-Player의 오브젝트명을 Hero로 변경
-모두를 관리하는 스크립트 Test_PlayerControlSceneMain 생성, 빈 오브젝트를 만들어 스크립트를 넣어준다.
:Input을 받는다
*메인 카메라는 태그에 Main이 붙어있어야한다.
-ray충돌검사
-HeroController추가
https://docs.unity3d.com/kr/560/Manual/Coroutines.html
코루틴 - Unity 매뉴얼
함수를 호출하면 값을 반환하기 전에 실행 완료됩니다. 이는 함수에서 수행되는 모든 액션이 하나의 프레임 업데이트 내에서 발생해야 한다는 것을 의미합니다. 시간이 지남에 따라 절차식 애
docs.unity3d.com
-StartCoroutine을 사용해서 메서드를 호출: 메서드를 써서 메서드를 호출
Update 메서드는 우리가 원할 때 호출하거나 멈출 수 없다. => 코루틴 사용
코루틴 연습을 위해 Fade함수를 구현해 보았다.
canvas inactive하고 Hero Controller를 수정해보자.
원래 update에 쓰고자 한다면 다음과같이 작성할 것이다.
-this.transform.position을 this.targetPosition으로 써야 잘 작동한다 고쳤는데 이전이미지이다.
코루틴을 통해 바꿔 구현
-애니메이션을 넣기위해 Animator 창에서 parameters 추가하고 transition을 추가해 1을 넣어주었다.
HasExitTime
https://docs.unity3d.com/Manual/class-Transition.html
Unity - Manual: Animation transitions
Animation transitions Animation transitions allow the state machineThe set of states in an Animator Controller that a character or animated GameObject can be in, along with a set of transitions between those states and a variable to remember the current st
docs.unity3d.com
-Has Exit Time 체크 안하면 앞에 애니메이션이 끝나는 시간이 추가된다.(해제하고 해야 순서대로 딱딱 나온다.)
-코드 수정
-몬스터 클릭하면 몬스터에게 이동을 구현하기 위해 몬스터를 추가하고 태그와 Collider를 추가하였다.
-MonsterController 추가
-GizmosExtensions.cs추가(바닥에 원을 그리기 위해 사용)
https://gist.github.com/luisparravicini/50d044a20c67f0615fdd28accd939df4
Method to draw an arc with Unity's Gizmos
Method to draw an arc with Unity's Gizmos. GitHub Gist: instantly share code, notes, and snippets.
gist.github.com
-MonsterController에도 추가
-클릭하면 이동하다가 (공격)사거리 안에 들어오면 공격한다.
-heroController수정
-main도 수정
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonsterController : MonoBehaviour
{
public float radius=1;
// 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, Vector3.forward, 360, radius);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Test;
using UnityEngine.UI;
public class Test_PlayerControlSceneMain : MonoBehaviour
{
[SerializeField]
private HeroController heroController;
[SerializeField]
private Image image;
// Start is called before the first frame update
void Start()
{
//var heroGo = GameObject.Find("Hero");
//this.heroController = heroGo.GetComponent<HeroController>();
//this.heroController = GameObject.FindObjectOfType<HeroController>();
this.StartCoroutine(CoFade());//코루틴 함수 호출
this.heroController.onMoveComplete = () =>
{
Debug.Log("<color=cyan>이동을 완료했습니다.</color>");
};
}
// 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;
//화면에 Ray 출력
Debug.DrawRay(ray.origin,ray.direction*maxDistance,Color.red,3f);
//충돌검사
RaycastHit hit;//raycast에서 out키워드 사용을 위해 변수선언을 먼저해준다.
if (Physics.Raycast(ray, out hit, maxDistance))
{
// Debug.Log(hit.point);//충돌정보가 hit변수에 담김/월드상의 충돌 지점 위치(Vector3)
//hit.point는 널이 나올 수 없다.
//hit.point가 타입이 Vector3로 구조체-값형식이기 때문에 힙을 쓰지않아 널이 될 수 없다.
//this.heroGo.transform.position = hit.point;//hero 게임 오브젝트의 위치에 hit.point를 넣어줌
if (hit.collider.tag == "Monster")//몬스터 클릭시
{//태그를 통해 몬스터에 접근
Debug.LogFormat("Monster: {0}", hit.collider.tag);
//거리를 구한다.
Vector3 targetPosition = hit.collider.gameObject.transform.position;
float distance = Vector3.Distance(this.heroController.gameObject.transform.position, targetPosition);
MonsterController monsterController = hit.collider.gameObject.GetComponent<MonsterController>();
//각 반지름 더한거와 비교
float sumRadius = this.heroController.radius + monsterController.radius;
//Debug.Log(distance);
if (distance <= sumRadius)//사거리 안에 들어옴 => attack
{
Debug.Log("Attack");
}
else//이동
{
this.heroController.MoveToMonster(monsterController);
}
}
else if (hit.collider.tag == "Ground")
{
Debug.Log(hit.point);
this.heroController.Move(hit.point);
}
}
}
}
IEnumerator CoFade()//코루틴 함수
{
for (float f = 1f; f >= 0; f -= 0.01f)
{
Color c = this.image.color;
c.a = f;
this.image.color = c;
//다음 프레임
yield return null;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Test{
public class HeroController : MonoBehaviour
{
//bool isMoveStart = false;
private Vector3 targetPosition;
private Coroutine moveRoutine;
private Animator anim;
public System.Action onMoveComplete;
public float radius = 1;
private MonsterController target;
// Start is called before the first frame update
void Start()
{
//targetPosition = this.transform.position;
this.anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
}
public void Move(Vector3 targetPosition)
{
//타겟을 지움
this.target = null;
this.targetPosition = targetPosition;//이동할 목표 지점을 저장
Debug.Log("Move");
//이동시작
if (this.moveRoutine != null)
{
//이미 코루틴이 실행중이다 -> 중지
this.StopCoroutine(this.moveRoutine);
}
this.moveRoutine = StartCoroutine(this.CoMove());
this.anim.SetInteger("State",1);//Run Animation
}
public void MoveToMonster(MonsterController target)
{
this.target = target;
this.targetPosition =this.target.gameObject.transform.position;//이동할 목표 지점을 저장
Debug.Log("MoveToMonster");
// Debug.LogFormat("targetPosition: {0},{1}",targetPosition,this.target.gameObject.transform.position);
//이동시작
if (this.moveRoutine != null)
{
//이미 코루틴이 실행중이다 -> 중지
this.StopCoroutine(this.moveRoutine);
}
this.moveRoutine = StartCoroutine(this.CoMove());
this.anim.SetInteger("State", 1);//Run Animation
}
private IEnumerator CoMove()
{
while (true)
{
this.transform.LookAt(this.targetPosition);//방향을 바라봄
this.transform.Translate(Vector3.forward * 1f * Time.deltaTime);//이미 바라봤으니까 정면으로 이동
//목표지점과 나와의 거리를 잼
float distance = Vector3.Distance(this.transform.position, this.targetPosition);
//Debug.LogFormat("target :{0}",this.target);//타겟이 있는지 확인
// Debug.Log(distance);
if (this.target != null) //타겟이 있을 경우
{//this.targetPosition은 Vector3라 null과 비교하면안된다. 주의.
if (distance <= (1f + 1f))
{
break;
}
}
else//타겟이 없을 경우
{
// Debug.Log(distance);
if (distance <= 0.1f)//** 0이 될수 없다 가까워질때 도착한것으로 판단 하자
{//도착
break;//isMoveStart 같은 변수를 안쓸 수 있다.
}
}
yield return null;//** 다음 프레임 시작
}
Debug.Log("<color=yellow>도착!</color>");
this.anim.SetInteger("State", 0);//Idle Animation :Stop
//대리자를 호출
this.onMoveComplete();
}
private void OnDrawGizmos()
{
// Gizmos.color = Color.red;
// Gizmos.DrawWireSphere(this.transform.position, 1.2f);
GizmosExtensions.DrawWireArc(this.transform.position,this.transform.forward,360,radius,40);
}
}
}
'3d 콘텐츠 제작' 카테고리의 다른 글
아이템 획득 후 장비 착용 연습 2 (0) | 2023.08.11 |
---|---|
아이템 획득시, 장착 연습 (0) | 2023.08.11 |
씬의 몬스터 제거시 포탈 생성 연습(동적 데이터 생성 및 관리) (0) | 2023.08.10 |
SimpleRPG-GameScene에서 플레이어 이동 및 Attack (0) | 2023.08.09 |
Unity-공격 연습 (0) | 2023.08.09 |