Kevin Young

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.

#godot4 #devlog

Reply to this post by email ↪