[Unity] 2D 게임 플레이 영역 제한하기, Rendering Pipeline의 좌표 공간에 대한 이해(WorldToViewport / ViewportToWorld)

728x90

유니티 2D 게임 플레이 영역 제한하는 방법

2D 게임에서 플레이어 이동 영역을 제한하는 방법은 여러가지가 있다. 대표적으로는 게임 뷰에 보이지 않게 오브젝트 Collider로 막아놓는 방법이 있을 수 있겠다. 하지만 코드로 플레이어 이동 좌표 영역의 제한을 걸어서 이동 범위를 한정지어줄 수 있다.

 

 

transform.position을 활용한 영역 제한

void Update()
{
    float h = Input.GetAxis("Horizontal");
    float v = Input.GetAxis("Vertical");
    
    vector3 dir = new Vector3(h, v, 0);
    dir.Normalize();
    
    transform.position += dir * speed * Time.deltaTime;
    
    if(transform.position.x < -2f)
    	transform.position.x = new Vector3(-2f, transform.position.y, transform.position.z);
    else if(transform.position.x > 2f)
    	transform.position.x = new Vector3(2f, transform.position.y, transforom.position.z);
}

또는

void Update()
{
    float h = Input.GetAxis("Horizontal");
    float v = Input.GetAxis("Vertical");
    
    vector3 dir = new Vector3(h, v, 0);
    dir.Normalize();
    
    Vector3 myPos = tranform.position;
    myPos += dir * speed * Time.deltaTime;
    
    if(myPos.x < -2f)
    	myPos.x = -2f;
    else if(myPos.x > 2f)
    	myPos.x = 2f;
        
    transform.position = myPos;
}

 

 코드에 대해 간단히 설명해보자면, 플레이어가 (0, 0, 0)을 기준으로 화면 상에 나타나는 x축의 왼쪽 끝은 (-2, 0, 0), 오른쪽 끝은 (2, 0, 0)의 값을 가진다. 따라서 플레이어의 x좌표가 -2보다 작으면(더 왼쪽으로 가면) 플레이어의 x좌표를 -2로 고정을 / x 좌표가 2보다 크면(더 오른쪽으로 가면) 플레이어의 x좌표를 2로 고정시켜놓는 로직을 구현했다. 추가적으로 Vector3 myPos는 값 형식으로 transform.position의 값을 복사해서 사용했기 때문에 원본에는 변화가 없다. 따라서 마지막에 transform.position 값에 myPos를 넣어주어야 한다.

 

Mathf.Clamp를 활용한 영역 제한

myPos.x = Mathf.Clamp(myPos.x, -2f, 2f);
transform.position = myPos;

위의 코드가 복잡하다면 Mathf.Clamp 메서드를 사용해서 범위를 제한해줄 수 있다.

https://docs.unity3d.com/ScriptReference/Mathf.Clamp.html

 

Unity - Scripting API: Mathf.Clamp

Returns the minimum value if the given float value is less than the minimum. Returns the maximum value if the given value is greater than the maximum value. Use Clamp to restrict a value to a range that is defined by the minimum and maximum values. Note: i

docs.unity3d.com

 

유니티 Rendering Pipeline과 좌표 공간

 

유니티에서 객체를 생성할 때는 다음과 같은 Graphics Rendering 과정을 거친다. 그 과정에 화면에 보이는 좌표 공간들을 이해하고 어떤 프로세스로 좌표가 전환되어 렌더링되는지를 반드시 숙지해야 한다.

 

유니티 오브젝트 렌더링 과정

유니티 씬에서 객체는 5개의 좌표계를 바탕으로 그려지는 과정을 거친다.

Model(Local) Space -> World Space -> View(Camera, Eye) Space -> Clip(Viewport) Space -> Screen Space   

Vertext(점)가 Pixel(해상도)로 화면에 표현되기까지의 공간 변화들인데, 이 각각의 변화들은 Matrix 연산에 의해 이뤄진다. 

 

 

유니티 좌표 공간별 특징

Model(Local) Space는 오브젝트가 Local 좌표계 상의 원점에 존재하는 공간이다. Local은 오브젝트 자체의 이동/회전을 기준으로 하는 상대적 좌표축으로 기본적인 평행이동은 로컬 스페이스를 기준으로 이동한다. 3D 모델링 데이터(.fbx)를 최초로 유니티 씬 상으로 가져올 때 모델링 툴에서 사용한 버텍스 데이터를 정확하게 모델 스페이스로 가져오는 특징이 있다. 

transform.Translate(move * TIme.deltaTime, Space.Self);

 

World Space는 오브젝트를 공간 상에서 특정한 World로 이동 및 회전, Scale 된 좌표이다. 월드 좌표는 공간 전체를 중심으로한 좌표로, Model Matix로 변환이 이루어진다. 또한 월드 공간에서는 기본적으로 미터(Meter) 단위를 사용한다.

transform.Translate(move * Time.deltaTime, Space.World);

 

http://rapapa.net/?p=3531 

 

렌더링 파이프라인의 좌표 공간들 – Rapapa Dev Story

렌더링시에 Object가 화면에 나오기까지의 좌표 공간들을 이해하는 것은 게임이나 Graphics 관련 개발에서 필수이다. 그 좌표계들을 나누는 방식과 이름 불리워지는 방식은 여러가지가 있지만 대

rapapa.net

 

화면 해상도(Screen)에 맞게 position 이동, model은 local 좌표를 가진다.

공간에서 사용하는 단위가 다름 : 스크린에서는 pixel / world 에서는 meter 연산을 하기 위해는 단위를 맞춰주어야 한다.

월드를 중심으로 계산하던지 / 스크린을 중심으로 계산을 하던지 단위를 맞추어 주어야 함

WorldToViewport : 스크린으로 가기 전에 0, 1로 맞추어 준다.

 

연산 공간을 월드 또는 스크린에서 해주어야 한다.

  • 1 pixel 이 몇 미터인지, 너비/해상도
  • 해상도 960 x 640
  • 1 pixel = 10/960 미터

 

size는 절반을 의미, 결국 10m라는 것이다.

 

    float speed = 5; // 이동 속도 
    float width;
    void Start()
    {
        // 1 pixel이 몇 meter인지 알고 싶다
        float height = Camera.main.orthographicSize * 2; // 세로 사이즈
        float meterPerPixel = height / Screen.height; // 해상도
        width = Screen.width * meterPerPixel * 0.5f - 0.5f; 
        // 가운데를 중심으로 절반만큼 좌우 이동 + 충돌체 크기까지 계산

    }

    void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Vector3 dir = new Vector3(h, v, 0);
        dir.Normalize();
        
        Vector3 myPos = transform.position;
        myPos += dir * speed * Time.deltaTime;


        myPos.x = Math.Clamp(myPos.x, -width, width);
        transform.position = myPos;
    }

728x90