I'm trying to make a game that makes procedurally generated puzzle areas/levels. Specifically, these are areas/levels where a player moves their character from one block to another and they can't stop until they hit something (sort of like in the mobile game Quell). Over the past week, I have been trying to generate such a level. What I do is randomly place a block at some position, and then have a path generated from that starting block. When the level is finished generating, the player would begin the level at the end of that path, and work their way to the "end".
I have written some code that sort of builds a path. It has a starting position, and then chooses a direction (north, south, east, or west). The path is then moved in that direction at a random length. The next direction is based upon the previous direction: if the last direction was north or south, the path would be moved to the east or west; if the last direction was east or west, the next direction would be north or south. I am having problems with moving the blocks far enough apart from each other so that the player can move between them. There's that, and the position of the blocks always seems to be off. I am trying to lay the blocks in a grid pattern. However, I can't get them laid properly.
Here's my code, if anyone's wondering:
extends Node2D
var block: PackedScene = preload( "res://Blue_block.tscn" )
var player: PackedScene = preload( "res://Player.tscn" )
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
const BLOCK_SIZE: int = 64
enum directions { NORTH, SOUTH, EAST, WEST }
func _ready():
create_other_puzzle()
func create_other_puzzle() -> void:
var viewport_size: Vector2 = get_viewport().get_size()
var max_width: int = int( viewport_size.x / BLOCK_SIZE )
var max_height: int = int( viewport_size.y / BLOCK_SIZE )
rng.randomize()
Helpers.set_rng( rng )
var random_width: int = rng.randi_range( 1, max_width )
var random_height: int = rng.randi_range( 1, max_height )
var place_for_starter_block_in_area: Vector2 = Vector2( random_width, random_height )
var player_instance: KinematicBody2D = player.instance()
player_instance.position = Vector2( random_width * (BLOCK_SIZE / 2), random_height * (BLOCK_SIZE / 2) )
call_deferred( "add_child", player_instance )
var previous_place_for_block: Vector2 = place_for_starter_block_in_area
var start_direction: int = Helpers.random_choice( directions.values() )
var previous_direction: int = start_direction
for _i in range( 0, 4 ):
if previous_direction == directions.NORTH or previous_direction == directions.SOUTH:
var results: String = Helpers.flip_a_coin( "east", "west" )
if results == "east":
previous_direction = directions.EAST
var max_distance: int = max_width - previous_place_for_block.x
var units_to_move: int = rng.randi_range( 1, max_distance )
if units_to_move == max_distance: units_to_move -= 1
var direction: Vector2 = previous_place_for_block + ( Vector2.RIGHT * units_to_move )
var mr_block: Sprite = block.instance()
mr_block.position = direction * (BLOCK_SIZE)
call_deferred( "add_child", mr_block )
previous_place_for_block += ( Vector2.RIGHT * ( units_to_move + 1 ) )
else:
previous_direction = directions.WEST
var units_to_move: int = rng.randi_range( 1, previous_place_for_block.x )
if units_to_move == 1: units_to_move += 1
var direction: Vector2 = previous_place_for_block + ( Vector2.LEFT * units_to_move )
var mr_block: Sprite = block.instance()
mr_block.position = direction * BLOCK_SIZE
call_deferred( "add_child", mr_block )
previous_place_for_block += ( Vector2.LEFT * ( units_to_move + 1 ) )
else:
var results: String = Helpers.flip_a_coin( "north", "south" )
if results == "north":
previous_direction = directions.NORTH
var units_to_move: int = rng.randi_range( 1, previous_place_for_block.y )
if units_to_move == 1: units_to_move += 1
var direction: Vector2 = previous_place_for_block + ( Vector2.UP * units_to_move )
var mr_block: Sprite = block.instance()
mr_block.position = direction * BLOCK_SIZE
call_deferred( "add_child", mr_block )
previous_place_for_block += ( Vector2.UP * ( units_to_move - 1 ) )
else:
previous_direction = directions.SOUTH
var max_distance: int = max_height - previous_place_for_block.y
var units_to_move: int = rng.randi_range( 1, max_distance )
if units_to_move == max_distance: units_to_move -= 1
var direction: Vector2 = previous_place_for_block + ( Vector2.DOWN * units_to_move )
var mr_block: Sprite = block.instance()
mr_block.position = direction * BLOCK_SIZE
call_deferred( "add_child", mr_block )
previous_place_for_block += ( Vector2.DOWN * ( units_to_move + 1 ) )
Here's an example of when it's generated:
