First Attempt at procedural generation HELP misaligned grid

Godot Version

4.3

Question

Im attempting to build out a city through procedural generation. I’ve never done anything like it, so it’s a new challenge. The idea is that a street acts as the backbone and procedurally generates structures on the left and right of it. Eventually, I’d like to have other streets come off of that street and continue to generate more of the city but I thought I would start small and do one street. Im also only generating parks for now too. The issue is I want to have structures of different size tiles. My base tile of a street is 9x9 pixels and some of the parks tiles are 9x9 as well but some are 18x18 and I’ve got a large one that is 45x18 (all multiples of 9x9) but the larger tiles are coming in slightly off and I can’t tell why

Here is the code here, any idea on what Im doing wrong? Maybe this is the wrong way to think about procedural generation too so Im open to that advice

I forgot to add a reference to the code sorry

I don’t know the cause, but I can point out a few issues:

(1)

func is_overlapping(position: Vector2, size: Vector2, occupied_cells) -> bool:
	for x in range(size.x):  # Use grid size, NOT pixels
		for y in range(size.y):
			if occupied_cells.has(position):
				return true
	return false

In this loop, you’re just checking whether occupied_cells has position over and over. I imagine you actually want to check something like has(position + Vector2(x, y)).

Also, you should not use a variable named “position”, because that variable already has a meaning for 2d nodes (there should be a compiler warning about “shadowing” the position variable)

(Same shadowing issue in the method “place_tile”)

(2) I don’t think set_cell is intended for use with differently sized cells. It seems to be doing something here, so I’m not sure if the behavior is intended or not.

(3) There are some variables that can be easily removed to make your code more readable (and bugs easier to find), for example

func generate_straight_street() -> void:
	#print("Generating street...")  
	var start_y = 0
	var x = 0

	for i in range(STREET_LENGTH):
		var y = start_y + i
		streets_layer.set_cell(Vector2(x, y), street_source_id, straight_tile_coords)

	#print("Street generation complete.")

can be rewritten as

func generate_straight_street() -> void:
	for y in range(STREET_LENGTH):
		streets_layer.set_cell(Vector2(0, y), street_source_id, straight_tile_coords)

Similar lines: “let y = i” in generate_side_structure, any commented print(…) statements

(4) I don’t have time right now to properly debug this, but I’ll recommend as a general exercise to add a breakpoint to some method that isn’t doing what you want and checking out what all the variables look like at each invocation. For example:

func is_overlapping(_position: Vector2, size: Vector2, occupied_cells) -> bool:
	breakpoint
	for x in range(size.x):
		for y in range(size.y):
			if occupied_cells.has(_position + Vector2(x, y)):
				return true
	return false

Code execution will pause every time you reach the breakpoint, and you will be able to look at each of the current stack variables, e.g. _position, size, and occupied_cells (as well as any vars in the surrounding context). This might help you figure out the issue.

1 Like

I wouldn’t be surprised if the problem was the tile position vs. the tile center. That is, each of those tiles has a “position” that’s a point in space, with the rest of the tile laid out relative to that position. If you thought that position was the center of the tile, but it was instead the top left corner, the double size tiles would be out of position by a quarter of their size.

The same is true in the other direction.

1 Like

Thank you! Ill try that out. Im still learning godot and have been ignoring the warnings (I know how bad that sounds) but I do see what your talking about and that helps me think through this a lot. Ive started reading other ways to do procedural generation and am trying to play around with those as well to help understand the math better too. Thank you again for your help.

If everything you’re working with is some multiple of a fixed size, you might consider using TileMapLayer.

There are some limits to what it can do that might not mesh with what you need, but if it handles everything you care about you might find it makes a bunch of hassle go away.

1 Like