0. 들어가기 전에
왼쪽 마우스로 점토를 꾹 누르면 점토 드래그 기능이 수행되도록 만들었다.
나중에 다 자란 점토를 가져다 팔기 위해서 꼭 필요한 기능이다. 주머니에 다 자란 점토를 드래그&드롭 하면 팔리도록 할 것이다.
1. 게임 오브젝트
점토를 바닥에 내려놓는 장소가 불가능 구역이라면 드래그 하기 전 위치로 돌아갈 수 있도록 하려고 했다.
이를 위해서는 불가능 구역을 지정해야 하는데 나는 빈 게임 오브젝트를 두 개 만들어서 x, y 좌표를 가지고 불가능 구역을 판단했다.
즉, 왼쪽 상단의 노란색 게임 오브젝트의 x 축보다 작거나 y 축보다 크거나, 오른쪽 상단의 노란색 게임 오브젝트의 x 축보다 크거나 y 축보다 작거나를 기준으로 불가능 구역을 판단했다.
2. 스크립트
이번에 새로 만든 스크립트는 없고 기존의 ClayController 스크립트를 수정했다.
2.1 ClayController 스크립트
using System.Collections;
using System.Collections.Generic;
using TreeEditor;
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; // 다 자란 동물 모습
[Header("Drag Clay")]
public float targetTime = 1; // 드래그 시작할 수 있는 시간
public float curTime; // 현재 시간
public Vector3 prevPos; // 점토를 드래그 하기 전 위치
private void Awake()
{
anim = GetComponent<Animator>();
}
// 점토가 터치되면 저절로 호출됨
private void OnMouseDown()
{
prevPos = transform.position; // 드래그 하기 전 위치 저장
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;
}
}
}
// 점토 드래그할 때 호출되는 함수
private void OnMouseDrag()
{
curTime += Time.deltaTime;
// 만약 현재 시간이 targetTime 보다 크거나 같다면 점토가 마우스를 따라오도록 하기..
if (curTime >= targetTime)
{
// 마우스 위치를 가져온 후 Z 축을 카메라와의 거리로 설정한다
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = Camera.main.WorldToScreenPoint(transform.position).z;
// 스크린 좌표를 월드 좌표로 변환
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
// 오브젝트의 위치를 마우스의 월드 좌표로 이동
transform.position = worldPosition;
// 이 경우에는 UI 보다도 앞에 갈 수 있도록..
gameObject.GetComponent<SpriteRenderer>().sortingOrder = 10;
}
}
// 점토 내려놓을 때 호출되는 함수
private void OnMouseUp()
{
curTime = 0;
if (transform.position.x < -6.5 || transform.position.x > 6.5 || transform.position.y < -3 || transform.position.y > 0.6)
transform.position = prevPos;
// 다시 UI 보다 아래로 가도록..
gameObject.GetComponent<SpriteRenderer>().sortingOrder = 1;
}
}
2.2 ClayController 스크립트 변경 사항 설명
ClayController 스크립트에 대한 설명은 다음과 같다.
1. 변수
마우스 왼쪽 버튼으로 점토를 계속 누르고 있다가 일정 시간에 도달하면 점토가 마우스를 따라오도록 하기 위해 targetTime 과 curTime 변수를 선언했다. curTime 의 값이 targetTime 보다 크거나 같아지면 점토가 마우스를 따라오도록 했다.
[Header("Drag Clay")]
public float targetTime = 1; // 드래그 시작할 수 있는 시간
public float curTime; // 현재 시간
public Vector3 prevPos; // 점토를 드래그 하기 전 위치
2. OnMouseDown()
OnMouseDown() 메서드는 왼쪽 마우스가 클릭(눌릴 때) 될 때 호출되는 메서드이다. 메서드에 진입하자마자 점토의 현재 위치를 prevPos 변수에 저장하도록 했다. 만약 점토를 불가능 영역에 내려놓으면 이 위치로 포지션을 설정하기 위함이다.
prevPos = transform.position; // 드래그 하기 전 위치 저장
3. OnMouseDrag()
이 메서드는 왼쪽 마우스 버튼을 클릭하고 손을 떼지 않는 중에 호출되는 메서드이다.
curTime 에 계속해서 시간을 더하는데 이 값이 targetTime 보다 크거나 같아지면 점토의 위치가 마우스의 위치랑 같아지도록 한다.
Input.mousePosition 은 스크린 좌표이다. 이를 점토가 돌아다니는 세상인 월드 좌표로 변환해야 점토가 화면상에서 마우스를 따라다니는 것처럼 보이게 할 수 있다.
스크린 좌표를 월드 좌표로 변환하기 위해서는 Camera.main.ScreenToWorldPoint 메서드를, 반대의 경우에는 Camera.main.WorldToScreenPoint 메서드를 이용한다.
게임 오브젝트의 sortingOrder 값을 10으로 올렸는데 이유는 점토를 마우스로 드래그 하는 순간에는 UI 보다 앞으로 나오면 좋겠다고 생각했기 때문이다. 이렇게 하지 않으면 UI 에 점토가 가려져서 마음에 들지 않았다.
// 점토 드래그할 때 호출되는 함수
private void OnMouseDrag()
{
curTime += Time.deltaTime;
// 만약 현재 시간이 targetTime 보다 크거나 같다면 점토가 마우스를 따라오도록 하기..
if (curTime >= targetTime)
{
// 마우스 위치를 가져온 후 Z 축을 카메라와의 거리로 설정한다
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = Camera.main.WorldToScreenPoint(transform.position).z;
// 스크린 좌표를 월드 좌표로 변환
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
// 오브젝트의 위치를 마우스의 월드 좌표로 이동
transform.position = worldPosition;
// 이 경우에는 UI 보다도 앞에 갈 수 있도록..
gameObject.GetComponent<SpriteRenderer>().sortingOrder = 10;
}
}
4. OnMouseUp()
왼쪽 마우스에서 손가락을 떼면 호출되는 메서드이다.
이 메서드에 진입하면 curTime 변수의 값을 0으로 만든다. 불가능 영역에 도달했음은 조건문을 통해 판단했고, 조건이 만족되면 위치를 prevPos 로 설정해줬다.
그리고 sortingOrder 의 값을 다시 원상태로 되돌려서 UI 보다 뒤로 갈 수 있도록 했다.
// 점토 내려놓을 때 호출되는 함수
private void OnMouseUp()
{
curTime = 0;
if (transform.position.x < -6.5 || transform.position.x > 6.5 || transform.position.y < -3 || transform.position.y > 0.6)
transform.position = prevPos;
// 다시 UI 보다 아래로 가도록..
gameObject.GetComponent<SpriteRenderer>().sortingOrder = 1;
}
3. 결과물
정상적으로 작동하는 모습을 볼 수 있다.
4. 참고자료
오늘 이용한 개념에 대해 설명해놓은 글들을 가져와봤다.
4.1 ScreenToWorldPoint
Unity - Scripting API: Camera.ScreenToWorldPoint
4.2 OnMouse 함수들