본문 바로가기
디지털노마드

[챗GPT게임개발8] ChatGPT를 활용하여 플랫폼 라이딩 구현하기

by 인텔리노마드라이프 2024. 5. 2.
728x90

안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.

오늘은 ChatGPT를 활용하여 플랫폼 라이딩 기능을 구현해볼거예요.

플랫폼 라이딩 또는 플랫폼 추종(Platform Following)

플레이어가 움직이는 플랫폼 또는 타일 위에서 자연스럽게 함께 이동하도록 구현하는 기법으로, 플레이어가 플랫폼 위에 있을 때 플랫폼의 이동에 따라 플레이어의 위치를 조정해주는 기능을 말합니다. 이는 플레이어가 움직이는 지면이나 플랫폼 위에서 안정적으로 유지되도록 하여, 게임 내에서의 실제감과 몰입감을 높이는 데 도움을 줍니다.

 

지난 번 코드에서는 플레이어가 타일과 같이 움직이지 않았어요.

아래 코드는 타일을 원하는 방향으로 움직였지만

플레이어가 타일 위에 올라가면 움직이는 타일 방향으로 같이 이동되지 않았어요.

using UnityEngine;

namespace Platformer.Mechanics
{
    /// <summary>
    /// A simple controller for moving tiles. Provides movement control over a patrol path.
    /// </summary>
    [RequireComponent(typeof(Collider2D))]
    public class TileMover : MonoBehaviour
    {
        public PatrolPath path;
        internal PatrolPath.Mover mover;
        internal Collider2D _collider;

        public Bounds Bounds => _collider.bounds;

        void Awake()
        {
            _collider = GetComponent<Collider2D>();
        }

        void Update()
        {
            if (path != null)
            {
                if (mover == null) mover = path.CreateMover(1.0f); // You can adjust the speed as necessary
                var moveX = mover.Position.x - transform.position.x;
                transform.position += new Vector3(moveX, 0, 0) * Time.deltaTime;
            }
        }
    }
}

 

플레이어가 플랫폼 위에 있을 때 플랫폼의 이동에 따라 플레이어의 위치를 조정해달라고 했어요.

조정하기 전에 소스 코드 학습부터 먼저 시켰어요.

 

원하는 결과를 코드를 얻기 위해서 먼저 코드 학습 또는 사전 지식에 대한 학습을 먼저 시키는 게 도움이 될 때가 있어요.

꼭 기억해주세요.

 

[질문] 안녕 ChatGPT, 먼저 아래 소스 코드를 천천히 그리고 정확히 분석해줘 
using UnityEngine;

namespace Platformer.Mechanics
{
    /// <summary>
    /// A simple controller for moving tiles. Provides movement control over a patrol path.
    /// </summary>
    [RequireComponent(typeof(Collider2D))]
    public class TileMover : MonoBehaviour
    {
        public PatrolPath path;
        internal PatrolPath.Mover mover;
        internal Collider2D _collider;

        public Bounds Bounds => _collider.bounds;

        void Awake()
        {
            _collider = GetComponent<Collider2D>();
        }

        void Update()
        {
            if (path != null)
            {
                if (mover == null) mover = path.CreateMover(1.0f); // You can adjust the speed as necessary
                var moveX = mover.Position.x - transform.position.x;
                transform.position += new Vector3(moveX, 0, 0) * Time.deltaTime;
            }
        }
    }
}

[답변]

이 소스 코드는 Unity 게임 엔진을 사용하여 2D 게임 내에서 이동하는 타일을 제어하는 TileMover 클래스를 정의하고 있습니다. 이 클래스는 특정 경로(Patrol Path)를 따라 타일을 움직이게 하는 기능을 구현합니다.

코드 상세 분석

  1. 네임스페이스와 클래스 선언
    • Platformer.Mechanics: 이 클래스가 포함된 네임스페이스입니다. 이는 클래스를 조직화하고, 다른 코드와의 명확한 구분을 돕습니다.
    • TileMover: 이 클래스는 MonoBehaviour를 상속받아 Unity의 게임 오브젝트에 붙일 수 있는 컴포넌트로 동작합니다.
  2. 필수 컴포넌트
    • [RequireComponent(typeof(Collider2D))]: 이 어트리뷰트는 TileMover 컴포넌트가 게임 오브젝트에 추가될 때 자동으로 Collider2D 컴포넌트의 추가를 요구합니다. 이는 TileMover가 제대로 기능하기 위해 Collider2D가 필수적임을 의미합니다.
  3. 멤버 변수
    • public PatrolPath path;: TileMover가 따라야 할 PatrolPath 오브젝트입니다. 이 경로를 따라 타일이 움직입니다.
    • internal PatrolPath.Mover mover;: 실제로 경로를 따라 움직이는 로직을 처리하는 Mover 인스턴스입니다.
    • internal Collider2D _collider;: 이 컴포넌트에 연결된 Collider2D 컴포넌트를 참조합니다.
  4. 속성
    • public Bounds Bounds => _collider.bounds;: 타일의 경계를 반환하는 속성입니다. 이는 타일의 현재 충돌 범위를 나타냅니다.
  5. 메소드
    • void Awake(): 이 메소드는 게임 오브젝트가 처음 활성화될 때 호출됩니다. 여기서 _collider는 해당 게임 오브젝트에서 Collider2D 컴포넌트를 가져옵니다.
    • void Update(): 매 프레임마다 호출되는 메소드입니다. 만약 path가 설정되어 있다면, mover 인스턴스를 생성하고, 계산된 moveX 값을 사용하여 타일을 x축 방향으로 움직입니다. 이동은 Time.deltaTime을 곱하여 프레임 속도에 따라 일관되게 조절됩니다.

이 클래스는 특정 경로를 따라 타일을 움직이기 위한 기본적인 구조를 제공하며, 간단한 패트롤 또는 루트 기반의 타일 움직임을 구현하는 데 사용될 수 있습니다.

 

챗GPT가 소스에 대한 학습을 완료했어요.

이제 플레이어가 플랫폼 위에 있을 때 플랫폼의 이동에 따라 플레이어의 위치를 조정하라고 할께요.

 

[질문] 안녕 ChatGPT, 이제 플레이어가 타일 위에 있을 때 타일과 함께 움직이되, 플레이어의 독립적인 이동 액션 (점프, 좌우 이동)을 방해하지 않도록 TileMover 클래스를 수정해줘 

[답변]

TileMover 클래스를 수정하여 플레이어가 타일 위에 있을 때 타일과 함께 움직이면서도, 플레이어가 점프나 좌우 이동과 같은 독립적인 액션을 수행할 수 있도록 하는 것은 Unity에서 흔히 사용되는 패턴입니다. 이를 위해 TileMover 클래스 내에서 플레이어와의 상호작용을 감지하고, 플레이어가 타일 위에 있을 때 플레이어의 위치를 타일의 이동에 맞추어 조정하는 로직을 추가할 수 있습니다.

아래는 이를 구현하기 위한 수정된 TileMover 클래스 코드 예제입니다:

using UnityEngine;

namespace Platformer.Mechanics
{
    /// <summary>
    /// A simple controller for moving tiles. Provides movement control over a patrol path and moves players standing on it.
    /// </summary>
    [RequireComponent(typeof(Collider2D))]
    public class TileMover : MonoBehaviour
    {
        public PatrolPath path;
        internal PatrolPath.Mover mover;
        internal Collider2D _collider;

        public Bounds Bounds => _collider.bounds;

        void Awake()
        {
            _collider = GetComponent<Collider2D>();
        }

        void Update()
        {
            if (path != null)
            {
                if (mover == null) mover = path.CreateMover(1.0f); // You can adjust the speed as necessary
                float moveX = mover.Position.x - transform.position.x;
                transform.position += new Vector3(moveX, 0, 0) * Time.deltaTime;

                MoveRiders(moveX);
            }
        }

        void MoveRiders(float moveX)
        {
            // Find all colliders on top of the tile
            RaycastHit2D[] hits = Physics2D.BoxCastAll(_collider.bounds.center, _collider.bounds.size, 0f, new Vector2(0, 1), 0.1f);
            foreach (RaycastHit2D hit in hits)
            {
                if (hit.collider != _collider)
                {
                    // Move any objects that are on top of the tile
                    var hitRigidbody = hit.collider.attachedRigidbody;
                    if (hitRigidbody != null)
                    {
                        hitRigidbody.position += new Vector2(moveX, 0) * Time.deltaTime;
                    }
                }
            }
        }
    }
}

주요 변경 사항

  1. MoveRiders 메소드 추가: 이 메소드는 타일 위에 있는 객체들(플레이어 포함)을 탐지하고, 타일과 함께 이동시키는 로직을 포함합니다. Physics2D.BoxCastAll 함수를 사용하여 타일 바로 위에 있는 객체들을 찾고, 이 객체들을 타일의 x축 이동에 맞추어 같이 이동시킵니다.
  2. Update 메소드 내 MoveRiders 호출: Update 메소드에서 타일의 위치가 업데이트된 후 MoveRiders 함수를 호출하여, 타일 위의 객체들도 같이 이동하도록 합니다.

이 수정을 통해 플레이어가 타일 위에 서 있을 때 타일과 함께 움직이면서도 독립적으로 점프하거나 좌우로 이동할 수 있게 됩니다. 이는 플레이어가 자연스럽게 플랫폼 위에서의 움직임을 경험할 수 있도록 돕습니다.

 

수정된 스크립트 및 모든 변경사항을 적용했어요.

그리고 Play 버튼을 클릭하여 게임을 실행하고 타일이 제대로 작동하는지 확인했어요.

 

[플랫폼 라이딩 실행 화면]

 

플랫폼 라이딩이 잘되었어요.

OnCollisionEnter2D을 왜 쓰지 않을까?

다른 교육 자료나 영상을 보면 플랫폼 라이딩을 위해 OnCollisionEnter2D와 OnCollisionExit2D를 사용했어요.

그래서 다음과 같이 수정을 해봤어요.

 

[질문] 안녕 ChatGPT, 위 코드는 동작을 잘 하고 있어. 혹시 OnCollisionEnter2D 등을 활용해서도 코드 수정이 가능하니? 

[답변]

네, Unity의 OnCollisionEnter2DOnCollisionExit2D 이벤트를 활용하여 플레이어가 타일 위에 있을 때 타일과 함께 움직이도록 처리하는 것도 가능합니다. 이 방법은 플레이어가 타일에 진입하고 탈출하는 시점을 정확하게 감지하고, 이에 따라 플레이어를 타일과 함께 움직이게 할 수 있습니다. 아래는 해당 이벤트를 사용한 코드 예제입니다.

using UnityEngine;

namespace Platformer.Mechanics
{
    [RequireComponent(typeof(Collider2D))]
    public class TileMover : MonoBehaviour
    {
        public PatrolPath path;
        internal PatrolPath.Mover mover;
        internal Collider2D _collider;

        public Bounds Bounds => _collider.bounds;

        private void Awake()
        {
            _collider = GetComponent<Collider2D>();
        }

        private void Update()
        {
            if (path != null)
            {
                if (mover == null) mover = path.CreateMover(1.0f); // Adjust speed as necessary
                float moveX = mover.Position.x - transform.position.x;
                transform.position += new Vector3(moveX, 0, 0) * Time.deltaTime;
            }
        }

        private void OnCollisionEnter2D(Collision2D collision)
        {
            if (collision.collider.CompareTag("Player"))
            {
                var playerRigidbody = collision.collider.GetComponent<Rigidbody2D>();
                if (playerRigidbody != null)
                {
                    playerRigidbody.transform.parent = this.transform;
                }
            }
        }

        private void OnCollisionExit2D(Collision2D collision)
        {
            if (collision.collider.CompareTag("Player"))
            {
                var playerRigidbody = collision.collider.GetComponent<Rigidbody2D>();
                if (playerRigidbody != null)
                {
                    playerRigidbody.transform.parent = null;
                }
            }
        }
    }
}

주요 변경 사항 설명

  1. OnCollisionEnter2D 메소드: 이 메소드는 플레이어가 타일과 충돌할 때 호출됩니다. 여기서 플레이어의 Rigidbody2D 컴포넌트를 가져와서 플레이어의 transform.parent 속성을 타일의 transform으로 설정합니다. 이렇게 하면 플레이어가 타일의 자식 오브젝트가 되어 타일과 함께 움직이게 됩니다.
  2. OnCollisionExit2D 메소드: 플레이어가 타일에서 떨어질 때 호출됩니다. 플레이어의 transform.parent 속성을 null로 설정하여, 플레이어를 타일의 자식 오브젝트에서 제거함으로써 독립적인 움직임을 회복합니다.

이 방법을 사용하면 플레이어가 타일에 머무는 동안 타일과 함께 자연스럽게 움직일 수 있으며, 타일에서 벗어나면 원래의 독립적인 움직임을 회복할 수 있습니다. 이는 특히 플레이어와 타일 간의 상호작용이 명확할 필요가 있을 때 유용하게 사용될 수 있습니다.

 

플레이어가 타일 위에서 이동이 되지 않아.

그런데 이 코드를 실행했더니 원하는 결과가 나오지 않아서 다시 수정했어요. 

2-3번 정도 수정 후 정상적인 코드가 나왔어요.

[질문] 안녕 ChatGPT, 그런데 이 코드를 쓸 때 플레이어가 타일 위에서 이동이 되지 않아

[답변]

이 문제를 해결하기 위해 첫 번째 코드의 접근 방식을 수정해야 합니다. 코드에서 플레이어가 타일에 올라올 때 플레이어를 타일의 자식으로 만드는 부분(playerRigidbody.transform.parent = this.transform;)이 플레이어의 자유로운 이동을 방해하고 있습니다. 이는 플레이어가 타일의 부모-자식 계층구조에 종속되면서, 타일의 모든 움직임을 상속받게 되기 때문입니다.

아래는 첫 번째 코드를 수정하여 플레이어가 타일 위에서 자유롭게 움직일 수 있게 하면서도, 타일의 움직임에 따라 플레이어를 움직이도록 하는 수정된 버전입니다. 이 코드는 타일의 이동량만큼 플레이어의 위치를 직접 조정하는 방식을 사용합니다:

using UnityEngine;

namespace Platformer.Mechanics
{
    [RequireComponent(typeof(Collider2D))]
    public class TileMover : MonoBehaviour
    {
        public PatrolPath path;
        internal PatrolPath.Mover mover;
        internal Collider2D _collider;

        public Bounds Bounds => _collider.bounds;

        private void Awake()
        {
            _collider = GetComponent<Collider2D>();
        }

        private void Update()
        {
            if (path != null)
            {
                if (mover == null) mover = path.CreateMover(1.0f); // Adjust speed as necessary
                float moveX = mover.Position.x - transform.position.x;
                transform.position += new Vector3(moveX, 0, 0) * Time.deltaTime;
            }
        }

        private void OnCollisionStay2D(Collision2D collision)
        {
            if (collision.collider.CompareTag("Player"))
            {
                var playerRigidbody = collision.collider.attachedRigidbody;
                if (playerRigidbody != null)
                {
                    // Compensate for the tile movement
                    float moveX = mover.Position.x - transform.position.x;
                    playerRigidbody.position += new Vector2(moveX, 0) * Time.deltaTime;
                }
            }
        }
    }
}

주요 변경 사항 설명:

  • 부모-자식 관계 제거: 플레이어를 타일의 자식으로 설정하는 코드를 제거하고, 대신 OnCollisionStay2D 이벤트를 사용하여 플레이어가 타일에 있는 동안 플레이어를 이동시키는 로직을 구현했습니다.
  • 플레이어 이동 조정: OnCollisionStay2D에서 타일의 이동에 맞추어 플레이어의 위치를 조정합니다. 이를 통해 타일의 이동량만큼 플레이어의 위치를 업데이트하여 타일과 함께 이동하게 합니다. 이 방법은 플레이어의 자유로운 움직임을 보장하면서도 필요할 때 타일과 함께 움직이도록 도와줍니다.

이 수정을 통해 플레이어는 타일 위에서 자유롭게 이동할 수 있으며, 타일이 움직일 때 그 움직임에 맞추어 부드럽게 함께 움직일 수 있습니다.

 

이제 원하는 결과대로 코드가 동작하네요.

추가 궁금증이 있어서 아래 질문도 했어요.

[질문] 안녕 ChatGPT, OnCollisionExit2D 는 사용할 필요가 없나?

[답변]

네, 제시한 마지막 코드 예제에서는 OnCollisionExit2D를 사용할 필요가 없습니다. 이는 코드 내에서 플레이어를 타일의 자식으로 설정하거나 부모-자식 관계를 해제하는 로직을 사용하지 않기 때문입니다. 플레이어의 움직임이 타일과 독립적으로 처리되면서도, OnCollisionStay2D를 통해 타일과 플레이어가 접촉하는 동안에만 플레이어의 위치를 타일의 움직임에 맞춰 조정하기 때문에 충분합니다.

설명

  • 플레이어와 타일의 독립적인 이동 처리: 이 접근 방식에서는 타일이 움직일 때 플레이어의 위치를 직접 조정합니다. 플레이어가 타일 위에 있지 않은 경우에는 플레이어의 위치 조정이 필요 없으므로, OnCollisionExit2D에서 처리할 추가적인 로직이 없습니다.
  • 동적인 위치 조정: OnCollisionStay2D에서 타일과 함께 움직이는 로직을 처리하기 때문에, 플레이어가 타일에서 물리적으로 벗어나는 순간에 별도의 상태 변경이 필요 없습니다. 타일에서 벗어나는 순간 자연스럽게 OnCollisionStay2D의 영향이 사라지기 때문입니다.

다른 상황에서 OnCollisionExit2D가 필요한 경우

만약 타일이 플레이어에게 추가적인 효과를 주는 경우 (예: 속도 증가, 점프력 향상 등) 또는 플레이어와 타일 간의 특별한 상호작용이 있는 경우에는 OnCollisionExit2D를 사용하여 이러한 효과를 해제할 수 있습니다. 예를 들어, 플레이어가 특정 타일 위를 벗어날 때 효과를 제거하거나, 플레이어의 특정 상태를 초기화해야 하는 경우에 유용하게 사용될 수 있습니다.

현재 상황에서는 플레이어의 위치만 조정하는 간단한 로직을 구현하는 것이 목표이기 때문에, OnCollisionExit2D를 사용할 필요가 없습니다.

 

지금까지  플랫폼 라이딩을 구현해봤어요. 

 

[인텔리노마드라이프와 함께 행복하세요 from IntelliOneStudio ]

 

지금까지,

언제나 성장하는 인텔리원스튜디오(IntelliOneStudio)입니다.

감사합니다.

 

 

728x90