• Register

Software Inc. combines tycoon gameplay with multi-story building mechanics, employee management and a simulated market. It is inspired by games like Game Dev Tycoon, Prison Architect, The Sims and Theme Hospital.

Report RSS Generating a city

I explain how to generate a city with a road system and skyscrapers that light up at night.

Posted by on

I recently added a city environment to Software Inc. You used to just start out in a forest with nothing more than a road crossing through and some trees. The city changes things up a bit, since a road is laid out when you start a new game and you slowly take it over by expanding your plot.

Laying down the road system


So let's start off with the algorithm for generating the road system. I basically divide the map somewhere around the middle, from the right to the left edge. I then end up with two sections, i divide these up somewhere around the middle, from the top to the bottom edge. I continue this process until I end up with sections that I think shouldn't become any smaller and, finally, I fill the final sections with a skyscraper, a parking lot or some trees. And that is it!

I've added some pseudo code at the end of the article.

Placing windows


Skyscrapers are generated procedurally by placing each window individually along the outside of the building. The picture below shows how a finished skyscraper looks in the Unity editor.

I have four quads(rectangles/planes), which map to each corner of the texture pictured below in their UV coordinates. The bottom right gray quad is used for the roof and the top and bottom row of the building. The bottom left quad is the door, placed in the bottom center of each side of the building. The top quads are windows. The top right quad is lit in a separate emission map, so only windows that are made from the top right quad light up at night.


Since I'm using one texture for the entire building, I gain a lot of performance by merging all the quads. This is done in Unity by using a CombineInstance object, which contains a mesh, coordinates, scale and orientation. If you have a list of combine instances, Unity can merge them into one mesh for you, which saves a lot of overhead for both the GPU and CPU. I do the same with trees.

I'm faced with a problem however. I want the lights to slowly turn on during the evening, but with the current system, my only option is turning on all lights at once, by enabling the emission texture. I then remembered that Unity 5 introduced the option of having several UV maps, so I decided to take all window quads through a function, which generates a random UV coordinate, and saves it in the window quad's second UV map, for all vertices. I wrote a custom shader which uses the randomly generated x coordinate to decide when to enable emission and the y coordinate to tint the emission color by sampling the gradient texture pictured below. Randomizing the tint a bit adds some life to the windows. It is very important that all of this is controlled by a shader, since having this logic for each window on the CPU is way too slow.


Now I just need a threshold to decide when windows should light up. You can picture this as if each window had it's own horizontal line crossing through the curve below, and every time the curve is above this line, the windows light up. In the curve pictured below, 0 is 00:00 and 1 is 23:59. You can see how all the lights turn on during the evening, then they fall down quickly and stop at 10%, which represents the night owls. Finally you can see a small jump in the morning, at around 0.25, when the early birds arrive.

Pseudo code for generating the roads

The algorithm for splitting an area into two areas, with a dividing road, is recursive.

It takes as input whether the split should be vertical and the horizontal/vertical range of the area to divide. The Rectangle object is initialized with x, y, width and height parameters.

DivideArea( vertical, rangeMin, rangeMax, borderMin, borderMax )
	//Choose a dividing line
	range = ( rangeMax - rangeMin ) / 4
	range = Random number between -range and range
	mid = ( rangeMin + rangeMax ) / 2 + range
	//Generate a rectangle that defines where the road is, always 1 wide
	if vertical
		r = Rectangle( mid, borderMin, 1, borderMax - borderMin )
	else
		r = Rectangle( borderMin, mid, borderMax - borderMin, 1 )
	Place a road along the rectangle r
	//If there is enough room in this area, split it further
	if ( borderMax - borderMin > 5 )
		DivideArea( inverse vertical, borderMin, borderMax, rangeMin, mid )
		DivideArea( inverse vertical, borderMin, borderMax, mid + 1, rangeMax )
	else
		//If there is not enough room, save the areas that have been generated
		//These areas can then be filled with skyscrapers and parking lots
		if ( vertical )
			save Rectangle( rangeMin, borderMin, mid - rangeMin, borderMax - borderMin )
			save Rectangle( mid + 1, borderMin, rangeMax - mid - 1, borderMax - borderMin )
		else
			save Rectangle( borderMin, rangeMin, borderMax - borderMin, mid - rangeMin )
			save Rectangle( borderMin, mid + 1, borderMax - borderMin, rangeMax - mid - 1 )
Post comment Comments
SteveMcStevenson
SteveMcStevenson - - 140 comments

Noice!

Reply Good karma Bad karma+1 vote
DeepVigil
DeepVigil - - 14 comments

amazing!

Reply Good karma Bad karma+1 vote
GreenForest
GreenForest - - 426 comments

Simple division code, but look complicated with all commenting on each line. I would through Jacky Chan troll picture for this code.

Reply Good karma Bad karma+1 vote
Vladiskov
Vladiskov - - 384 comments

"Jacky Chan troll picture" my head its soo full of **** right now

Reply Good karma Bad karma+1 vote
GreenForest
GreenForest - - 426 comments

What's exactly what he thinks.: M.flickr.com

Reply Good karma Bad karma+1 vote
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: