Firestarter (WIP and a couple questions...)

Sorry for the delay. I’ve been a tad busy and I put off answering your questions partly because you seemed to be mostly working out the answers on your own and partly because the questions are slightly more complex than the other ones that were on my todo list.


If you put them in a different array then you might not be able to use the toTileIndex and fromTileIndex functions, depending on how you’re handling roads.

If you’re planning to have the road shapes determined at rendering time rather than being stored in the map itself and have only one type of road tile then you don’t even need fromTileIndex because you’ll always be using the same value. You can just do tileMap[y][x] = TileType::road;.

(For the record, you should call your road tile either roadTile or just road. You shouldn’t give it a plural name because it’s a singular value - as far as the tile system is concerned there would be only a single tile value that represents ‘road’, and the fact it’s a tile type should be obvious by the fact you have to prefix it with TileType::.)

An alternative way would be to have multiple tile types representing different kinds of roads. This would make generating slightly more complicated and burn through more of your available tile values, but would make rendering a lot simpler and frankly you have 256 tile values and only a handful of road and building types so that wouldn’t really be an issue. (Though if you can limit yourself to only 16 tile types then you could start packing two tiles per byte, but I’m not sure you’d necessarily need a particularly large map.)

Thinking about it, it might be wiser to try to make the rendering cheaper at expense of the map generation because the isometric rendering already seems expensive.

Anyway…

You need to actually assign those for loop variables a value, otherwise they’ll end up with junk values, which is bad.

You don’t need to put the ++x in the index. You’re basically indexing the tileMap and then discarding the unused result (i.e. you are neither using the value read, nor assigning to it).

I’ve no clue what the comment about ‘increment half sprite width’ is supposed to mean.

I think you were aiming for something like this:

void generateRoad()
{
	constexpr uint8_t horizontalRoadMax = 5;
	constexpr uint8_t verticalRoadMax = 5;

	uint8_t roadLength = random(5, 10);

	// If i is less than horizontal road count
	for (uint8_t i = 0; i < horizontalRoadMax; ++i)
	{
		// Get random x and y
		uint8_t y = random(0, mapHeight);
		uint8_t x = random(0, mapWidth);

		// For road length, increment or decrement horizontal position and set tile to road    
		for(uint8_t j = 0; j < roadLength; ++j)
		{
			// Set tile type at that location to road
			tileMap[y][x] = TileType::road;

			// Incremement x
			++x;

			// If x exceeds the width of the map,
			if(x >= mapWidth)
				// stop generating,
				// otherwise you'll go outside the map
				break;
		}
	}
}

Which would generate a few horizontal roads, but likely not enough to fill the map.
You’d need to run this several times to generate enough roads.
(Also the vertical maximum is unused.)

Picking a position at random might not be a good idea because it won’t guarantee that you end up with fully connected roads. I.e. you might have some road ‘islands’, even after doing the same for vertical roads.

You’ll also probably end up with your roads clustered more towards the positive end of the map because you’re building them from the selected position towards the positive end, though that might not be a deal breaker.

If you have an idea of roughly what you want your roads to look like, I might be able to suggest some code that could give you the right effect.

To be honest though, I still think you should try setting all the tiles to ‘road’ and then filling in randomly selected rectangles with buildings. I think the end result would look better, and you’re less likely to get road ‘islands’. Having ‘islands’ of buildings isn’t a problem, that’s the sort of effect you’re aiming for anyway, right?

If you want to give that a go, something like this might work:

TileType generateRandomBuildingTile()
{
	constexpr uint8_t buildingMin = toTileIndex(TileType::building0);
	constexpr uint8_t buildingMax = toTileIndex(TileType::building3);
	return fromTileIndex(random(buildingMin, buildingMax));
}

void generateBuildingBlock()
{
	// Get random x and y
	uint8_t yStart = random(0, mapHeight);
	uint8_t xStart = random(0, mapWidth);
	
	// Get random dimensions
	uint8_t width = random(2, 8);
	uint8_t height = random(2, 8);

	for(uint8_t yOffset = 0; yOffset < height; ++yOffset)
	{
		uint8_t y = (yStart + yOffset);
	
		// Skip y values that are outside the map
		if(y >= mapHeight)
			continue;

		for(uint8_t xOffset = 0; xOffset < width; ++xOffset)
		{
			uint8_t x = (xStart + xOffset);
	
			// Skip x values that are outside the map
			if(x >= mapHeight)
				continue;		
		
			// Place a random building
			tileMap[y][x] = generateRandomBuildingTile();
		}
	}
}

void generateBuildingBlocks(uint8_t count)
{
	for(uint8_t amount = 0; amount < count; ++amount)
		generateBuildingBlock();
}

Then you’d just call e.g. generateBuildingBlocks(50); to generate 50 building blocks. (Assuming you’d already filled tileMap with TileType::road.

This will still suffer from the fact you’re only building in a single direction, so you’re likely to get more buildings around the higher end of the map, and you’ll likely run into some overlap and possibly have wider streets, but for now it seems like a start.

If it’s not working, try having a go at generating a city manually on paper and try to work out some rules that produce something decent. E.g. perhaps drawing lines from particular positions produce better results. Maybe try to work out why/how you end up picking particular areas to build roads from.


Just to mention it, if you were taking the approach where you were using tile values to represent different road pieces (e.g. four-ways, bends, et cetera) then either in this part or the equivalent vertical road generating (or both) you’d have some code that examined the surrounding von neumann neighbourhood and select the appropriate tile piece based on where the roads are, possibly modifying pre-exiting roads to change their shape as necessary.


Regardless of which approach you use, there’s a clever trick you can do to determine the road piece.

If you say that 0 means ‘no neighbouring road’ and 1 means ‘has a neighbouring road’, and realise that there are 4 directions that a road can connect via (-Y, -X, +Y, +X - or North, South, East and West, however you wish to label them) then suddenly you see that you have 4 bits work of information determining which piece of road is needed, and 4 bits can hold 16 values, therefore you have 16 different types of road. (If you aren’t convinced, draw them all and mark the connected and unconnected sides and you’ll see what I mean.)

The reason that’s a clever trick is because you can do this:

uint8_t determineRoadType(uint8_t x, uint8_t y)
{
	uint8_t roadType = 0;

	if(((x + 1) < mapWidth) && isRoad(tileMap[y][x + 1])
		roadType |= (1 << 0);

	if((x > 0) && isRoad(tileMap[y][x - 1])
		roadType |= (1 << 1);

	if(((y + 1) < mapHeight) && isRoad(tileMap[y + 1][x])
		roadType |= (1 << 2);

	if((y > 0) && isRoad(tileMap[y - 1][x])
		roadType |= (1 << 3);
		
	return roadType;
}

Which will then give you a value from 0 to 15 that uniquely identifies a particular road piece based on whether the surrounding tiles are also roads.
(It would be more elegant if you had some mapLastX and mapLastY constants.)

You could use this either for selecting the correct road sprite, or for selecting the correct tile type when first generating the map (using fromTileIndex and a bit of calculating).

No worries, thats why i try to edit my posts if i am still able to work out some of the simpler stuff on my own, just saves you the time having to correct/explain more whenever you can get around to it lol.

quote=“Pharap, post:163, topic:10261”]
Sorry for the delay. I’ve been a tad busy and I put off answering your questions partly because you seemed to be mostly working out the answers on your own and partly because the questions are slightly more complex than the other ones that were on my todo list
[/quote]

No worries, thats why i try to edit my posts if i am still able to work out some of the simpler stuff on my own, just saves you the time having to correct/explain more whenever you can get around to it lol.

Ohh, whoops :sweat_smile: I tried to sketch it out a bit in the notepad on my phone (using pseudocode) then left these simple mistakes when I added it in (always doing this when I’m tired lol). And I meant incrementing by half the tile width to set it to the correct x/y position, but I also forgot this is already taken care of elsewhere.

Yeahh, I figured it wouldn’t produce the correct results, was just trying to work it out incrementally and play with whatever looked best once I got it actually functioning correctly (which is why my vertical maximum was unused, wanted to work it out one axis at a time lol).

And you were right, they did generate to the positive end of the map… funny enough it had actually occurred to me when I was sketching it out that I should have it randomly increment either plus or minus (just a hunch) but I wasn’t actually sure how it might affect it and didn’t want to confuse myself with the details so just made it positive for now. I figured this method (just randomly generating horizontal and vertical lines) probably wouldnt produce ideal results, I just chose it because it seemed to be the simplest (and cheapest) back when you mentioned it, but I’ll probably just go with your suggestion and redo the map generation at this point…

That being said, I corrected all of the above mistakes and now the roads will at least display, but only the first sprite… I know all of this:

…is how to fix this issue, but i still haven’t quite worked it out yet. Not sure if its even worth spending the time trying to fix or if I should just start over on my map generation, but my road sprites also cant be seen behind my buildings (something about the size must be incorrect even though I scaled it from the original tile sizes…) so im probably gonna need to spend a bunch of time redrawing all my sprites now too :expressionless: lol. But I updated the repo with all of my most recent changes. Thanks!

When I draft code, I still use a pencil and paper.

Yeah, that’s at the ‘presentation’ (rendering) level, not the ‘conceptual model’ (logical) level. Different levels of abstraction.

I couldn’t be certain, but attempting the same process in my head got that result. The roads never travel towards zero (i.e. point (0,0)).

I was thinking it might be better to have every road travel in both directions because that should theoretically provide an even spread (since all roads would then travel towards both ends of the map).

Choosing a direction at random could work, but I think you’d have to test it to be sure. The awkward thing about working with randomness is that it’s hard to predict. Sometimes what ‘looks’ random to a human actually isn’t random, and sometimes what is random doesn’t ‘look’ random.

I’d offer to have a go at finding something that works for you, but I kind of feel like I’d be robbing you of the learning experience.

If you get particularly stuck then I don’t mind too much, but I kind of thing that procedural generation is the kind of thing where you need to get a feel for how different processes produce patterns and data, and go through a lot of trial and error to fine tune the result.

(Also, I probably wouldn’t have the time anyway at the moment.)

That’s definitely just because you aren’t actually attempting to draw the other road sprites. Your code picks the road sprites out of an array, but it only ever draws frame 0 of any sprite.

I think you should start by deciding whether you want to go down the route of picking the correct tile sprite at render time or assigning each road type a tile and building all those tiles into the map at generation time.

Ordinarily I’d say working it out at render time should be easier, but like I said before, I think the rendering might already be too slow.

I would imagine the buildings might be too tall.

That does happen to an extent with the original too if you look. directly adjacent roads are only just visible by the columned buildings, and the taller buildings almost completely obscure them.

Either way, I’d suggest filling the level with a known pattern and examining it to determine whether the issue is with your sprites or just how the level is generated.


If I get some time I might draw some diagrams that might help you understand the situation better.

In the meantime, I found a tutorial that mentions and has some diagrams demonstrating what I meant about using 4 bits to represent whether a road tile has connections to other road tiles.

(Personally I’m not sure I’d label it ‘bitmasking’, but it gets the idea across.)

Looking at the original game again it appears to be an issue with how the level is generated, as the original game seems to just have more blank tiles (which makes the road more visible). But regardless ill just start over again and let you know how it goes

Ok, ive started rewriting my map generation (to set all tiles to road then randomly fill with blocks of buildings)… what i have so far works but I still need to figure out proper placement (since doing it randomly isn’t likely to produce usable results )… though I also did found this:

Which generates roads like this:

And its definitely a good start so I’m gonna try to implement that tomorrow when I’m a bitp less tired lol (and worst case if i cant get it working using the above method i can just take the generated blocks and simply add them together with a space in betwen

Ah, Lindenmeyer systems. Fun stuff.

I’m aware of them, but it didn’t occur to me that they could be useful in this instance. Usually I think of them as mainly being useful for trees and decoration.

But that’s probably just because the examples Wikipedia provides produce those sorts of things:

Thinking about it, I suppose certain road layouts could be represented as a tree. (Any group of connected roads could be represented as a graph, and a tree is a specific kind of graph - a “connected acyclic unidirected graph”.)

If you can get one that produces decent roads though, there’s a chance it might use too much memory to be practical on Arduboy since they effectively need to be double buffered (i.e. they generally need to store both the current state and the next state as it’s being produced).

The example given in that SO answer seems to me more like a randomly generated k-d tree than a Lindenmeyer system, but the answerer listed the axiom, rules and so forth so I suppose it technically must be.

It could work, but the problem is that it’s recursive, so you’ll have to be careful to limit the depth, otherwise it’ll chew up too much RAM.

(I’ve got a feeling this algorithm actually crossed my mind at some point last week, but I’ve had so much to think about these last few days that I probably completely forgot about it.)

I think you may have gone vertical when you should have gone horizontal in one place. That aside, yes, that’s the sort of thing the algorithm could produce.

You might be surprised. The key is to use the PRNG only to make decisions (e.g. how big the block of buildings you’re about to place is going to be, how far away it should be places). With the right rules, the rules will provide structure and the PRNG making decisions will provide suitable variance.

I can think of a few more approaches, that might produce a decent result, but some are more expensive than others.

If you remind me what your map size is, I can do a few checks to see what might be more efficient.

Hmm, ok… im not really sure what would be the most sensible approach at this point. But my map size is 32x32

Also i just realized the link i posted above goes on to say it can be done recursively or iteratively (and shows both in code), although i still dont quite understand it yet

Anything that can be done recursively can be done iteratively, but in some cases that requires using a stack, or in this case a tree.

(E.g. flood fill is one such case where a stack is required. The example in this SO answer is better than the wonky pseudocode in the Wikipedia article.)

The Gamedev SE answer’s ‘iterative’ example uses a tree data structure, so it’s still using memory, and potentially quite a lot of memory. I’m not sure which would be cheaper, it probably depends on how you implement the tree.

Even then though, the example code is just for generating that weird tree, it would have to be adapted to produce the road layout.


I just noticed that image used in the answer says it’s taken from another answer. That answer is here:

The algorithm discussed is nice and simple, but probably wouldn’t suit what you’re trying to do.


When I have the time I’ll have a think about the options to see if I can determine which is best without having to write any code (or if I really have to, I’ll write some simple demos).

Ohh alright, thanks! Yeah ive been trying to look up everything youve mentioned in regards to different methods (and how to do them on a 2d grid, etc), just had a hard time fully wrapping my head around any of them enough to see the pros and cons (and haven’t come up with very many answers in the way of implementing any of them either)

No worries, ive still been trying to work it out on my own… i came up with even less answers/resources when it came to generating the map as roads first then buildings (actually zero answers lol)… seems like everything ive come up with so far favors it the other way around (buildings then roads) since they just generate the road instead of needing to generate/place entire building blocks… so for now ive been back to working on a copy that has it set up that way, and ive been trying to just implement a simple set of rules (although ive been so exhausted ive been having difficulty with that as well lol, so maybe tomorrow)

I had a very brief look today.

So far I have established that the randomised squares approach is very unlikely to work:

#include <iostream>
#include <cstdlib>
#include <cstdint>
#include <cstddef>

char city[32][32];

constexpr char road = '.';
constexpr char building = '#';

void fill(char value)
{
	for(std::size_t y = 0; y < 32; ++y)
		for(std::size_t x = 0; x < 32; ++x)
			city[y][x] = value;
}

void generate(std::size_t steps)
{
	// Fill with road
	fill(road);

	for(std::size_t step = 0; step < steps; ++step)
	{
		const std::uint8_t x = (std::rand() % 32);
		const std::uint8_t y = (std::rand() % 32);
		const std::uint8_t width = (2 + (std::rand() % 4));
		const std::uint8_t height = (2 + (std::rand() % 4));

		const std::int8_t lowX = (x - (width / 2));
		const std::int8_t highX = (x + (width / 2));
		const std::int8_t lowY = (y - (height / 2));
		const std::int8_t highY = (y + (height / 2));

		for(std::int8_t y = lowY; y <= highY; ++y)
		{
			if(y < 0)
				continue;

			if(y >= 32)
				continue;

			for(std::int8_t x = lowX; x <= highX; ++x)
			{
				if(x < 0)
					continue;

				if(x >= 32)
					continue;

				city[y][x] = building;
			}
		}
	}
}

void print()
{
	for(std::size_t y = 0; y < 32; ++y)
	{
		for(std::size_t x = 0; x < 32; ++x)
			std::cout << city[y][x];

		std::cout << std::endl;
	}
}

int main()
{
	generate(64);
	print();

	// Uncomment this line if necessary
	//std::cin.get();
}

(Either compile as desktop code or run with something like this to get the output. # represents a building, . represents a road. Note that this is a really poor way to write proper code, but this is a simple throwaway experiment to get the idea across, so code quality isn’t important here.)

It would probably work alright for a cave system or land and ocean, but not for what you want. If I have time I’ll give the other techniques a spin, but they’ll likely take longer than the 5-10 minutes this took.

The subdivision technique seems to work alright as long as you don’t go too heavy on the number of steps, but I’m still slightly concerned about stack usage.

#include <iostream>
#include <cstdlib>
#include <cstdint>
#include <cstddef>

char city[32][32];

constexpr char road = '.';
constexpr char building = '#';

void fill(char value)
{
	for(std::size_t y = 0; y < 32; ++y)
		for(std::size_t x = 0; x < 32; ++x)
			city[y][x] = value;
}

void fillHorizontalLine(std::uint8_t x, std::uint8_t y, std::uint8_t width, char value)
{
	for(std::size_t offset = 0; offset < width; ++offset)
		if(x + offset < 32)
			city[y][x + offset] = value;
}

void fillVerticalLine(std::uint8_t x, std::uint8_t y, std::uint8_t height, char value)
{
	for(std::size_t offset = 0; offset < height; ++offset)
		if(y + offset < 32)
			city[y + offset][x] = value;
}

void generateHorizontalStep(std::uint8_t x, std::uint8_t y, std::uint8_t width, std::uint8_t height, std::uint8_t depth);
void generateVerticalStep(std::uint8_t x, std::uint8_t y, std::uint8_t width, std::uint8_t height, std::uint8_t depth);

void generateSubdivide(std::uint8_t depth)
{
	fill(building);
	generateVerticalStep(0, 0, 32, 32, depth);
}

void generateHorizontalStep(std::uint8_t x, std::uint8_t y, std::uint8_t width, std::uint8_t height, std::uint8_t depth)
{
	if(depth == 0)
		return;

	if(width < 2)
		return;

	if(height < 3)
		return;

	const std::uint8_t division = 1 + (std::rand() % (height - 2));

	fillHorizontalLine(x, y + division, width, road);

	const std::uint8_t upperY = y;
	const std::uint8_t upperHeight = division;

	const std::uint8_t lowerY = (y + division + 1);
	const std::uint8_t lowerHeight = (height - division - 1);

	generateVerticalStep(x, upperY, width, upperHeight, depth - 1);
	generateVerticalStep(x, lowerY, width, lowerHeight, depth - 1);
}

void generateVerticalStep(std::uint8_t x, std::uint8_t y, std::uint8_t width, std::uint8_t height, std::uint8_t depth)
{
	if(depth == 0)
		return;

	if(height < 2)
		return;

	if(width < 3)
		return;

	const std::uint8_t division = 1 + (std::rand() % (width - 2));

	fillVerticalLine(x + division, y, height, road);

	const std::uint8_t leftX = x;
	const std::uint8_t leftWidth = division;

	const std::uint8_t rightX = (x + division + 1);
	const std::uint8_t rightWidth = (width - division - 1);

	generateHorizontalStep(leftX, y, leftWidth, height, depth - 1);
	generateHorizontalStep(rightX, y, rightWidth, height, depth - 1);
}

void print()
{
	for(std::size_t y = 0; y < 32; ++y)
	{
		for(std::size_t x = 0; x < 32; ++x)
			std::cout << city[y][x];

		std::cout << std::endl;
	}
}

int main()
{
	generateSubdivide(6);
	print();

	std::cin.get();
}

If all else fails then this is probably a decent approach to fall back on.

In the back of my head I’ve got an idea for another approach,
but I just can’t think of a good way to formalise it.

Hmm… i still dont quite understand how the subdivision technique works, sorry. Still trying to make a bit more sense of it though

Try doing what the above code deos manually with a pencil and paper (and ideally a grid, or some gridded paper).

It’s basically just taking a rectangular area and partitioning that area into two other rectangular areas by drawing a line ‘somewhere’ (the position is chosen randomly). That process is then repeated with each of the partitioned regions (i.e. the process recurses - this is recursion), up to some arbitrary depth, and alternating between horizontal and vertical partitions (i.e. if the first partitioning was done vertically then the two partions will themselves be partitioned horizontally).

In my above example the depth is limited by both an explicit depth parameter, and by checks to ensure that the region being partitioned is sufficiently large - if it’s too small, the function returns. I.e. a region must be at least 3 (tiles/cells) wide and 2 (tiles/cells) high to be partitioned vertically, and vice versa for a horizontal partition.

The above code would only require minimal adaptation to work with your existing code. If you can’t figure out how then I’ll see what I can do when I have time to do so.

1 Like

Ahh ok, that makes much more sense, thank you! I had come across various resources that talked about/showed that method but couldnt quite put it together thats what you were doing (and couldnt quite understand any of the examples enough to get it) but that explanation makes it much clearer step by step, thanks!

And i might be able to adapt it to my existing code, just wanted to make sure i at least understood it before attempting lol.

Ok, i managed to make a good bit of progress but have a few parts im a little stuck on. Everything compiles, uploads, and works except for some reason my buildings are only displaying one of the sprites (even though the code im using to return their index looks ok so im not sure whats the issue)

And as for the generation, it seems to give mixed results… too few depths and it wasnt split up enough, as you increase it looks good in groupings up to a certain number, then it doesn’t appear to have any effect (as i would imagine you can only subdivide an area so many times)… not sure what might be a good solution to spreading it out (or if the issue just has to do with something i did putting it together lol)

You’re going to kick yourself when I tell you what the problem is.
But first up, let’s examine the relevant bits of code…

Firstly, this building variable is assigned once and never modified:

But even if it were modified, it’s not actually necessary because it’s being fed directly to the fill function:

And the fill function fills the entire field with a single tile - the tile provided as an argument.

If you meant to fill the field with lots of different buildings, you’ll need to modify the fill function.


The example I gave you was purposely simplified to try to make it easier to understand:

  • I used chars instead of tiles so it wouldn’t need any fancy rendering code, I could just print it to the console
  • I used the building and road variables to show what those two characters were supposed to represent rather than just having two seemingly arbitrary characters littering the code
    • Had I used an enum class instead, I could have just used enumerator values, e.g. TileType::Road
  • I filled the map with a single building type to avoid complicating it with building selection code

It was supposed to be a very distilled form of the subdivision algorithm without any additional complexity, so you could focus on how the algorithm works.

Indeed, there comes a point where an area cannot be further divided. Like I said before, I set it up to refuse to subdivide if subdividing would not produce at least two buildings either side of the road, else you’ll end up with 2-wide roads in certain places.

If that confuses you, get some gridded paper and do the algorithm by hand. It’ll give you a greater appreciation for what the code has to do, and you may even think of some way to get better results by adjusting the rules.

No, it looks like you ‘glued it in’ well enough. The fact you ended up with only one kind of building is more or less proof that you ended up with a very literal adaptation.

That depends what you mean by ‘spreading it out’.
I notice that some areas end up with lots of small buildings and other areas end up with fewer, larger buildings.

If that’s your problem then I can think of one possible way to solve that…

Instead of placing the partition completely randomly, it may be better of have the parition occur randomly up to ‘N’ tiles away from the centre of the area. E.g. up to 3 tiles away from the centre, so you could end up with anything from -3 to +3 tiles away from the centre, where permitted.

I think you might struggle to adapt it to do that on your own, but I think you should try anyway, purely to give you chance to play around with the algorithm, to try to make sense of it. It might be easier using the desktop version though, assuming you have a suitable C++ compiler for desktop, or can find a decent online one.

If you can’t manage it then I’ll try to find some time to provide you with an adapted one, but I think the experience would do you good. Procedural content generation is one of those things where you either need to be a really good mathematician that understands the kind of patterns certain algorithms produce, or you need to get some experience (and ideally exposure to different algorithms) so you develop a kind of feel/instinct for how certain algorithms behave and how certain modifications are likely to change their behaviour. (Also doing them manually or visualising how they happen can help a lot with understanding why they produce the effects that they do.)


While I worked on a way to create the console version of the algorithm, I also developed a modified version that avoids producing building blocks with a width or height lower than a specified amount, the buildingLimit, (e.g. if you specified ‘4’, the smallest block of buildings would be 4x4,) but I’m not sure that would help much in your case.

Just to show you some results…

1: BuildingLimit1 2: BuildingLimit2 3: BuildingLimit3 4: BuildingLimit4

(I presume all of these are using the same seed based on how similar the outputs are.)

Ahh ok, yeah definitely kicking myself for that lol. And yeah, i know it was meant to be as straightforward/simple of an example as possible but in my defense i was half asleep (to the point i was falling asleep) while trying to figure it out :sweat_smile: sorry lol. But ill give it another look over with all of that in mind, thanks!

Sorry, not sure why im still having trouble with this… i deleted the line

“TileType building = generateRandomBuildingTile();”

And changed fill(building) to fill(generateRandomBuildingTile());

but im not seeing how i need to change my fill function, sorry. Updated the repo with rhe most recent changed though

Nevermind, I got it… I just had to change my fill function to

void fill()
{
  for(size_t y = 0; y < 32; ++y)
    for(size_t x = 0; x < 32; ++x)
      tileMap[y][x] = generateRandomBuildingTile();
}

…although I am genuinely confused how this differs from passing it as an argument like I was originally trying to do

Edit: also, just thinking about how to fix the road generation issue, is there a way to increase the probability of spawning a certain tile? I’ve changed my max building tile to my blank tile (and should really rename all that stuff to reflect this), but I’ve noticed the original uses blank tiles as a way to both break up the building blocks and keep them from obscuring the street (since right now even if I include them in with my other buildings you can’t see the street)

I’ll update the repo with the changes now, just thinking put loud a bit now that I look at it on my arduboy