오늘 학습 키워드

마우스 따라다니기, 점프 스케어 만들기

오늘 학습 한 내용을 나만의 언어로 정리하기

마우스 따라다니기

void Update()
{
    Vector3 mousePosition = Input.mousePosition; // 마우스 포지션 가져오기
    mousePosition.z = Mathf.Abs(Camera.main.transform.position.z); // 카메라와의 거리만큼 Z축 위치 설정
    Vector3 targetPosition = Camera.main.ScreenToWorldPoint(mousePosition);
    targetPosition.z = 0; // Z축 위치를 0으로 설정하여 2D 평면에서 움직이도록 함
 
    transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
}

마우스 포지션 가져와서 그걸 월드 포인트로 바꿈

갑툭튀 애니메이션 만들기

초 간격 0.01초로 해서 진짜 갑툭튀처럼 보이게 함

그리고 마지막에 마우스 오브젝트 삭제해서 계속 나오지 않게 함

화면이 흔들리는 연출 만들기 (Using DoTween)

DoTween 에셋을 사용해서, 마우스를 쫓아오는 객체가 일정 거리 이내로 다가오면 화면이 흔들리게 만들 것.

참고 자료 : 팀원분의 설명 + 벨로그 글

DOTween에는 DOShakePosition 이라는 함수가 있음. 이걸 사용해서 만들 것.

public class FollowCursor : MonoBehaviour
{
    public float speed = 5f; 
    public float gameOverDistance; // 게임 오브젝트와 마우스 포인터 사이 게임오버 기준 거리
    public float shakeDistance; // 카메라가 흔들리기 시작 할 거리
 
    public Vector3 originalCameraPosition; // 카메라 원래 위치 저장용
 
    public GameObject jumpScareImage; // 점프스케어 이미지 오브젝트
 
    private Tween shaking; // 카메라 흔드는거 저장해놓고 중단할 때 사용
 
    // Start is called before the first frame update
    void Start()
    {
        originalCameraPosition = Camera.main.transform.position; 
        Vector2 size = GetComponent<SpriteRenderer>().bounds.size; // 스프라이트의 크기
        gameOverDistance = size.x / 2; // 게임 오브젝트의 크기 반으로 설정
        shakeDistance = size.x * 2f;
    }
 
    // Update is called once per frame
    void Update()
    {
        Vector3 mousePosition = Input.mousePosition; // 마우스 포지션 가져오기
        mousePosition.z = Mathf.Abs(Camera.main.transform.position.z); // 카메라와의 거리만큼 Z축 위치 설정
        Vector3 targetPosition = Camera.main.ScreenToWorldPoint(mousePosition);
        targetPosition.z = 0; // Z축 위치를 0으로 설정하여 2D 평면에서 움직이도록 함
 
        transform.position = Vector3.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
 
        float distance = Vector3.Distance(transform.position, targetPosition);
        if (distance < gameOverDistance)
        {
            // 놀래키기
            jumpScareImage.SetActive(true);
            Destroy(this.gameObject); // FollowCursor 스크립트 제거
            Invoke("OnExitButton", 0.5f);
        }
        
        UpdateShaking(distance);
    }
 
    
    public void UpdateShaking(float distance)
    {
        // 가까워질수록 카메라가 흔들리도록 함
 
        float intensity = Mathf.Clamp01(1f - (distance / shakeDistance));
        float strength = intensity * 2.0f;
 
        if(intensity <= 0) // intensity가 0보다 작다 = 거리가 멀다
        {
            if (shaking != null)
            {
                shaking.Kill(); 
                Camera.main.transform.position = originalCameraPosition; // 카메라 원래 위치로 되돌리기
                shaking = null;
            }
            return;
        }
 
        if (shaking != null) shaking.Kill();
 
        shaking = Camera.main.transform.DOShakePosition(
            duration: 0.5f,
            strength: strength,
            vibrato: 30,
            randomness: 90f,
            snapping: false,
            fadeOut: false
            );
    }
 
    public void OnExitButton()
    {
        Application.Quit();
    }
}

여기서 intensity에 대해 조금 더 정리하는 편이 좋을 듯 함

float intensity = Mathf.Clamp01(1f - (distance / shakeDistance));

여기서 원래 Clamp는 세 개의 값을 받음.

  • Mathf.Clamp(값, 최소값, 최대값)

첫 번째 인수로 넣었던 이 최소값보다 작지 않도록, 최대값보다 크지 않도록 일종의 경계를 지어두는 것.
그렇다면 Clamp01은 무엇인가?
최소값이 0이고 최대값이 1인 Clamp이다. 그래서 인수도 하나만 받음.

그러면 왜 값을 1f - (distance / shakeDistance) 로 넣었는가?
먼저 distance는 현재 마우스와 쫓아오는 오브젝트 간의 거리.
shakeDistance는 흔들리기 시작할 거리이다.
만약에 distance가 shakeDistance보다 크다면 = 거리가 멀다면
Mathf.Clamp01(1f - (최소 1 이상)) = 0 이 반환될 것.

반대로, distance가 shakeDistance보다 작다면 = 거리가 가깝다면
Mathf.Clamp01(1f - (아무리 커도 1이 안됨)) = 0 이상이 반환될 것.

그리고 distance가 작을수록, 즉 거리가 가까울 수록 1f에서 빼는 값이 작기때문에 1에 가까운 값이 반환될 것.

그러니 intensity는 얼마나 가까운지를 0에서 1사이로 가지고있는 척도라고 보면 될 것.

함수를 부른게 누구인가?

팀원분이 버튼이 눌려지면 실행될 OnClick 메소드를 만들려고 하셨는데,
어떻게 해야 이 함수를 부른 버튼을 찾을지 고민하셨음. 그래서 나도 한 번 찾아보았음.

public void OnClickHandler()
{
    GameObject caller = UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject;
    Debug.Log("클릭한 오브젝트: " + caller.name);
}

EventSystem.current.currentSelectedGameObject는 UI 상에서 현재 이벤트를 발생시킨 GameObject를 알려준다고 함.

학습하며 겪었던 문제점 & 에러

문제 1

  • 문제&에러에 대한 정의
using UnityEngine;
 
public class FollowCursor : MonoBehaviour
{
    public float followSpeed = 5f; // 따라가는 속도
 
    void Update()
    {
        // 마우스 위치를 월드 좌표로 변환
        Vector3 mousePosition = Input.mousePosition;
        mousePosition.z = 10f; // 카메라에서의 거리 (조정 필요)
        Vector3 targetPosition = Camera.main.ScreenToWorldPoint(mousePosition);
 
        // 현재 위치에서 목표 위치로 부드럽게 이동
        transform.position = Vector3.MoveTowards(transform.position, targetPosition, followSpeed * Time.deltaTime);
    }
}
 

이렇게 했더니 마우스 커서를 따라다니는 이미지가 카메라 뒤로 넘어가버리는 현상이 발생함

  • 해결 방법

위에 마우스 따라다니기에서 만든 것처럼 마우스 포지션의 Z를 카메라 위치로 하고, 그걸 월드포인트로 변환한 좌표의 z를 0으로 만들어서 평면에서 움직이게 함

  • 새롭게 알게 된 점

Unity 2D로 작업해도 좌표계 자체는 3D를 계속 사용하고 있다.

  • 이 문제&에러를 다시 만나게 되었다면?

사용하고있는 좌표계에 맞게 변환할 것

내일 학습 할 것은 무엇인지

내일 꼭 할거는 아니긴 한데, DOTween에 대해 좀 더 알아보고싶음.