אף פעם לא שטוח
שיעור 10 מתוך 19 בקורס Unity: משחק שובר לבנים של Coddy.
קפיצה מפינה של לבנה עלולה להשאיר את הכדור כמעט אופקי, כך שהוא חוצה את המגרש שוב ושוב בזמן שהשחקן ממתין. הפתרון הוא בתיקון המהירות: אם רכיב ה-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 אונליין