0. 들어가기 전에
이제 보니까 비활성화 된 점토가 다시 활성화 될 때 ClayMove 스크립트가 제대로 동작하지 않는 모습을 확인했다. ClayMove 스크립트를 수정해서 정상적으로 작동하도록 했다.
1. 스크립트
ClayMove 스크립트를 수정했다.
1.1 ClayMove 스크립트
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum MoveDirection
{
Minus = -1, Plus = 1, Idle = 0
}
public class ClayMove : MonoBehaviour
{
[Header("ClayMovement")]
public float moveSpeed; // 움직이는 속도
public MoveDirection moveDirX; // x 축 방향
public MoveDirection moveDirY; // y 축 방향
public bool isMoving; // 돌아다니는지 여부 확인
public bool isReturning; // 중점으로 돌아가는 중인지 여부 확인
public GameObject targetPosObj; // 중점에 있는 게임 오브젝트 할당해주기
private Coroutine randomMoveCoroutine;
[Header("Animation")]
public Animator anim;
void Start()
{
// 코루틴의 핸들을 저장하고 이를 통해 중단하는 것이 좋음
randomMoveCoroutine = StartCoroutine(RandomMove());
anim = GetComponent<Animator>();
targetPosObj = GameObject.Find("TargetObj"); // 게임 오브젝트 찾아서 할당하기
}
private void OnEnable()
{
// 코루틴 중복 호출 막기
if (randomMoveCoroutine != null)
{
StopCoroutine(randomMoveCoroutine);
}
randomMoveCoroutine = StartCoroutine(RandomMove());
isReturning = false; // 활성화 시 반환 상태 초기화
// 애니메이션도 초기황..
if (anim != null)
{
anim.SetBool("isWalk", false);
}
}
void Update()
{
if (!isReturning)
{
// Time.deltaTime 을 곱해주는 이유는 게임 오브젝트가 순간이동 하는 것을 막기 위함.
transform.Translate(moveSpeed * Time.deltaTime * new Vector2((int)moveDirX, (int)moveDirY));
// x 축 이동 방향이 오른쪽이면 sprite 를 뒤집도록..
if (moveDirX == MoveDirection.Plus)
gameObject.GetComponent<SpriteRenderer>().flipX = true;
else if (moveDirX == MoveDirection.Minus)
gameObject.GetComponent<SpriteRenderer>().flipX = false;
}
// Idle 상태가 아니라면 walk 애니메이션 수행하도록
if (moveDirX != 0 || moveDirY != 0)
{
anim.SetBool("isWalk", true);
}
else
{
anim.SetBool("isWalk", false);
}
}
// 점토가 비활성화 될 때..
private void OnDisable()
{
// 코루틴 종료
if (randomMoveCoroutine != null)
{
StopCoroutine(randomMoveCoroutine);
}
}
// 3초에 한 번씩 이동 방향 바꾸도록 하는 코루틴..
// 코루틴은 IEnumerator 를 반환함
private IEnumerator RandomMove()
{
while (true)
{
// 방향 랜덤으로 설정
moveDirX = (MoveDirection)Random.Range(-1, 2);
moveDirY = (MoveDirection)Random.Range(-1, 2);
yield return new WaitForSeconds(3f); // 3초 동안 기다령
}
}
private IEnumerator ReturnToCenter()
{
isReturning = true;
float curTime = 0f;
float duration = 5f; // 중점으로 돌아가는 시간 5초 만큼 줄 것..
Vector2 targetPos = targetPosObj.transform.position; // 중점에 있는 오브젝트의 위치 할당
while (curTime < duration)
{
// 현재 점토의 위치가 목표 지점보다 왼쪽에 있으면 오른쪽을 보도록..
if (targetPos.x > transform.position.x)
gameObject.GetComponent<SpriteRenderer>().flipX = true;
else if (targetPos.x < transform.position.x)
gameObject.GetComponent<SpriteRenderer>().flipX = false;
transform.position = Vector2.MoveTowards(transform.position, targetPos, moveSpeed * Time.deltaTime * 1.5f);
curTime += Time.deltaTime;
yield return null; // 다음 프레임까지 대기
}
isReturning = false; // 랜덤 이동 재개
randomMoveCoroutine = StartCoroutine(RandomMove()); // 다시 시작시키기
}
// 콜라이더 컴포넌트를 가진 게임 오브젝트랑 부딪히면 이 함수로 진입
private void OnCollisionEnter2D(Collision2D collision)
{
if (isReturning) return; // 만약 이미 돌아가고 있는 중에 또 부딪히면 걍 나가라..
// 부딪힌 게임 오브젝트의 태그가 Target 이면 ReturnToCenter 코루틴 호출하도록
if (collision.gameObject.CompareTag("Wall"))
{
// 랜덤 이동 코루틴은 중단시키기
StopCoroutine(randomMoveCoroutine);
// 중앙 복귀 코루틴 호출
StartCoroutine(ReturnToCenter());
}
}
}
1.2 ClayMove 스크립트 변경 사항 설명
더보기
1. OnEnable()
메서드를 새로 추가했다. 이는 게임 오브젝트가 활성화 될 때 자동으로 호출되는 메서드이다.
점토가 다시 활성화 되었을 때 코루틴을 중복으로 호출하는 것을 막기 위해서 이미 돌아가고 있는 코루틴이 있다면 종료시켰다. 그 후 새로운 코루틴을 시작하고 randomMoveCoroutine 변수에 할당했다.
그리고 isReturing 의 값이 true 로 설정되어 있으면 점토의 움직임이 제대로 작동하지 않을 가능성이 있기 때문에 이 값도 false 로 초기화 해줬다.
private void OnEnable()
{
// 코루틴 중복 호출 막기
if (randomMoveCoroutine != null)
{
StopCoroutine(randomMoveCoroutine);
}
randomMoveCoroutine = StartCoroutine(RandomMove());
isReturning = false; // 활성화 시 반환 상태 초기화
// 애니메이션도 초기황..
if (anim != null)
{
anim.SetBool("isWalk", false);
}
}
2. OnDisable()
새로 추가한 메서드이다. 게임 오브젝트가 비활성화될 때 자동으로 호출되는 메서드이다.
돌아가는 중인 코루틴을 강제적으로 종료시켰다.
// 점토가 비활성화 될 때..
private void OnDisable()
{
// 코루틴 종료
if (randomMoveCoroutine != null)
{
StopCoroutine(randomMoveCoroutine);
}
}
2. 결과물