patterncsharpMinor
Snake game in Unity
Viewed 0 times
gameunitysnake
Problem
I've made a simple snake game in Unity and it has 3 different types of foods.
Note - 5 blocks = 1 point
This is a screenshot from the game here I'm colliding with myself and the game is restarted after that. As you can see the snake has a highlighted head (the light green block) and it consists of quite a lot smaller blocks and there are those outlines on the body of the snake they are created on each 10 blocks you get;
The snake is controlled by the
```
public class SnakeHead : MonoBehaviour
{
public bool IsMoving { get; set; }
private const float Speed = .2f;
public ObjectPooler snakePartsObjectPooler;
public Text ScoreText;
private Vector3 moveSize;
private Vector3 moveDirection;
private float invulnerabilityTime;
private readonly List snake = new List();
private void Start()
{
moveSize = GetComponent().bounds.size;
snake.Add(gameObject);
StartCoroutine(Move());
}
private void Update()
{
if (Input.anyKeyDown)
{
SetDirection(Vector3.left, Vector3.right, KeyCode.LeftArrow, KeyCode.A);
SetDirection(Vector3.right, Vector3.left, KeyCode.RightArrow, KeyCode.D);
SetDirection(Vector3.up, Vector3.down, KeyCode.UpArrow, KeyCode.W);
SetDirection(Vector3.down, Vector3.up, KeyCode.DownArrow, KeyCode.S);
}
}
private void SetDirection(Vector3 direction, Vector3 oppositeDirection, params KeyCode[] triggers)
{
if (triggers.Any(Input.GetKeyDown))
{
if (snake.Count == 1 || moveDirection != oppositeDirection)
{
moveDirection = direction;
IsMoving = true;
}
}
}
private IEnumerator Move()
{
do
{
for (int i = snake.Count - 1; i > 0; i--)
{
snake[i].transform.position = snake[i - 1].transform.position;
}
transform.posi
Note - 5 blocks = 1 point
This is a screenshot from the game here I'm colliding with myself and the game is restarted after that. As you can see the snake has a highlighted head (the light green block) and it consists of quite a lot smaller blocks and there are those outlines on the body of the snake they are created on each 10 blocks you get;
The snake is controlled by the
SnakeHead script```
public class SnakeHead : MonoBehaviour
{
public bool IsMoving { get; set; }
private const float Speed = .2f;
public ObjectPooler snakePartsObjectPooler;
public Text ScoreText;
private Vector3 moveSize;
private Vector3 moveDirection;
private float invulnerabilityTime;
private readonly List snake = new List();
private void Start()
{
moveSize = GetComponent().bounds.size;
snake.Add(gameObject);
StartCoroutine(Move());
}
private void Update()
{
if (Input.anyKeyDown)
{
SetDirection(Vector3.left, Vector3.right, KeyCode.LeftArrow, KeyCode.A);
SetDirection(Vector3.right, Vector3.left, KeyCode.RightArrow, KeyCode.D);
SetDirection(Vector3.up, Vector3.down, KeyCode.UpArrow, KeyCode.W);
SetDirection(Vector3.down, Vector3.up, KeyCode.DownArrow, KeyCode.S);
}
}
private void SetDirection(Vector3 direction, Vector3 oppositeDirection, params KeyCode[] triggers)
{
if (triggers.Any(Input.GetKeyDown))
{
if (snake.Count == 1 || moveDirection != oppositeDirection)
{
moveDirection = direction;
IsMoving = true;
}
}
}
private IEnumerator Move()
{
do
{
for (int i = snake.Count - 1; i > 0; i--)
{
snake[i].transform.position = snake[i - 1].transform.position;
}
transform.posi
Solution
private void Update()
{
if (Input.anyKeyDown)
{
SetDirection(Vector3.left, Vector3.right, KeyCode.LeftArrow, KeyCode.A);
SetDirection(Vector3.right, Vector3.left, KeyCode.RightArrow, KeyCode.D);
SetDirection(Vector3.up, Vector3.down, KeyCode.UpArrow, KeyCode.W);
SetDirection(Vector3.down, Vector3.up, KeyCode.DownArrow, KeyCode.S);
}
}
private void SetDirection(Vector3 direction, Vector3 oppositeDirection, params KeyCode[] triggers)
{
if (triggers.Any(Input.GetKeyDown))
{
if (snake.Count == 1 || moveDirection != oppositeDirection)
{
moveDirection = direction;
IsMoving = true;
}
}
}Not sure if I'm missing something, but I don't see the point of calling
SetDirection and iterating through an array four times to set the direction - you only expect one of these directions to be set, right?Also it might be more efficient to do this check
if (snake.Count == 1 || moveDirection != oppositeDirection) before if (triggers.Any(Input.GetKeyDown)) - technically they could all be in the same if statement, but better to shortcut with a couple of simple comparisons before going through an iterator. (Unless Vector3 has overloaded the operators to do some complex logic...)Overall I think it would be more efficient to create a dictionary with the various keys of interest, look up
Input.GetKeyDown (it returns a KeyCode, right?) in the dictionary, and if found use the corresponding value. Although since you only want to move in the direction if it's not the "opposite" direction, you could either have another dictionary for storing opposites or create a class, e.g. class Direction
{
public Vector3 Desired { get; }
public Vector3 Opposite { get; }
}Then setup a dictionary, e.g.
private readonly Dictionary keycodeToDirection = new Dictionary()
{
{ KeyCode.LeftArrow, new Direction() { Desired = Vector3.left, Opposite = Vector3.right } },
{ KeyCode.A, new Direction() { Desired = Vector3.left, Opposite = Vector3.right } }
// all the rest
// edit: Just realised this wouldn't compile due to not being able to set the property values here, but that's not the point of the example... you get the idea.
};Then:
private void Update()
{
if (Input.anyKeyDown)
{
var direction = GetDirectionForKeyCode(Input.GetKeyDown);
if (direction != null)
SetDirection(direction);
}
}
private Direction GetDirectionForKeyCode(KeyCode keyCode)
{
Direction d;
if (keycodeToDirection.TryGetValue(keyCode, out d)
{
if (snake.Count == 1 || moveDirection != d.Opposite)
return d;
}
return null;
}
private void SetDirection(Direction direction)
{
moveDirection = direction.Desired;
IsMoving = true;
}private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Wall")
{
Loss();
}
if (other.tag == "SnakePart" && invulnerabilityTime <= Time.time)
{
Loss();
}
}Could be written with a single
if statement:private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Wall" || (other.tag == "SnakePart" && invulnerabilityTime <= Time.time))
{
Loss();
}
}Code Snippets
private void Update()
{
if (Input.anyKeyDown)
{
SetDirection(Vector3.left, Vector3.right, KeyCode.LeftArrow, KeyCode.A);
SetDirection(Vector3.right, Vector3.left, KeyCode.RightArrow, KeyCode.D);
SetDirection(Vector3.up, Vector3.down, KeyCode.UpArrow, KeyCode.W);
SetDirection(Vector3.down, Vector3.up, KeyCode.DownArrow, KeyCode.S);
}
}
private void SetDirection(Vector3 direction, Vector3 oppositeDirection, params KeyCode[] triggers)
{
if (triggers.Any(Input.GetKeyDown))
{
if (snake.Count == 1 || moveDirection != oppositeDirection)
{
moveDirection = direction;
IsMoving = true;
}
}
}class Direction
{
public Vector3 Desired { get; }
public Vector3 Opposite { get; }
}private readonly Dictionary<KeyCode, Direction> keycodeToDirection = new Dictionary<KeyCode, Direction>()
{
{ KeyCode.LeftArrow, new Direction() { Desired = Vector3.left, Opposite = Vector3.right } },
{ KeyCode.A, new Direction() { Desired = Vector3.left, Opposite = Vector3.right } }
// all the rest
// edit: Just realised this wouldn't compile due to not being able to set the property values here, but that's not the point of the example... you get the idea.
};private void Update()
{
if (Input.anyKeyDown)
{
var direction = GetDirectionForKeyCode(Input.GetKeyDown);
if (direction != null)
SetDirection(direction);
}
}
private Direction GetDirectionForKeyCode(KeyCode keyCode)
{
Direction d;
if (keycodeToDirection.TryGetValue(keyCode, out d)
{
if (snake.Count == 1 || moveDirection != d.Opposite)
return d;
}
return null;
}
private void SetDirection(Direction direction)
{
moveDirection = direction.Desired;
IsMoving = true;
}private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Wall")
{
Loss();
}
if (other.tag == "SnakePart" && invulnerabilityTime <= Time.time)
{
Loss();
}
}Context
StackExchange Code Review Q#150862, answer score: 4
Revisions (0)
No revisions yet.