Bite Yourself
Lesson 10 of 14 in Coddy's Unity Game: Snake 3D course.
The snake dies when its head runs into its own tail, as it does on a wall. The test goes in the same place: on next, the cell ahead, before the head moves, so the head stays where it is when the game ends.
One segment is safe. On this step the last segment moves up too, out of its cell, so a head that follows the end of its tail into that cell never touches it. A snake of four cubes can circle a 2 by 2 square forever this way. The test leaves the last segment out by stopping one short of the end:
// every item but the last
for (int i = 0; i < items.Count - 1; i++)
{
Debug.Log(items[i].name);
}With the walls and the tail both deadly, the game can be lost, and the next chapter adds the score and a way to play again.
Challenge
MediumIn Step(), after the wall test: if next is the cell of any tail segment except the last one, call Die() and return, so the head does not move.
Press Play, grow the snake and bite your tail, then press Check.
Try it yourself
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Snake : MonoBehaviour
{
public float tick = 0.15f; // seconds between two steps
public int edge = 7; // the board's cells run from -edge to edge
public bool alive = true;
public List<Transform> tail = new List<Transform>();
public Transform segmentPrefab;
private float timer;
private Vector3 direction = Vector3.right; // the way the head moved on its last step
private Vector3 nextDirection = Vector3.right; // the turn waiting for the next step
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;
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.