Menu
CoddyTech

永不平局

Coddy Unity 游戏:打砖块 课程的第 10 课,共 19 课。

球撞到砖块的角后,可能几乎水平地弹开,在场地上来回穿行,而玩家只能等待。解决办法是在速度修正中处理:如果方向的 y 分量太小,就把它设为最小值,然后再次归一化。

Mathf.Abs 会返回一个数的绝对值,也就是不带符号的大小,因此一次判断就能捕捉向上和向下移动的球。Mathf.Sign 对负数返回 -1,否则返回 1,因此球向下移动时仍会继续向下。

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

如果最小值设为 0.4,方向 (0.99, -0.12, 0) 的 y 分量会变成 -0.4,归一化后约为 (0.93, -0.37, 0):仍然向右下方移动,但现在角度足够陡,能够弹回来。角度更陡的方向则保持不变。

challenge icon

挑战

中等

别让球长时间近乎水平地穿过场地。

  1. 在 Ball 中,添加 public float minVertical = 0.3f;
  2. 在 FixedUpdate 中,获取 Vector3 direction = rb.linearVelocity.normalized;。如果 Mathf.Abs(direction.y) < minVertical,就设置 direction.y = Mathf.Sign(direction.y) * minVertical;,然后再次归一化。
  3. 设置 rb.linearVelocity = direction * speed;

按下“开始”:球就不会长时间近乎水平地穿过场地。然后点击“检查”。

亲手试试

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

Unity 游戏:打砖块中的所有课

自己练习: Unity 在线编辑器