유니티 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
유니티 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);
화면 해상도(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;
}
'게임 프로그래밍 > 유니티 프로젝트' 카테고리의 다른 글
[Unity] Joystick 제작 원리 (0) | 2022.07.20 |
---|---|
[Unity] GameManager 클래스 선언과 .NET 연관성, enum 타입 (0) | 2022.07.19 |
[유니티] 오브젝트 회전(Euler/Quaternion), Vector3의 외적/내적, 삼각함수를 이용한 플레이어 이동 및 총알 발사 (2022.07.14) (0) | 2022.07.19 |
[Unity] File 저장과 PlayerPrefs (0) | 2022.07.15 |
[Unity/C#] Call by Value / Call by Reference 비교, StringBuilder 사용 이유 (0) | 2022.07.13 |