유니티 프로젝트/점토게임

[개발일지] 7. 점토 클릭 시 애정 얻기 & 점토 스프라이트 변경

dubu0721 2025. 1. 10. 18:22

0. 들어가기 전에

점토를 클릭할 때 레벨에 맞는 애정을 획득할 수 있도록 했다. 점토를 클릭하다 보면 레벨업을 하는데 최고 레벨에 도달하면 점토의 모습이 동물로 변하도록 했다.

 

레벨업을 할 때마다 점토의 크기가 커지도록 하기 위해서 각 레벨에 맞게 애니메이터를 할당해주었다.

 

점토가 다 자라서 동물이 되면 스프라이트 이미지 상 움직이는 방향에 맞게 이미지를 좌우반전시켰다.

 

 


 

 

1. 스크립트

이번에 만든 스크립트는 ClayController 이고, ClayMove 스크립트에 변동사항이 생겼다.

 

1.1 ClayController 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ClayController : MonoBehaviour
{
    [Header("Clay Data")]
    public float[] loves; // 점토를 클릭했을 때 얻는 애정 수치(1~5 레벨)
    public int[] touchCnts; // 해당 요소만큼 클릭되면 레벨업
    public int clayLevel = 1; // 1레벨에서 시작(5레벨까지 있음)
    public int curTouchCnt = 0;

    [Header("Animation")]
    Animator anim; // 점토가 터치될 때 애니메이션 실행하기 위함
    public RuntimeAnimatorController[] animators;

    [Header("Sprites")]
    public Sprite clay; // 점토 모습
    public Sprite animal; // 다 자란 동물 모습


    private void Awake()
    {
        anim = GetComponent<Animator>();
    }

    // 점토가 터치되면 저절로 호출됨
    private void OnMouseDown()
    {
        Debug.Log("터치됨!");
        anim.SetTrigger("doTouch");
        GameManager.instance.GetLove(loves[clayLevel - 1]); // 레벨에 맞는 수치를 함수로 넘겨주기
        curTouchCnt++;

        // 이미 점토의 레벨이 최고 레벨에 도달했으면 밑으로 진입 안 하도록..
        if (clayLevel != 5)
        {
            if (curTouchCnt == touchCnts[clayLevel - 1])
            {
                clayLevel++; // 레벨 1 증가
                curTouchCnt = 0; // 초기화
                anim.runtimeAnimatorController = animators[clayLevel - 1]; // 레벨에 맞는 애니메이터로 바꿔주기

                if (clayLevel == 5)
                    gameObject.GetComponent<SpriteRenderer>().sprite = animal;
            }
        }
    }
}

 

1.2 ClayController 스크립트 설명

ClayController 스크립트에 대한 설명은 다음과 같다.

더보기
더보기

1. 변수

  • loves: 각 레벨마다 획득할 수 있는 애정의 수치가 다르도록 하기 위해서 선언했다.
  • touchCnts: 해당 요소만큼 클릭되면 레벨업 되도록 하기 위해 선언했다.
  • clayLevel: 현재 점토의 레벨을 나타내기 위한 변수이다.
  • curTouchCnt: 현재 레벨에서 점토를 클릭한 횟수를 나타내기 위한 변수이다.
  • anim: 점토가 터치될 때 애니메이션을 실행하도록 하기 위한 변수이다
  • animators: 각 레벨에 맞는 애니메이터를 할당해주기 위한 변수이다.
  • clay: 점토 모습 스프라이트
  • animal: 동물 모습 스프라이트
[Header("Clay Data")]
public float[] loves; // 점토를 클릭했을 때 얻는 애정 수치(1~5 레벨)
public int[] touchCnts; // 해당 요소만큼 클릭되면 레벨업
public int clayLevel = 1; // 1레벨에서 시작(5레벨까지 있음)
public int curTouchCnt = 0;

[Header("Animation")]
Animator anim; // 점토가 터치될 때 애니메이션 실행하기 위함
public RuntimeAnimatorController[] animators;

[Header("Sprites")]
public Sprite clay; // 점토 모습
public Sprite animal; // 다 자란 동물 모습

 

 

2. Awake()

anim 변수에 현재 게임 오브젝트의 Animator 컴포넌트를 할당했다.

private void Awake()
{
    anim = GetComponent<Animator>();
}

 

 

3. OnMouseDown()

이는 마우스로 게임 오브젝트를 터치했을 때 자동으로 호출되는 함수이다. 직접 호출할 필요가 없다.

 

터치 상태의 애니메이션을 실행하도록 하기 위해 anim.SetTrigger 메서드를 실행했다. 그리고 현재 점토 레벨에 맞는 애정을 얻게 하기 위해서 GetLove 메서드에 매개변수로 loves[clayLevel - 1] 값을 넣어주었다. 그 후, curTouchCnt 값을 +1 해주었다.

 

만약 점토의 레벨이 이미 최고 상태라면 더 이상 레벨업 할 수 없으므로 if (clayLevel != 5) 를 통해 걸러냈다. 만약 5레벨이 아니라면 진입할 수 있도록 했다.

 

진입하면 점토의 레벨이 1 증가하고, curTouchCnt 값은 다시 0이 되고, 게임 오브젝트의 애니메이터가 레벨에 맞는 애니메이터로 변경될 수 있도록 했다.

 

최고레벨이 되면 점토의 스프라이트를 동물 모습으로 변경해주어서 다 자랐음을 표현하도록 했다.

// 점토가 터치되면 저절로 호출됨
private void OnMouseDown()
{
    Debug.Log("터치됨!");
    anim.SetTrigger("doTouch");
    GameManager.instance.GetLove(loves[clayLevel - 1]); // 레벨에 맞는 수치를 함수로 넘겨주기
    curTouchCnt++;

    // 이미 점토의 레벨이 최고 레벨에 도달했으면 밑으로 진입 안 하도록..
    if (clayLevel != 5)
    {
        if (curTouchCnt == touchCnts[clayLevel - 1])
        {
            clayLevel++; // 레벨 1 증가
            curTouchCnt = 0; // 초기화
            anim.runtimeAnimatorController = animators[clayLevel - 1]; // 레벨에 맞는 애니메이터로 바꿔주기

            if (clayLevel == 5)
                gameObject.GetComponent<SpriteRenderer>().sprite = animal;
        }
    }
}

 

1.3 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>();
    }

    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);
        }
    }

    // 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.4 ClayMove 스크립트 변경 사항 설명

더보기
더보기

1. Update()

x 축 이동 방향이 오른쪽이면 sprite 를 뒤집도록 하는 로직을 추가했다. 점토가 다 자라서 동물이 되면 방향이 구분된다. 이때 동물이 쳐다보는 방향과 이동 방향이 다르면 이상하기 때문에 이를 위해 추가했다.

// x 축 이동 방향이 오른쪽이면 sprite 를 뒤집도록..
if (moveDirX == MoveDirection.Plus)
    gameObject.GetComponent<SpriteRenderer>().flipX = true;
else if (moveDirX == MoveDirection.Minus)
    gameObject.GetComponent<SpriteRenderer>().flipX = false;

 

 

2. ReturnToCenter()

점토가 벽에 닿아서 중앙으로 돌아갈 때 스프라이트의 방향을 조정하기 위해 추가한 구문이다. 만약 점토가 중앙보다 왼쪽에 위치한다면 오른쪽을 쳐다보도록, 오른쪽에 위치한다면 왼쪽을 쳐다보도록 했다.

// 현재 점토의 위치가 목표 지점보다 왼쪽에 있으면 오른쪽을 보도록..
if (targetPos.x > transform.position.x)
    gameObject.GetComponent<SpriteRenderer>().flipX = true;
else if (targetPos.x < transform.position.x)
    gameObject.GetComponent<SpriteRenderer>().flipX = false;

 

 


 

 

2. 결과물

 

정상적으로 작동하는 모습을 확인할 수 있다.

 

 


 

 

3. 참고자료

RuntimeAnimatorContoller 에 대해 설명해놓은 글이 있길래 가져왔다.

 

3.1 RuntimeAnimatorController

유니티 기본기 : 애니메이터(Animator) 2편. 애니메이터 기초 | by Supercent.official | Supercent Blog 슈퍼센트 블로그 | Medium

 

유니티 기본기 : 애니메이터(Animator) 2편

애니메이터 기초

medium.com