لا تجعلها مسطّحة أبدًا
الدرس 10 من 16 في دورة لعبة Unity: تحطيم الطوب على Coddy.
قد ينتهي الأمر بالكرة وهي تطير بشكل جانبي تقريبًا: فارتدادها عن زاوية طوبة أو دفع كرة أخرى لها قد يجعلها شبه أفقية، فتقطع الملعب مرارًا وتكرارًا من دون أن تهبط. تتوقف اللعبة بينما ينتظر اللاعب هبوطها. يكمن الحل في إصلاح السرعة: بعد جعل الاتجاه بطول وحدة واحدة، إذا كان جزء 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، كما سبق.
اضغط تشغيل، ثم تحقّق.
جرّب بنفسك
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);
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.