In this lesson we’re going to cover the _update_next_position()
and _update_down_counter()
functions found in _generate_level()
.
The _update_next_position()
function is where we advance the random walker one step, either horizontally or downwards. We use multiple checks to see if the walker can move in a direction and, if not, choose a better direction.
The following function moves the algorithm one cell forward based on the previous delta
and the _horizontal_chance
. We do this by choosing a random direction from our STEP
array. We store this random direction in _state.delta
.
func _update_next_position() -> void: _state.random_index = ( _rng.randi_range(0, STEP.size() - 1) if _state.random_index < 0 else _state.random_index ) _state.delta = STEP[_state.random_index] var horizontal_chance := _rng.randf() if _state.delta.is_equal_approx(Vector2.LEFT): _state.random_index = 0 if _state.offset.x > 1 and horizontal_chance < _horizontal_chance else 4 elif _state.delta.is_equal_approx(Vector2.RIGHT): _state.random_index = 2 if _state.offset.x < grid_size.x - 1 and horizontal_chance < _horizontal_chance else 4 else: if _state.offset.x > 0 and _state.offset.x < grid_size.x - 1: _state.random_index = _rng.randi_range(0, 4) elif _state.offset.x == 0: _state.random_index = 2 if horizontal_chance < _horizontal_chance else 4 elif _state.offset.x == grid_size.x - 1: _state.random_index = 0 if horizontal_chance < _horizontal_chance else 4 _state.delta = STEP[_state.random_index] _state.offset += _state.delta
There’s a lot to cover here so lets go through it one step at a time.
To pick our move direction from STEP
, we generate a random index between 0
and STEP.size() - 1
and assign it to _state.random_index
.
We need to avoid ending up on a previously visited cell. To make sure this doesn’t happen, we reuse the previous _state.random_index
and use _rng
only at the first step of the algorithm when _state.random_index < 0
is true. Recall we initialized _state.random_index = 1
in the _reset()
function.
_state.random_index = ( _rng.randi_range(0, STEP.size() - 1) if _state.random_index < 0 else _state.random_index )
Once we’ve picked this _state.random_index
, we get the direction we should move from STEP
and save it in _state.delta
.
_state.delta = STEP[_state.random_index]
The next code block tests for special cases that could break our generated path. Depending on the direction the walker moves in, we might need to force it to move in a specific way.
var horizontal_chance := _rng.randf() if _state.delta.is_equal_approx(Vector2.LEFT): _state.random_index = 0 if _state.offset.x > 1 and horizontal_chance < _horizontal_chance else 4 elif _state.delta.is_equal_approx(Vector2.RIGHT): _state.random_index = 2 if _state.offset.x < grid_size.x - 1 and horizontal_chance < _horizontal_chance else 4 else: if _state.offset.x > 0 and _state.offset.x < grid_size.x - 1: _state.random_index = _rng.randi_range(0, 4) elif _state.offset.x == 0: _state.random_index = 2 if horizontal_chance < _horizontal_chance else 4 elif _state.offset.x == grid_size.x - 1: _state.random_index = 0 if horizontal_chance < _horizontal_chance else 4
Let’s break it down further.
We prepare ourselves to select either Vector2.LEFT
or Vector2.DOWN
from STEP
. This is randomized based on the _horizontal_chance
value.
However, if _state.offset.x > 1
, we’ve reached the boundary of our grid_size
so we move down by setting _state.random_index = 4
.
var horizontal_chance := _rng.randf() if _state.delta.is_equal_approx(Vector2.LEFT): _state.random_index = 0 if _state.offset.x > 1 and horizontal_chance < _horizontal_chance else 4
We then do the same as before but this time we select from Vector2.RIGHT
or Vector2.DOWN
. Again, if the walker tries to go past the right boundary, we move down.
elif _state.delta.is_equal_approx(Vector2.RIGHT): _state.random_index = 2 if _state.offset.x < grid_size.x - 1 and horizontal_chance < _horizontal_chance else 4
If neither of the above branches are valid, then we’re on the branch where _state.delta.is_equal_approx(Vector2.DOWN)
is true.
In this case, we check we’re not at the left or right edges of the grid. If we’re not, we update _state.random_index
to a random value because any position is valid from here. Remember that we just moved down.
else: if _state.offset.x > 0 and _state.offset.x < grid_size.x - 1: _state.random_index = _rng.randi_range(0, 4)
If _state.offset.x == 0
, we’ve hit the left boundary of the grid so we set _state.random_index
to either Vector2.RIGHT
or Vector2.DOWN
randomly depending on _horizontal_chance
.
elif _state.offset.x == 0: _state.random_index = 2 if horizontal_chance < _horizontal_chance else 4
If _state.offset.x == grid_size.x - 1
, we’re at the right boundary of the grid so we pick either Vector2.LEFT
or Vector2.DOWN
depending on _horizontal_chance
.
elif _state.offset.x == grid_size.x - 1: _state.random_index = 0 if horizontal_chance < _horizontal_chance else 4
At this point we finally assign the updated direction to _state.delta
and calculate the final position in _state.offset
using this direction.
_state.delta = STEP[_state.random_index] _state.offset += _state.delta
We update _state.down_counter
in the _update_down_counter()
function by checking _state.delta
and, if we’re moving down, we increase the value by 1
. Otherwise we reset the counter to 0
.
func _update_down_counter() -> void: _state.down_counter = ( _state.down_counter + 1 if _state.delta.is_equal_approx(Vector2.DOWN) else 0 )
We covered how _state.down_counter
is used in _update_room_type()
to rectify any problems we might have when moving down in the previous lesson.