GAME OVER:
using UnityEngine;
What it does: This imports the main Unity library. It's essential for any Unity
script, allowing you to use core functions like MonoBehaviour and
GameObject.
using TMPro;
What it does: This imports the TextMeshPro library. You must add this line
anytime you want to control or get data from a TextMeshPro text element (like
TextMeshProUGUI).
public class GameOverDisplay : MonoBehaviour
public class GameOverDisplay: This declares your new script component,
naming it GameOverDisplay.
: MonoBehaviour: This is the most important part. It tells Unity that this script
can be attached to a GameObject. It also gives you access to all of-Unity's
built-in event functions, like Start() and Update().
{
What it does: This curly brace marks the beginning of your
GameOverDisplay class.
public TextMeshProUGUI scoreText;
public: This keyword makes the variable show up in the Unity Inspector.
TextMeshProUGUI: This declares that the variable, which you've named...
scoreText: ...can only hold a reference to a TextMeshPro UI Text object.
How you use it: After attaching this script to an object (like your "Game Over"
Canvas), you'll see a slot in the Inspector named "Score Text." You drag your
actual text object from the scene Hierarchy into this slot to connect them.
void Start()
What it does: Start() is a special Unity function that is called only once when
the script (or the object it's on) first becomes active in the scene. This makes it
the perfect place to set up initial values, like displaying the final score.
{
What it does: This brace marks the beginning of the Start() function.
int score = [Link];
int score: This creates a new temporary variable inside the Start function to
hold a whole number (int). You've named it score.
= [Link];: This is the key part. It reaches into your other script,
named Snake, and grabs the value of a static variable you must have created
there, named finalScore.
Why this works: You likely (and correctly) made finalScore in your Snake
script public static int finalScore;. The static keyword means this variable
belongs to the class itself, not just one instance of the snake. This allows any
other script (like this one) to easily access it at any time, which is perfect for a
final score.
[Link] = "Your Score: " + score;
What it does: This is the line that actually updates the text on the screen.
[Link]: It accesses the text property (the actual string of text that is
displayed) of the scoreText object you linked in the Inspector.
= "Your Score: " + score;: It assigns a new value to that text. It takes the
literal string "Your Score: " and then concatenates (adds) the number stored in
your score variable.
Example: If [Link] was 12, this line would set the text to display:
Your Score: 12.
}
What it does: This brace marks the end of the Start() function.
}
What it does: This final brace marks the end of your GameOverDisplay class.
FOOD:
using UnityEngine;
What it does: Imports the main Unity library, which is necessary for almost
any script. It gives you access to components like MonoBehaviour,
BoxCollider2D, LayerMask, Vector3, Random, etc.
public class Food : MonoBehaviour
public class Food: Declares your new script component, naming it Food.
: MonoBehaviour: This tells Unity that this script can be attached to a
GameObject (your food prefab). This also lets you use built-in functions like
Start() and OnTriggerEnter2D().
{
What it does: This curly brace marks the beginning of your Food class.
public BoxCollider2D gridArea;
public: This makes the variable appear in the Unity Inspector.
BoxCollider2D: This declares a variable that can hold a reference to a 2D
Box Collider component.
gridArea: This is the name you've given it.
How you use it: You'll likely create an empty GameObject in your scene
named "SpawnArea," add a BoxCollider2D to it, and scale it to cover your
whole game board. Then, you'll drag that "SpawnArea" object from your
Hierarchy into this "Grid Area" slot in the Inspector.
public LayerMask obstacleLayer;
public: Again, this makes it visible in the Inspector.
LayerMask: This is a special variable type that lets you select one or more
"Layers" from the Unity Editor.
obstacleLayer: The name of your variable.
How you use it: In the Inspector, you will select the layer(s) that you consider
"obstacles." For example, you probably have a "Wall" layer and a
"PlayerBody" layer. This script will use this to make sure the food doesn't
spawn on top of either.
private void Start()
What it does: This is a built-in Unity function that runs one time when the
GameObject this script is attached to first becomes active in the scene.
In this script: It's used to give the food its first random position when the
game begins.
{
What it does: Marks the beginning of the Start() function.
RandomizePosition();
What it does: This is a function call. It tells the script to find and run your
custom function (which you defined below) named RandomizePosition.
}
What itd does: Marks the end of the Start() function.
public void RandomizePosition()
What it does: This is a custom function (or "method") that contains all the
logic for finding a new, safe spot for the food. It's public so other scripts could
call it if needed, but here it's just called by Start() and OnTriggerEnter2D. void
means it doesn't return any value.
{
What it does: Marks the beginning of the RandomizePosition() function.
Bounds bounds = [Link];
Bounds: This is a struct that holds the exact boundaries (min and max X/Y/Z
coordinates) of a collider in world space.
[Link];: This gets the bounds from the BoxCollider2D you
linked in the Inspector. Now the bounds variable knows the exact left, right,
top, and bottom edges of your "Grid Area."
Vector3 newPosition;
What it does: Declares an empty Vector3 (X, Y, Z) variable. This will hold the
potential new spot for the food while the script checks if it's safe.
bool positionIsSafe;
What it does: Declares a bool (true/false) variable. This will act as a "flag" to
track if the newPosition is clear of obstacles.
do
What it does: This starts a do-while loop. This type of loop is special
because it always runs at least once before it checks the while condition at
the end.
Why use it? You need to at least pick one random spot before you can even
check if it's safe.
{
What it does: Marks the beginning of the loop's code block.
float x = [Link]([Link].x, [Link].x);
What it does: Generates a random float (a number with decimals) for the X-
coordinate. The number will be somewhere between the far left
([Link].x) and far right ([Link].x) of your grid area.
float y = [Link]([Link].y, [Link].y);
What it does: Does the same thing for the Y-coordinate, picking a random
spot between the bottom ([Link].y) and top ([Link].y).
newPosition = new Vector3([Link](x), [Link](y), 0.0f);
What it does: This takes the random x and y values and rounds them to the
nearest whole number.
[Link](): This is the key to making your game grid-based. It turns a
value like 7.81 into 8.0 and 3.2 into 3.0.
Result: This ensures your food always lands perfectly on an integer
coordinate (like (5, 2) or (-1, 7)), just like your snake.
Collider2D hit = [Link](newPosition, [Link] * 0.5f, 0f,
obstacleLayer);
What it does: This is the safety check.
[Link](...): This function creates a small, invisible box at a
specific point and checks if it's touching any other colliders.
newPosition: The center of the invisible box (the spot we are testing).
[Link] * 0.5f: The size of the invisible box. [Link] is (1, 1), so
multiplying by 0.5f makes the box 0.5 units wide and 0.5 units tall.
0f: The rotation of the box (0 degrees).
obstacleLayer: This tells the function to only check for colliders that are on
the "Obstacle" layers you chose in the Inspector.
Collider2D hit = ...: If the box hits an obstacle, hit will store that obstacle's
collider. If it hits nothing, hit will be null (empty).
positionIsSafe = (hit == null);
What it does: This sets your bool flag.
If hit is null (empty, no obstacle found), then positionIsSafe becomes true.
If hit is not null (it hit a wall or the snake), then positionIsSafe becomes false.
} while (!positionIsSafe);
What it does: This is the condition for the do-while loop.
!positionIsSafe: The ! means "NOT". So, this reads as "while position is NOT
safe".
How it works: If positionIsSafe is false (it hit an obstacle), the loop will run all
over again (picking a new random x and y). It will keep doing this until it finds
a spot where positionIsSafe becomes true.
[Link] = newPosition;
What it does: Once the loop finally exits (meaning it found a safe spot), this
line moves the actual food GameObject to that newPosition.
}
What it does: Marks the end of the RandomizePosition() function.
private void OnTriggerEnter2D(Collider2D other)
What it does: This is another built-in Unity function. It runs automatically
whenever another collider enters this object's collider.
Requirements: For this to work, your food object must have a Collider2D
component with its "Is Trigger" box checked. The "other" object (your snake
head) must have a Rigidbody2D and a Collider2D.
Collider2D other: This variable holds a reference to the collider that just hit
the food (e.g., the snake's head).
{
What it does: Marks the beginning of the OnTriggerEnter2D() function.
if ([Link] == "Player")
What it does: This checks the Tag of the object that just hit the food.
How you use it: You must select your snake head GameObject in the
Inspector and set its Tag to "Player" (you may need to add this tag to your
project first).
Why? This ensures that the food only respawns when the player hits it, not if
something else (like another piece of food, if you had multiple) bumps into it.
{
What it does: Marks the beginning of the if statement's code.
RandomizePosition();
What it does: If the tag was "Player", it simply calls your RandomizePosition()
function again, which instantly moves the food to a new, safe, random spot.
}
What it does: Marks the end of the if statement.
}
What it does: Marks the end of the OnTriggerEnter2D() function.
}
What it does: Marks the end of your Food class.
Here is a line-by-line explanation of your Snake script.
This is the main script for your game. It controls the player's snake, including
handling keyboard input, moving the snake, growing when it eats food, tracking the
score, and handling death (collision).
SNAKE:
using System;
What it does: Imports the base System library for core C# functionalities.
using [Link];
What it does: This is very important. It imports the library that allows you to
use List<T>, which you use to store all the snake's body segments.
using UnityEngine;
What it does: The standard Unity library, required for MonoBehaviour,
Vector2, Transform, Input, PlayerPrefs, etc.
using TMPro;
What it does: Imports the TextMeshPro library, which you need to control
your scoreText and highScoreText UI elements.
using [Link];
What it does: Imports the library that lets you manage game scenes,
specifically to use [Link]().
public class Snake : MonoBehaviour
What it does: Declares your new script component, Snake, which can be
attached to a GameObject (your snake head).
{
What it does: Marks the beginning of the Snake class.
private Vector2 _direction = [Link];
What it does: Creates a private variable _direction to store the snake's
current movement direction. It's initialized to [Link] (which is (1, 0)), so
the snake starts by moving to the right.
private List<Transform> _segments;
What it does: Declares a list that will hold the Transform (position, rotation,
scale) of every segment of the snake, including the head. This list is the
snake.
public Transform segmentPrefab;
What it does: Creates a public variable that will show up in the Inspector. You
must drag your snake body prefab from your Project files into this slot. This
is the object that will be "Instantiated" (copied) to make the snake grow.
public TextMeshProUGUI scoreText; public TextMeshProUGUI highScoreText;
What it does: Creates two public variables for your UI text. You will drag the
TextMeshPro objects from your scene Hierarchy into these slots in the
Inspector.
private int score; private int highScore;
What it does: Private variables to keep track of the current score during the
game and the highest score loaded from memory.
public static int finalScore;
What it does: This is the key variable for your game over screen.
public: Makes it accessible from other scripts.
static: This is the important part. A static variable belongs to the class itself,
not a specific instance. This means its value persists even after this Snake
object is destroyed and the scene changes. Your GameOverDisplay script will
read this value.
private const string HighScoreKey = "SnakeHighScore";
What it does: Creates a const (constant) string. This is a "key" used for
PlayerPrefs. Using a const variable prevents you from making a typo when
saving or loading the high score.
private void Start()
What it does: This function runs once, right at the beginning of the game.
{
What it does: Marks the beginning of Start().
_segments = new List<Transform> { [Link] };
What it does: This initializes your _segments list. It creates a new, empty list
and then immediately adds its first item: [Link] (the Transform of the
snake head object this script is attached to). So, the snake starts with a length
of 1 (just the head).
highScore = [Link](HighScoreKey, 0);
What it does: PlayerPrefs is Unity's system for saving simple data. This line
tries to load an integer value using your HighScoreKey. If it doesn't find any
saved data (like the first time you play), it will use the default value 0.
UpdateHighScoreText();
What it does: Calls your custom function (defined below) to make the
highScoreText UI element display the value you just loaded.
ResetState();
What it does: Calls your ResetState function to position the snake at the start
and set the score to 0.
}
What it does: Marks the end of Start().
private void Update()
What it does: This function runs every single frame. It's the best place to
check for quick, one-time inputs like a key press.
{ if ([Link](KeyCode.W))
What it does: [Link] is true for the single frame the 'W' key is
pressed down.
Note: Your code allows the snake to move directly backward into itself (e.g.,
moving right, then pressing 'A'). A common fix is to add && _direction !=
[Link] to this if statement.
{ _direction = [Link]; }
What it does: If 'W' is pressed, it sets the _direction variable to (0, 1). It
doesn't move the snake yet; it just saves the direction for FixedUpdate to
use.
else if ([Link](KeyCode.S)) ... (and A, and D) ...
What it does: The else if chain does the same check for S, A, and D, setting
the _direction to [Link], [Link], or [Link] respectively.
}
What it does: Marks the end of Update().
private void FixedUpdate()
What it does: This function runs at a fixed, consistent time interval (e.g., 50
times per second), independent of your frame rate. This is essential for grid-
based movement and physics to prevent jerky motion.
{ for (int i = _segments.Count - 1; i > 0; i--)
What it does: This is the core "follow the leader" logic. It's a for loop that
starts at the very tail of the snake (_segments.Count - 1) and counts
backward until it gets to the segment just behind the head (index 1). It does
not move the head (index 0).
{ _segments[i].position = _segments[i - 1].position; }
What it does: Inside the loop, it sets the position of the current segment (i) to
the position of the segment in front of it (i - 1).
Example: The tail (i=3) moves to where the 3rd segment (i=2) was. Then the
3rd segment (i=2) moves to where the neck (i=1) was.
[Link] = new Vector3(...)
What it does: After all the body parts have moved, this line moves the head
(which is [Link], or _segments[0]).
[Link]([Link].x) + _direction.x,
[Link]([Link].y) + _direction.y,
What it does: It gets the head's current, rounded position and adds the
_direction vector. [Link] is crucial for a grid game—it snaps the position
to the nearest whole number (e.g., 4.9 becomes 5) before moving, ensuring it
always lands perfectly on a grid square.
}
What it does: Marks the end of FixedUpdate().
private void Grow()
What it does: This custom function is called when the snake eats food.
{ Transform segment = Instantiate([Link]);
What it does: Instantiate creates a new clone of your segmentPrefab and
stores its Transform in a new variable called segment.
[Link] = _segments[_segments.Count - 1].position;
What it does: It sets the new segment's position to be exactly where the
current tail is.
_segments.Add(segment);
What it does: It adds the new segment to the end of the _segments list,
making it the new tail. On the next FixedUpdate, the old tail will move forward,
and this new segment will be visible in its place.
}
What it does: Marks the end of Grow().
private void UpdateScoreText() private void UpdateHighScoreText()
What it does: These are simple helper functions to keep your code clean.
They find the .text property of your UI elements and update them with the
current score or highScore values.
private void CheckForHighScore()
What it does: This custom function checks if the game that just ended
resulted in a new high score.
{ if (score > highScore) { highScore = score;
What it does: Updates the highScore variable in the script.
[Link](HighScoreKey, highScore);
What it does: Saves the new high score to the device's memory using your
special key.
[Link]();
What it does: Officially commits the saved data to disk.
UpdateHighScoreText();
What it does: Updates the UI text to immediately show the new high score. }
}
private void ResetState()
What it does: This function is called to clean up the snake and reset the
game, either at the very beginning or after dying.
{ CheckForHighScore();
What it does: Before resetting, it checks if the score from the run that just
ended was a new high score.
for (int i = 1; i < _segments.Count; i++)
What it does: Loops through the _segments list, starting from index 1 (the
first body part) and skipping the head (index 0).
{ Destroy(_segments[i].gameObject); }
What it does: Destroys the gameObject of each body segment, cleaning
them from the scene.
_segments.Clear();
What it does: Empties the list.
_segments.Add([Link]);
What it does: Adds the head back into the empty list.
[Link] = [Link];
What it does: Resets the head's position to the center of the world ((0, 0, 0)).
score = 0; UpdateScoreText();
What it does: Resets the score to 0 and updates the UI.
private void OnTriggerEnter2D(Collider2D other)
What it does: A built-in Unity function that runs automatically when this
object's collider (the head) hits another collider that is set to "Is Trigger".
Collider2D other: This variable holds the collider of the object that was hit
(e.g., the food or a wall).
{ if ([Link] == "Food")
What it does: Checks if the object it hit has its Tag set to "Food" in the
Inspector.
{ Grow();
What it does: Calls your Grow() function.
[Link]<Food>().RandomizePosition();
What it doa: This gets the Food script from the food object you hit (other) and
calls that script's public RandomizePosition() function, telling the food to
move.
score++; UpdateScoreText();
What it does: Increases the score by 1 and updates the UI. }
else if ([Link] == "Obstacle")
What it does: Checks if the object it hit has its Tag set to "Obstacle" (e.g., a
wall or one of its own body segments).
{ finalScore = score;
What it does: This is the critical step. It saves the current score into your
static finalScore variable, so the next scene can read it.
ResetState();
What it does: Cleans up the snake (destroys the body parts, etc.).
[Link]("GameOver");
What it does: Loads your "GameOver" scene, ending the game.
MAIN MENU:
using [Link];
What it does: Imports the library for Unity's Visual Scripting system (flow
graphs).
Note: Based on the code you've written, this line is not actually being used
and could be safely removed.
using [Link];
What it does: Imports internal editor functions related to building the game.
Note: This line is also not being used by your script and could be removed.
using UnityEngine;
What it does: This is the standard, essential Unity library. It gives you access
to core components like MonoBehaviour and Application.
using [Link];
What it does: This is a very important import. It gives you access to the
SceneManager, which is the component that allows you to load different
scenes.
public class MainMenuController : MonoBehaviour
public class MainMenuController: Declares your new script component,
naming it MainMenuController.
: MonoBehaviour: This tells Unity that this script can be attached to a
GameObject.
{
What it does: This curly brace marks the beginning of your
MainMenuController class.
public void OnStartClick()
public void: This declares a function that can be "seen" from outside this
script, specifically by the Unity Inspector. void means the function doesn't
return any value; it just performs an action.
How you use it: You will link your "Start" button's OnClick() event in the
Inspector to this specific function.
{
What it does: Marks the beginning of the OnStartClick function.
[Link]("Snake");
What it does: This is the command that loads your game. It tells the
SceneManager to find and load the scene with the exact name "Snake".
Important: For this to work in a built game, you must add your "Snake"
scene to the Build Settings (File > Build Settings...).
}
What it does: Marks the end of the OnStartClick function.
public void OnExitClick()
What it does: A public function you will link to your "Exit" or "Quit" button.
{ #if UNITY_EDITOR
What it does: This is a preprocessor directive. It's a special instruction that
checks if you are currently running the game inside the Unity Editor.
[Link] = false;
What it does: If you are in the editor, this is the correct command to stop
"Play Mode." The [Link]() command below it does not work in the
editor.
#endif
What it does: This marks the end of the special "editor-only" code block.
[Link]();
What it does: This is the command that tells a real, built game (like a .exe
on Windows) to close. This line will be ignored when you are playing inside
the Unity Editor, which is why the code block above it is necessary for testing.
}
What it does: Marks the end of the OnExitClick function.
public void OnRulesClick()
What it does: A public function you will link to your "Rules" button.
{ [Link]("Rules Screen");
What it does: Tells the SceneManager to load the scene named "Rules
Screen". (This scene must also be in your Build Settings).
public void OnPlayGameClick()
What itG does: Another public function, likely for a "Play" button (perhaps on
your Rules screen).
{ [Link]("Snake");
What it does: Loads the "Snake" game scene.
public void OnPlayAgainClick()
What it does: Another public function, most likely for a "Play Again" button on
your "Game Over" screen.
{ [Link]("Snake");
What it does: Loads the "Snake" game scene, effectively restarting the
game.
}
What it does: This final brace marks the end of your MainMenuController
class.