Menu
CoddyTech

לעולם לא שטוח

שיעור 10 מתוך 16 בקורס משחק Unity: שובר לבנים של Coddy.

כדור עלול למצוא את עצמו עף כמעט הצידה: פגיעה בפינה של לבנה או דחיפה מכדור אחר עלולות לגרום לו לנוע כמעט במקביל לקרקע, ולחצות את המגרש שוב ושוב בלי לרדת. המשחק נתקע בזמן שהשחקן מחכה שהכדור ירד. התיקון שייך לתיקון המהירות: אחרי שהופכים את הכיוון ליחידה שאורכה 1, אם רכיב ה־y שלו קטן מדי, קובעים ל־y ערך מינימלי ומנרמלים שוב.

שתי מתודות של Mathf עושות את העבודה. Mathf.Abs מחזירה את הגודל של מספר בלי הסימן שלו, כך שבדיקה אחת תופסת גם כדורים שעולים וגם כדורים שיורדים. Mathf.Sign מחזירה ‎-1 למספר שלילי ו־1 אחרת, כך שה־y החדש שומר על כיוון התנועה של הכדור: כדור שיורד עדיין ימשיך לרדת.

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

נראה את זה עם ערך מינימלי של 0.3 והכיוון (0.99, -0.12, 0). הגודל של y, שהוא 0.12, קטן מ־0.3, ולכן y הופך ל־-0.3, והווקטור (0.99, -0.3, 0) לאחר נרמול הוא בערך (0.96, -0.29, 0): עדיין ימינה ולמטה, אבל עכשיו בזווית תלולה מספיק כדי לחזור. הנרמול מקטין שוב מעט את y מתחת לערך המינימלי, ובשלב הבא מעלים אותו שוב, כך שהוא נשאר מעט מתחת ל־0.3. כיוונים תלולים יותר נשארים ללא שינוי.

challenge icon

אתגר

בינוני
  1. הוסף את public float minVertical = 0.3f אל Ball.
  2. ב־FixedUpdate(), קח את הכיוון: את המהירות, לאחר נרמול. אם הגודל של ה־y שלו קטן מ־minVertical, הגדר את y ל־minVertical עם הסימן של y, ונרמל שוב את הכיוון.
  3. לאחר מכן הגדר את המהירות לכיוון כפול speed, כמו קודם.

לחץ על Play, ואז על Check.

נסו בעצמכם

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);
    }
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה משחק Unity: שובר לבנים