A new space for snake
Oh yeah. We’re rollin now. Bug fixes and new state trigger logic!
Diagonal movement bug
Had to change the movement vector code to fix a bug that would allow the player to move in diagonals… which kind of breaks the whole rule set of Snake now doesn’t it. This is because the Input.get_vector()
func will create a vector based on all inputs it recieves. Good for some games like top down 2d or 3d games, not good for snake.
1# Snake.gd
2
3...
4func _process(_delta):
5 if Input.get_vector("left", "right", "up", "down") != Vector2.ZERO:
6 if manager.current_state == GlobalVars.State.PAUSE :
7 manager.set_state(GlobalVars.State.PLAY)
8 if Input.is_action_just_pressed("left"):
9 input_buffer = Vector2(-1, 0)
10 elif Input.is_action_just_pressed("right"):
11 input_buffer = Vector2(1, 0)
12 elif Input.is_action_just_pressed("up"):
13 input_buffer = Vector2(0, -1)
14 elif Input.is_action_just_pressed("down"):
15 input_buffer = Vector2(0, 1)
16...
So I unfortunately had to break up my nice neatly coded movement code into a sequence of if statements, while still keeping the get_vector
for detecting an input to start the game. I’m sure theres a hip way to consolidate this but for now this’ll do.
Dead snake
To detect if the snake’s head has made contact with the snake’s tail, I just added a CollisionArea2d
to the SnakeTail.tscn
, and add the following code to connect the body_entered
signal.
1# SnakeTail.gd
2extends StaticBody2D
3
4@onready var col_area = $CollisionArea
5@onready var manager = get_parent()
6
7func _ready():
8 col_area.body_entered.connect(_on_area_2d_body_entered)
9
10func _on_area_2d_body_entered(body):
11 if body.is_in_group("SnakeHead"):
12 manager.set_state(GlobalVars.State.DEAD)
I added the SnakeHead node to a group “SnakeHead” as a lazy check, I’ll admit. This may change later if I find it stupid but it works well enough for now.
Play area changes
As you can see from the header image, its pretty minimal. I added a new TileMap
layer for the “frame”, so the playarea does not end up being massive and take forever to traverse, and I can also decorate it later if I want / when I choose a final visual style. Overall a simple but pleasing enhancement from the janky floating window with dimensions that were slightly off from the TileMap
:D
Detecting wall collision
Ideally, in Godot 4 I could simply add a physics collision layer to the TileMap
. However, because I’ve chosen not to use any physics based movement, I don’t think this is possible.
The good news is, since I’m already storing the coordinates for all the cells that make up the playarea, all I need to do is check to see if the cell that the snake’s head is about to move into is going to have an x or y value greater or less than the maximum x or y values used for the playarea.
1# GameManager.gd
2
3...
4func _ready():
5 bg_layer_coords = grid.get_used_cells(1)
6 min_nav_x_y = bg_layer_coords[0]
7 max_nav_x_y = bg_layer_coords[bg_layer_coords.size() - 1]
8
9...
10
11func is_in_boundaries(grid_coord):
12 if (min_nav_x_y.x < grid_coord.x) and (max_nav_x_y.x > grid_coord.x):
13 if (min_nav_x_y.y < grid_coord.y) and (max_nav_x_y.y > grid_coord.y):
14 return true
15 return false
16...
This function gets called in the _timer_timeout()
func.
1# GameManager.gd
2
3...
4func _timer_timeout():
5...
6 if snake.grid_coords.size() > snake.body_segments.size() :
7 update_snake()
8 for s in range(snake.grid_coords.size()):
9 if s == 0:
10 if !is_in_boundaries(snake.grid_coords[s]):
11 set_state(GlobalVars.State.DEAD)
12...
So close I can almost smell the polishing phase.