Coding Feature.

[Unity 2D] Portal 같은 게임 만들기 #11 레벨 디자인, 여러 시스템 개선, Raycast2D 사용. 본문

Toy Project/mini-portal [Unity2D]

[Unity 2D] Portal 같은 게임 만들기 #11 레벨 디자인, 여러 시스템 개선, Raycast2D 사용.

codingfeature 2024. 1. 13. 17:08

우선 포탈 매커니즘, 관성 등을 사용해 풀 수 있는 레벨들을 몇 가지 더 만들어보았습니다.

 

그리고 포탈을 들락날락 할 때 플레이어가 스폰하는 지점을 이전까지는 거리를 임의적인 수치로 설정했지만,

포탈의 각도에 따라 스폰 위치가 제가 의도한것과는 다르게 불규칙적으로 바뀌는 것을 깨닫고,

그냥 새로운 Game Object ("PortalSpawnPoint")를 Child로 놓고 스폰 위치를 직접 설정했습니다.

 

그리고 키보드 "R" 버튼을 누르면 레벨을 재시작할 수 있도록 스크립트를 고쳤습니다.

...
void Update()
{
    if (Input.GetKeyDown(KeyCode.R))
    {
        ResetScene();
    }
}
...
public void ResetScene()
{
    SceneManager.LoadSceneAsync(SceneManager.GetActiveScene().buildIndex); // 현재 레벨 재시작
}

 

 

그리고 캐릭터 조작법을 조금 수정했습니다.

 

포탈 게임은 캐릭터의 Rigidbody를 통해 물리적인 성질을 사용하는 것이 매우 중요합니다.

따라서 일반적으로 플랫포머 게임에서 캐릭터를 컨트롤하는 방식인 transform.Translate 즉 position을 변경하는 방식으로는 좋은 플레이 경험을 만들 수 없습니다.

제가 선택한 방식은 RigidBody의 속도를 제어하는 방식으로 캐릭터를 조종하는 것이었습니다.

그리고 일반적으로 움직일 때에는 속도에 일정한 값을 부여해서 이동하게 했지만,

만약, 포탈을 통해 공중에 뜬 상태인 경우 속도에 일정한 값을 주게 된다면 캐릭터가 멈추거나 이상하게 움직이게 될 것입니다.

 

따라서 저는 공중에 떠 있을 경우, 속도를 additive한 방식으로 제어하는 대신 매우 작은 값을 더해주는 것으로 해결했습니다.

 

if (Input.GetKey(KeyCode.A))
{
    if (m_isGrounded) {
        Vector3 newVelocity = new Vector3(-1 * playerSpeed * Time.deltaTime, m_rb.velocity.y, 0);
        m_rb.velocity = newVelocity;
    }
    else
    {
        if (m_rb.velocity.x > 0)
        {
            Vector3 newVelocity = new Vector3(m_rb.velocity.x - playerSpeed * playerFloatingRatio * Time.deltaTime, m_rb.velocity.y, 0);
            m_rb.velocity = newVelocity;
        }
        else if (isPortalJump) // 정방향으로 가는 방향이지만 포탈 점프일 경우에만 속도 제어.
        {
            Vector3 newVelocity = new Vector3(m_rb.velocity.x - playerSpeed * playerFloatingRatio * 0.15f * Time.deltaTime, m_rb.velocity.y, 0);
            m_rb.velocity = newVelocity;
        }
    }
}

 

그리고 현재 움직이는 방향과 정 반대의 방향으로 움직일 경우, 속도를 additive한 방식으로 변경해주었습니다.

만약 같은 방향으로 움직일 경우에 대해서는 일반적으로 그냥 걷다가 점프할 경우에 속도를 additive하게 변경해준다면 계속 뛰어다니면서 속도를 높이는 버니합을 남발하게 되면서 UX를 망칠 수 있다고 생각했습니다.

따라서 같은 방향으로 움직일 때는, 포탈을 사용해 공중에 떠 있는 경우에만 더 멀리 이동할 수 있도록 설정했습니다.

 

 

그리고 캐릭터가 수직으로 떨어질 때의 속력 제한을 걸어두어서 화면 밖으로 튕기거나 하는 버그를 방지했습니다.

        if (m_rb.velocity.y < -1 *playerMaximumSpeed * Time.deltaTime)
        {
            m_rb.velocity = new Vector2(m_rb.velocity.x, -1 * playerMaximumSpeed * Time.deltaTime);
        }

 

 

 

 

또한 포탈건을 이용할 레벨을 위해서 Raycast 기능을 사용하기로 했습니다.

 

이전까지 저는 포탈건이 가리키는 Game Object를 판단, 그 위치를 구하기 위해 Edge Collider를 사용했었습니다.

다만 이 방법에는 Collider에 검출되는 게임 오브젝트가 여러 개 발생할 경우에도 처리를 해야 했기 때문에 좋은 방법이 아니다는 판단을 했습니다.

그리고 Raycast가 더 적절한 처리 방식이라고 생각했습니다.

 

RaycastHit2D hit;

..
    hit = Physics2D.Raycast(m_mouseDir * aimLineStartLength + m_startPos, m_mouseDir, 300);
..
..
    if (hit.collider.tag == "Portalable")
    {
        m_pointedGameObject = hit.collider.gameObject;
        portal_X = hit.point.x;
        portal_Y = hit.point.y;
    }
..

 

위와 같이 코드를 작성하여 Raycast를 구현했습니다! 확실히 더 깔끔해졌습니다!

 

또한 특정 Game Object(블루, 오렌지 포탈, on/off 버튼 등)에 대해서는 Raycast가 무시될 수 있도록 Layer에 IgnoreRaycast를 설정했습니다.

 

Raycast는 아래 글을 참고했습니다!

[Unity] Physics.Raycast에 대한 고찰 (tistory.com)

 

[Unity] Physics.Raycast에 대한 고찰

Unity에서 광선을 쏘아 충돌체를 감지할 수 있는 Physics.Raycast알아보고, 이를 디버깅할 때 사용할 수 있는 Draw.Debug에 대해 간단히 알아보자. 개념 시작 지점에서 특정 방향으로 씬의 모든 충돌체를

sikpang.tistory.com

 

 

 

위 처럼 게임 시스템을 계속해서 개선해나갈 것이고,

앞으로는 레벨 디자인에 좀 더 신경쓸 예정입니다!

현재까지 8개의 레벨을 만들었지만 아마 20개에서 30개 정도의 레벨을 더 만들고, 보스전을 하고 끝나게끔 할 것 같습니다!

추가로 여러 가지 기믹들(On/Off 타이머, 레이저, 큐브와 같은 물체 등)을 추가해볼 예정입니다.

 

+ 개선해야 할 사항 개인 Note.

- 키보드 이모티콘이 배경인 줄 아는 경우 발생 -> TEXT로 바꾸기.

- 수직 벽에는 마찰력 줄이기.

- 레벨 사이사이에 간단한 팁, 또는 스토리를 설명하는 창 만들기. (확인 버튼도 추가.)