永不平局
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):仍然向右下方移动,但现在角度足够陡,能够弹回来。角度更陡的方向则保持不变。
挑战
中等别让球长时间近乎水平地穿过场地。
- 在
Ball中,添加public float minVertical = 0.3f; - 在 FixedUpdate 中,获取
Vector3 direction = rb.linearVelocity.normalized;。如果Mathf.Abs(direction.y) < minVertical,就设置direction.y = Mathf.Sign(direction.y) * minVertical;,然后再次归一化。 - 设置
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 在线编辑器