Menu
CoddyTech

절대 평평하지 않게

Coddy의 Unity 게임: 벽돌깨기 코스 레슨. 16개 중 10번째.

공이 거의 옆으로 날아갈 수도 있습니다. 벽돌 모서리에 맞고 튀거나 다른 공에 밀리면 공이 거의 수평으로 이동하며, 아래로 내려오지 않은 채 경기장을 계속 가로지를 수 있습니다. 공이 내려오기만 기다리는 동안 게임은 멈춥니다. 해결 방법은 속도 보정에 있습니다. 방향 벡터의 길이를 1로 만든 다음, y 성분이 너무 작으면 y를 최솟값으로 설정하고 다시 정규화하면 됩니다.

두 가지 Mathf 메서드가 이 작업을 수행합니다. Mathf.Abs는 부호를 제외한 숫자의 크기를 반환하므로, 한 번의 검사로 위로 가는 공과 아래로 가는 공을 모두 처리할 수 있습니다. Mathf.Sign은 음수이면 -1을, 그렇지 않으면 1을 반환하므로 새 y 값은 공의 진행 방향을 유지합니다. 아래로 가는 공은 계속 아래로 갑니다.

float drift = -0.12f;
Debug.Log(Mathf.Abs(drift));    // 0.12
Debug.Log(Mathf.Sign(drift));   // -1

최솟값을 0.3으로 하고 방향 벡터를 (0.99, -0.12, 0)으로 두어 살펴보겠습니다. y의 크기인 0.12는 0.3보다 작으므로 y는 -0.3이 되고, (0.99, -0.3, 0)을 정규화하면 약 (0.96, -0.29, 0)이 됩니다. 여전히 오른쪽 아래로 이동하지만, 이제 충분히 가파르게 움직여 되돌아옵니다. 정규화하면 y가 다시 최솟값보다 약간 작아지고, 다음 단계에서 이를 조금 보정하므로 계속 0.3보다 약간 작게 유지됩니다. 더 가파른 방향은 그대로 둡니다.

challenge icon

챌린지

중급
  1. Ball에 public float minVertical = 0.3f를 추가하세요.
  2. FixedUpdate()에서 방향을 구하세요. 속도를 정규화한 값입니다. y의 크기가 minVertical보다 작으면 y의 부호를 유지하면서 y를 minVertical로 설정하고, 방향을 다시 정규화하세요.
  3. 그런 다음 이전과 같이 속도를 방향에 speed를 곱한 값으로 설정하세요.

Play를 누른 다음 Check를 누르세요.

직접 해보기

using UnityEngine;
using UnityEngine.InputSystem;

public class Ball : MonoBehaviour
{
    public Transform paddle;
    public float speed = 9f;

    Rigidbody rb;
    bool launched;

    void Awake()
    {
        rb = GetComponent<Rigidbody>();
        PhysicsMaterial bouncy = new PhysicsMaterial("Bouncy");
        bouncy.bounciness = 1f;
        bouncy.dynamicFriction = 0f;
        bouncy.staticFriction = 0f;
        bouncy.bounceCombine = PhysicsMaterialCombine.Maximum;
        bouncy.frictionCombine = PhysicsMaterialCombine.Minimum;
        GetComponent<Collider>().material = bouncy;
    }

    void Update()
    {
        if (launched) return;
        transform.position = paddle.position + Vector3.up * 0.5f;
        if (Keyboard.current.spaceKey.wasPressedThisFrame) Launch(new Vector3(0.3f, 1f, 0f));
    }

    public void Launch(Vector3 direction)
    {
        launched = true;
        rb.linearVelocity = direction.normalized * speed;
    }

    public void ResetToPaddle()
    {
        launched = false;
        rb.linearVelocity = Vector3.zero;
    }

    void FixedUpdate()
    {
        if (!launched) return;
        rb.linearVelocity = rb.linearVelocity.normalized * speed;
    }

    void OnCollisionEnter(Collision collision)
    {
        if (!collision.gameObject.CompareTag("Paddle")) return;
        float offset = transform.position.x - collision.transform.position.x;
        float halfWidth = collision.collider.bounds.size.x / 2f;
        float x = Mathf.Clamp(offset / halfWidth, -1f, 1f);
        rb.linearVelocity = new Vector3(x, 1f, 0f).normalized * speed;
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("DeathZone")) GameManager.Instance.BallLost(this);
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Unity 게임: 벽돌깨기의 모든 레슨