[UNITY]/TIL: UNITY

움직이는 플랫폼 및 위에 있는 객체 함께 이동하기

네,가능합니다 2024. 10. 27. 19:44

개인 과제를 하던 도중 이것도 만들면 공부에 도움이 될 것 같아 만들었다.

 

오브젝트를 좌우, 상하 그리고 회전하게 하는 스크립트를 만들었다.

 

3가지 기능을 모두 넣고 에디터에서 수정하며 재밌는 맵을 만들 수 있게 해두었다.

 

이렇게 만들고 테스트를 해봤는데 오브젝트는 움직이는데 캐릭터는 혼자 가만히 있어서 마음에 들지 않았다..

 

처음에는 트리거를 이용해서 플레이어를 오브젝트의 자식오브젝트에 넣었다가 뺏다가를 반복할까 했는데

 

이런 방법은 성능적으로 좋지 않아 보였다. 그래서 플랫폼의 움직임에 맞게 플랫폼 주변의 객체를 함께 움직여줄것이다.

 

설명은 주석을 달아 적도록 하겠다.

 

using UnityEngine;

public class MovingPlatform : MonoBehaviour
{
    public enum MovementType { Vertical, Horizontal, Rotate }
    public MovementType movementType = MovementType.Vertical; // 움직임타입

    [Header("상하/좌우")]
    public float movementDistance = 5f; // 이동범위
    public float movementSpeed = 2f; // 속도

    [Header("회전")]
    public float rotationSpeed = 50f; // 회전 속도
    public Vector3 rotationAxis = Vector3.up; // 회전의 축 (Y축이 기본)

    private Vector3 startPosition; // 시작위치
    private Vector3 previousPosition; // 직전 프레임 기준 위치

    private void Start()
    {
        startPosition = transform.position;
        previousPosition = startPosition;
    }

    private void Update()
    {
        switch (movementType)
        {
            case MovementType.Vertical:
                MoveVertical();
                break;
            case MovementType.Horizontal:
                MoveHorizontal();
                //  좌우이동시 플랫폼 위의 객체도 함께 움직이게 하는 함수
                ApplyMovementToObjectsOnPlatform();
                break;
            case MovementType.Rotate:
                RotatePlatform();
                break;
        }

        previousPosition = transform.position;
    }

    private void MoveVertical()
    {
        float newY = startPosition.y + Mathf.Sin(Time.time * movementSpeed) * movementDistance;
        transform.position = new Vector3(transform.position.x, newY, transform.position.z);
    }

    private void MoveHorizontal()
    {
        float newX = startPosition.x + Mathf.Sin(Time.time * movementSpeed) * movementDistance;
        transform.position = new Vector3(newX, transform.position.y, transform.position.z);
    }

    private void RotatePlatform()
    {
        transform.Rotate(rotationAxis, rotationSpeed * Time.deltaTime);
    }

    private void ApplyMovementToObjectsOnPlatform()
    {
    	// movementDelta에 (플랫폼의 위치 - 직전프레임의위치)를 해서 얼만큼 이동했는지 담아준다.
        Vector3 movementDelta = transform.position - previousPosition;
        // 박스사이즈 조절
        Vector3 boxCenter = transform.position + Vector3.up * 0.5f - Vector3.right * 1.3f + Vector3.forward * 1.1f;
        Vector3 boxSize = new Vector3(2.5f, 1f, 2.5f);
		// Physics.OverlapBox를 이용하여 주변의 충돌체를 감지하여 배열로 반환
        Collider[] colliders = Physics.OverlapBox(transform.position, transform.localScale / 2);
        foreach (var col in colliders)
        {
            if (col.CompareTag("Player"))
            {
                col.transform.position += movementDelta;
            }
        }
    }
}

 

이해하기 어려울 수 있겠다고 생각한것만 주석을 달았습니다.

 

충돌체를 감지하는 박스는 기즈모 기준이라 이 코드를 적용하면 이상하게 작동할 수 있습니다.

 

private void OnDrawGizmos()
{
    Gizmos.color = Color.red; 
    Gizmos.DrawWireCube(boxCenter, boxSize);
}

 

이런 코드를 작성하여 기즈모를 시각화 하고, 박스의 크기를 조절해보시길 바랍니다.

 

해당 기즈모 시각화 코드는 스크립트를 컴포넌트에 추가하는 것 만으로도 작동합니다.