마우스를 움직여서 2D 오브젝트를 움직여 보겠다 실험을 위해 2D 프로젝트를 만든뒤 2D Sprite Circle을 하나 만들고 포지션을 리셋한다. 나중에 아시겠지만 마우스는 게임오브젝트가 투영되는 스크린의  해상도와 카메라의 Z좌표를 갖는다.

그런데 게임오브젝트는 각자의 좌표가 있고 씬뷰에 보이는 범위는 카메라에 의존한다. 따라서 마우스의 좌표를 게임오브젝트에 적용하기 위해서는 2좌표간의 차이를 알고 변환해 줘야한다.

그다음 ScreenToWorld라는 스크립트를 다음과 같이 붙여준다. 무척 직관적이다.

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

public class ScreenToWorld : MonoBehaviour
{
    public Vector2 mousePosition;

    // Update is called once per frame
    void Update()
    {
        mousePosition = Input.mousePosition;
        transform.position = mousePosition;
    }
}

실행히보면 원이 없어진다. 원인을 찾아보자.  

유니티 2D 기본스크린 화면이다. 객체포지션은 리셋하면  (0,0,0)인데 스크린 범위를 보기위해 (5,4,-10)으로 카메라 Z위치와 맞추었다.

하이라키뷰의 Circle을 클릭하고 Inspector를 보면 포지션이  각자 다르겠지만 마우스좌표는 스크린 좌표라 x:0~1980 y:0~1080,인데 이게 월드봐표 x:±8.8ㄹ y:±5f를 넘어서면 안보이게 된다. 

스크립트에 mousPosition을 Public으로 했기 때문에 마우스를 움직이면 좌표값을 확인할 수 있다.

마우스를 왼쪽아래로 잘 몰아보면 0에 가까워지면서 Circle이 보이게 된다.

문제는 Input.mousePosition과 transform.position과의 차이 때문이다. 왼쪽이 마우스좌표 오른쪽이 transform.position이다

두 시스템의 숫자차이도 문제지만 스크린은 (0,0)점이 좌하이고 월드좌표는 가운데다 따라서 offset(1920/2,1080/2)를 생각해야한다. 월드좌표는 현재 아래와 같고 만일 카메라의 위치 회전에 따라 변화할수 있다.

문제를 알았으니 다음 스크립트를 넣고 다시한번 해보자.

유니티는 모니트의 화면사이즈를 Screen.width, Screen.height로 얻을 수 있고 camera world의 높이를 Camera.main.orthographiSize로 얻을수 있어 이걸 화면비를 곱하면 폭도 얻을 수 있다.

실험을 위해 public변수를 많이 만들었다. 마우스를 움직이면서 봐주길 바란다.

 

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

public class ScreenToWorld : MonoBehaviour
{
    public Vector2 mPos;  //마우스 좌표
    public float mWidth;  //마우스 스크린 폭
    public float mHeight;  //마우스 스크록 높이
    public float wWidth;  
    public float wHeight;
    public float xscale,yscale;

    // Update is called once per frame
    private void Start() {
        mWidth = Screen.width;  //좌측에서 우측까지의 사이즈
        mHeight= Screen.height;  //아래서 위까지의 사이즈
        
        wWidth = Camera.main.orthographicSize * mWidth / mHeight;  //중앙에서 오른쪽까지 화면의 반
        wHeight = Camera.main.orthographicSize;  //중앙에서 위까지의 화면의 반
        yscale = wHeight *2 / Screen.height;
        xscale = wWidth *2 / Screen.width;
    }
    void Update()
    {
        mPos = Input.mousePosition;
        transform.position = MouseToWorld(mPos);
    }
    Vector2 MouseToWorld(Vector2 mPos) {
        return new Vector2((mPos.x - Screen.width/2) * xscale, (mPos.y- Screen.height / 2) * yscale);
    }
}

위 방법은 카메라가 월드좌표의 (0,0,0)을 바라 보고 있을 경우만 잘동작하고 그렇지 않은 경우 잘 안될것이다. 좀더 섬세한 계산이 필요할 것다. 

그런데 유니티가 이럴줄 알고  스크린좌표를 월드좌표를 마련해주었다. 잘보면 Vector2를 사용한다.

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

public class ScreenToWorld : MonoBehaviour
{
    Vector2 worldPosition;
    Vector2 mousePosition;

    // Update is called once per frame
    void Update()
    {
        Screen2World();
        transform.position = worldPosition;
    }
    void Screen2World() {
        mousePosition = Input.mousePosition;
        worldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
    }
}

Vector3를 사용하면 Input.mousePosition의 리턴값의 Z좌표가 카메라의 Z좌표 -10되면서 카메라가 자기와 같은 평면의 Circle을 못보게 된다. 자기눈과 같은 평면에 걸 볼수가 없다. Vector2에서는 Z정보를 전달안하기 때문에 이런 문제가 안 일어 났던거다. 따라서 변환된 world좌표에 게임객체의z좌표를 카피해 주면 간단히 끝난다. 이외에도 방법은 여러가지 생각해보시길

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

public class ScreenToWorld : MonoBehaviour
{
    Vector3 worldPosition;
    Vector3 mousePosition;

    // Update is called once per frame
    void Update()
    {
        Screen2World();
        transform.position = worldPosition;
    }
    void Screen2World() {
        mousePosition = Input.mousePosition;
        worldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
        worldPosition.z = transform.position.z; 
        Debug.Log(mousePosition+ " " + worldPosition);
    }
}

'유니티스크립팅 > 유니티매뉴얼' 카테고리의 다른 글

[유니티매뉴얼] Physics Raycast Ray RaycastHit  (0) 2023.03.04
카메라 - 유니티  (0) 2023.03.03
[유니티매뉴얼] Unity의 회전 및 방향  (0) 2023.02.28
Vector3  (0) 2023.02.25
변수와 함수  (0) 2023.02.25

+ Recent posts