본문 바로가기
프로그래밍 이야기/GameDev

[게임이론] 등가속도 운동, 포물선 운동의 활용

by Mulder5 2021. 1. 18.
반응형

[게임이론] 등가속도 운동, 포물선 운동에서 학습한 내용을 Unity에 적용해본다.

 

위의 동영상과 같이 Space키를 누르면 입력한 각도와 가속도로 포물선 운동을 하는 예제를 바탕으로 등가속도 운동 및 포물선 운동에 대해 알아본다.

Inspector상에서 Ball에 대한 가속도는 10, 각도는 50도로 설정되었다.

이에 대한 소스 코드는 다음과 같다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BallController : MonoBehaviour
{
    public float shotVelocity;
    public float shotAngle;

    private Rigidbody2D ballRB2D;
    private bool isGround = true;
    private bool isCenter = false;
    private float totalTime = 0f;

    void Start()
    {
        ballRB2D = GetComponent<Rigidbody2D>();
    }
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            StartCoroutine(ShotBall());
        }
    }
    IEnumerator ShotBall()
    {
        Debug.Log("=== Simulation ===");

        isGround = false;
        // 공의 각도를 설정
        transform.right = new Vector2(Mathf.Cos(shotAngle * Mathf.Deg2Rad), Mathf.Sin(shotAngle * Mathf.Deg2Rad));
        // 설정된 각도 shotVelocity 속도로 발사
        ballRB2D.velocity = transform.right * shotVelocity;

        totalTime = 0f;
        while (true)
        {
            yield return null;
            // 착지하면 while문 종료
            if (isGround) break;
            // 작치자히 전까지는 계속 시간 측정
            totalTime += Time.deltaTime;

            // y축의 속도의 절대값이 0.1보다 작을때 isCenter == false일때(딱 한번만 발동)
            if (Mathf.Abs(ballRB2D.velocity.y) < 0.1f && !isCenter)
            {

                isCenter = true;
                Debug.Log("CenterHeight: " + transform.position.y);
            }
        }
    }
    private void OnCollisionEnter2D(Collision2D _col)
    {
        // 그라운드에 착지
        if(isGround == false)
        {
            isGround = true;
            // 더이상 움지기지 않게 하기 위해 속도는 0
            ballRB2D.velocity = Vector2.zero;
            //총 걸린 시간
            Debug.Log("Totaltime: " + totalTime);
            // 초기위치가 -8에서 시작 했기 때문에 +8로 보정 (총 이동거리)
            Debug.Log("TotalMeter: " + (transform.position.x + 8));

            Verification();
        }
    }

    private void Verification()
    {
        // 공식을 적용한 계산값 확인.
        Debug.Log("=== Verification ===");

        // 총걸린 시간은 2t
        // 2 * V* sin(theta)/g 
        float totalTime = 2 * shotVelocity * Mathf.Sin(shotAngle * Mathf.Deg2Rad) / 9.81f;
        // 최고 높이 (V*sin(theta))^2 / (2g)
        float centerHeight = Mathf.Pow(shotVelocity * Mathf.Sin(shotAngle * Mathf.Deg2Rad), 2) / (2*9.81f); //
        // 총 날아간 거리 2*V^2*sin(theta)*cos(theta)/g = > 2sin(theta)cos(theta) == sing(2theta) => v^2/g*sin(2*theta)
        float totalMeter = Mathf.Pow(shotVelocity,2) / 9.81f * Mathf.Sin(2 * shotAngle * Mathf.Deg2Rad); // 

        Debug.Log("Totaltime: " + totalTime);
        Debug.Log("CenterHeight: " + centerHeight);
        Debug.Log("TotalMeter: " + totalMeter);

        // Simulation 값과 Verification 결과의 오차가 발생하는 이유
        // Project Settings - Physics 2D의 속성값에 따라 계산 결과가 다르기 때문이다.
    }
}

 

Ball의 발사

SpaceBar가 눌리면 Coroutine으로 ShotBall() 호출된다. 이 함수 내에서 방향과 가속도가 입력된다. Ball은 아래의 공식에 의해 방향이 결정되었다.

 

Ball이 이동하는 동안의 시간 증가, 최고점 확인

ShotBall() 내에서 이동하는 동안의 시간을 증가시키고, y축의 속도가 0일때 (0.1보다 작을떄) 최고점으로 가정하고,  중심점 도달 처리를 수행한다.

 

Ball과 Ground의 충돌

Ball이 중심점(최고점)을 지나 하강을 하고 결국 Ground와 충돌하면 Ball의 이동을 멈추고 전체 시간과 이동거리를 로그로 출력한다.

 

Verification()

지난 학습에서 나온 공식을 이용해서 직접 시간, 최고 높이, 이동 거리를 계산한다. 이 값은 ShotBall(), OnCollisionEnter2D()를 수행하며 도출된 값과는 작은 오차가 있지만 거의 같다. 그 이유는 Unity의 Physics2D 의 속성 설정 값에 따라 계산 결과가 다르기 때문이다.

반응형