Menu
CoddyTech

Không bao giờ nhàm chán

Bài học 10 trên 19 trong khóa học Trò chơi Unity: phá gạch của Coddy.

Cú nảy trúng góc viên gạch có thể khiến bóng bay gần như ngang, liên tục băng qua sân trong khi người chơi chờ đợi. Cách khắc phục nằm ở phần sửa tốc độ: nếu thành phần y của hướng quá nhỏ, hãy đặt nó ở mức tối thiểu rồi chuẩn hóa lại.

Mathf.Abs cho biết độ lớn của một số mà không xét dấu, vì vậy một phép kiểm tra sẽ bắt được bóng bay lên lẫn bay xuống. Mathf.Sign trả về -1 với số âm và 1 trong các trường hợp còn lại, nên bóng đang bay xuống vẫn tiếp tục bay xuống.

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

Với mức tối thiểu là 0.4, hướng (0.99, -0.12, 0) có y bằng -0.4 và sau khi chuẩn hóa sẽ xấp xỉ (0.93, -0.37, 0): bóng vẫn bay sang phải và xuống dưới, nhưng giờ hướng đủ dốc để quay lại. Các hướng dốc hơn sẽ được giữ nguyên.

challenge icon

Thử thách

Trung bình

Đừng để bóng bay gần như ngang qua sân.

  1. Trong Ball, thêm public float minVertical = 0.3f;
  2. Trong FixedUpdate, lấy Vector3 direction = rb.linearVelocity.normalized;. Nếu Mathf.Abs(direction.y) < minVertical, đặt direction.y = Mathf.Sign(direction.y) * minVertical; rồi chuẩn hóa lại.
  3. Đặt rb.linearVelocity = direction * speed;

Nhấn Chơi: bóng sẽ không bay ngang qua sân trong thời gian dài. Sau đó nhấn Kiểm tra.

Tự làm thử

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);
    }
}

Tất cả bài học trong Trò chơi Unity: phá gạch

Tự luyện tập: Playground Unity