عضّ نفسك
الدرس 10 من 14 في دورة لعبة الثعبان ثلاثية الأبعاد في Unity على Coddy.
يموت الثعبان عندما يصطدم رأسه بذيله، كما يحدث عند اصطدامه بجدار. يُجرى الاختبار في الموضع نفسه: على next، الخلية التي أمامه، قبل أن يتحرك الرأس، ليبقى الرأس في مكانه عند انتهاء اللعبة.
جزء واحد آمن. في هذه الخطوة، يتحرك الجزء الأخير إلى الأعلى أيضًا، خارج خليته، لذا فإن الرأس الذي يتبع نهاية ذيله إلى تلك الخلية لا يلمسه أبدًا. يمكن لثعبان مكوّن من أربعة مكعبات أن يدور حول مربع أبعاده 2 في 2 إلى الأبد بهذه الطريقة. يستثني الاختبار الجزء الأخير بالتوقف قبل النهاية بجزء واحد:
// كل عنصر باستثناء الأخير
for (int i = 0; i < items.Count - 1; i++)
{
Debug.Log(items[i].name);
}مع كون الجدران والذيل كليهما قاتلين، يمكن خسارة اللعبة، ويضيف الفصل التالي النتيجة وطريقة للعب مرة أخرى.
التحدي
متوسطفي Step()، بعد اختبار الجدار: إذا كانت next خلية أيّ مقطع من الذيل باستثناء الأخير، فاستدعِ Die() ثم أعد، حتى لا يتحرك الرأس.
اضغط على Play، واجعل الثعبان يطول ثم اجعله يعضّ ذيله، وبعد ذلك اضغط على Check.
جرّب بنفسك
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Snake : MonoBehaviour
{
public float tick = 0.15f; // الثواني بين خطوتين
public int edge = 7; // تمتد خلايا اللوحة من -edge إلى edge
public bool alive = true;
public List<Transform> tail = new List<Transform>();
public Transform segmentPrefab;
private float timer;
private Vector3 direction = Vector3.right; // الاتجاه الذي تحرّك فيه الرأس في خطوته الأخيرة
private Vector3 nextDirection = Vector3.right; // الانعطاف المنتظر حتى الخطوة التالية
void Update()
{
if (!alive) return;
Keyboard keyboard = Keyboard.current;
if (keyboard != null)
{
if (keyboard.upArrowKey.wasPressedThisFrame || keyboard.wKey.wasPressedThisFrame) Turn(Vector3.forward);
if (keyboard.downArrowKey.wasPressedThisFrame || keyboard.sKey.wasPressedThisFrame) Turn(Vector3.back);
if (keyboard.leftArrowKey.wasPressedThisFrame || keyboard.aKey.wasPressedThisFrame) Turn(Vector3.left);
if (keyboard.rightArrowKey.wasPressedThisFrame || keyboard.dKey.wasPressedThisFrame) Turn(Vector3.right);
}
timer += Time.deltaTime;
if (timer >= tick)
{
timer -= tick;
Step();
}
}
void Turn(Vector3 newDirection)
{
if (newDirection != -direction)
{
nextDirection = newDirection;
}
}
void Step()
{
direction = nextDirection;
Vector3 next = transform.position + direction;
if (Mathf.Abs(next.x) > edge || Mathf.Abs(next.z) > edge)
{
Die();
return;
}
Vector3 tailEnd = tail.Count > 0 ? tail[tail.Count - 1].position : transform.position;
for (int i = tail.Count - 1; i > 0; i--)
{
tail[i].position = tail[i - 1].position;
}
if (tail.Count > 0)
{
tail[0].position = transform.position;
}
transform.position = next;
if (GameManager.Instance.IsFood(next))
{
tail.Add(Instantiate(segmentPrefab, tailEnd, Quaternion.identity));
GameManager.Instance.Eat();
}
}
public bool Occupies(Vector3 cell)
{
if (transform.position == cell) return true;
foreach (Transform segment in tail)
{
if (segment.position == cell) return true;
}
return false;
}
void Die()
{
alive = false;
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.