Menu
CoddyTech

אף פעם לא שטוח

שיעור 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): עדיין ימינה ולמטה, אבל כעת בזווית תלולה מספיק כדי לחזור. כיוונים תלולים יותר נשארים ללא שינוי.

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 אונליין