לעולם לא שטוח
שיעור 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. כיוונים תלולים יותר נשארים ללא שינוי.
אתגר
בינוני- הוסף את
public float minVertical = 0.3fאלBall. - ב־
FixedUpdate(), קח את הכיוון: את המהירות, לאחר נרמול. אם הגודל של ה־y שלו קטן מ־minVertical, הגדר את y ל־minVerticalעם הסימן של y, ונרמל שוב את הכיוון. - לאחר מכן הגדר את המהירות לכיוון כפול
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);
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.