CleverRaven / Cataclysm-DDA

Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.
http://cataclysmdda.org
Other
9.95k stars 4.08k forks source link

Urban development concept #21488

Closed acidia closed 5 years ago

acidia commented 6 years ago

Hey, I'd like to get input midway through the current project so I can correct course if needed to get the best player experience.
The attached 6 pictures are from an urban development concept I've had around for a few months. To make actual cities happen in game we need z-level support, a reworked/or patched mapgen function, and a metric ton of buildings. I'll never have the time to implement z-levels but I might be able to tackle the other two. The suburbs Using 2x1 map tiles for the houses gives enough working space that I can base the houses on real buildings, at least to a better degree. This acts to distinguish the transition from rural buildings to a more urban environment. suburb 1 suburb 2 suburb 3

The cities My thoughts on how cities could be implemented would either be in blocks or along main streets. The vast majority of building will either be 2x1 "Dense Urban" tiles or 2x2 major buildings. I really like how the alleys in the blocks generate even if a city is only big enough to generate a single block. Main streets would probably be more realistic but there wouldn't be tight alleys unless if the city is large enough to generate 3 main streets (2 EW 1 NS or 1 EW 2 NS) Figured cities would be a core of major buildings/dense urban tiles, a ring of traditional commercial buildings, a ring of 50% (2x1) suburban houses 25% (1x1) traditional houses 25% commercial, finally allow mapgen to use the current function to tapper the edges till wilderness. Not great for neighborhoods but easier to implement. I think the shortest building in the city blocks is the 2 story cafe, the tallest is the hotel tower (5 floors with penthouse?). Everything has a basement/foundation so in theory a character can easily tunnel from one building to the next or jump from roof to roof. city block 1 Block 1 Left to right, top to bottom (2x2) Police station, movie Theater & office, house & Bank, (2x2) fire station (2x2) Police station, house & apt & house, salon & low income apt, (2x2) fire station city block 2 Block 2 (2x2) Hotel tower, apt & diner, clothing store & subway & jewlrey store, (2x2) school (2x2) Hotel tower, apt & Quick-e-Mart & to go food, club & house, (2x2) school city block 3 Block 3 Laundry & ouside cafe & nice clothing store, row houses, (2x2) hospital

Under construction/Ideas: Dense Urban (2x1) Bar Hardware Store Drug Store Gym Major Buildings (2x2) Projects (ocean of undead) Public library (cultists?) Church (survivor castle?) Ikea Parking Garage Subway & bus terminal Office building (covered in bees?)

Current Goals: 35/50 z-level suburban/urban buildings as a proof of concept/justification for suburban/urban code 2.5/3 full city blocks of unique buildings

What I need: -Urban building ideas or changes to existing ones, sorry you can't see the other z-levels. -Suburban house blueprints or sketchs that would be cool in game -Thoughts, current subway tiles are at z-1 but if most building have basements/foundations there is no room after sewers are accounted for. Keep sewers on z-1, push subways to z-2? Now would be the time as I'm adding subway stops. . -Motivation to finish item and vehicle spawns on the 2nd half of the completed buildings, the worst part

Coolthulhu commented 6 years ago

Thoughts, current subway tiles are at z-1 but if most building have basements/foundations there is no room after sewers are accounted for. Keep sewers on z-1, push subways to z-2? Now would be the time as I'm adding subway stops.

I'd push sewers to -2, to make them stop clashing with basements.

To make actual cities happen in game we need z-level support, a reworked/or patched mapgen function

What exactly is needed? What is lacking in current z-level support that is necessary here? As for mapgen: you mean overmap gen or map-level mapgen?

DangerNoodle commented 6 years ago

What exactly is needed?

The only thing that comes to mind is that the current way that houses and shops are placed in towns has no support for wide or tall mapgens, both houses and stores. It always has to be 1x1 in floor plan, and only 1 level in height, with basements handled via separate code.

This is the reason why More Locations mod handles multi-story houses by having them as overmap specials, not by adding them to the default region settings.

acidia commented 6 years ago

Sorry for being vague. overmap gen is what I was looking at for generating cities focusing either on a block or main street approach, the outstanding map generation issue. As dangernoodle said, I'm current running all buildings as overmap specials which means all but the suburban houses look out of place as they are strewn all over the map.

Coolthulhu commented 6 years ago

So basically, we want "in-city specials"? It could be implemented by allowing signed city distance for specials: 0 distance would be border of the city, negative would mean deeper in the city. High negative distance would mean inside big city.

Good enough? If not, I'll need more data, at least an example of how it should look like after proper generation (ascii art or a ms paint block of rectangles with some explanation would be enough).

Could be a better to move the discussion to the forums. We have an unwritten rule that suggestions go on forums and github is for more "concrete" stuff.

DangerNoodle commented 6 years ago

Problem is generation of them. Forcing them to appear will risk the problems that have plagued overmap specials as of late.

vache commented 6 years ago

I actually have a ton of thoughts on improving cities and mapgen that are probably a little too extensive, but a quick summary is that overmap gen would track city sizes and use a distribution to determine the size of new cities, then it would apply a "theme" to each new city based on its size and the existing cities and their themes, then when it populates the city, it splits it up into districts, which it then uses along with some combination of tags on the overmap terrain entry and the mapgen entry to determine which buildings to place in this section of the city.

So for example: A medium sized city is placed, and its theme is "rust belt style industrial town" The city is split up into several districts, such as a city center, high density low income housing, heavy industrial, medium density housing, and a small commercial district When placing a building in the city center, it has a much higher chance to select a building tagged as "CIVIC," or when placing one in the high density low income housing, it has a much higher chance to select a building tagged as both "HIGH DENSITY" and "LOW INCOME", and because of the overarching city theme placing buildings in general in the city has a much higher chance to select ones that are tagged "ABANDONED" or "DISREPAIR", etc.

I think this would be a good way to have finer grained control over what sort of things spawn where and make the overmap generation smart enough to create cities that feel diverse and realistic.

Edit: Also, when spawning, cities could keep track of which buildings have spawned in that city (and even which variant) to prevent saturating a certain type, or to ensure that some buildings (like a city hall) can always be placed.

John-Candlebury commented 6 years ago

This is my idea for city generation

img_20170725_0001 Now for an explanation of how its generated:

  1. The game places the city center
  2. From the center main streets are generated, main streets are the ones that can exit the town to connect with other towns and specials. If the streets dont connect to anything outside town, they can decay into core or suburb street after some distance.
  3. Every X map tiles, the main street adds an intersection from which a a city core street originates.
  4. Every time two city core street intersect theres a chance that the street will: continue as a core stret, decay into a suburb street, end, or continue for X tiles and end. 5.Then suburb streets are generated using the algorithm we have now
  5. Now the game looks at the empty plots between the core streets, and based on a list of "city specials" decides what will fit in each. For example the 3x3 lot could either fit a single hospital or a 2x2 office tower and an L shaped parking lot.

Then the specials could also have some placement requirements ( for example: whether its adjacent to a main street, whether its adjacent to suburbs or the distance from the city center). So you could have taller office buildings and government offices in the very center of town and then have shopping malls and parks near suburbs

The bad part is that this basically requires a complete rework, and I have no idea of how simple this is, most likely not easy at all.

Frost-wood commented 6 years ago

The mapgen definitely needs a rework-the last person who understood it left the project. I think vache is the only one who has worked on it.

The code is also slightly spaghettish-determining where it all starts takes a bit of work.

It probably needs to be split into steps- a) subways and sewers need to transferred into json. Unfortunately subways and sewers use a loop to create them rather than being defined in json. b) roads needs to be transferred into json.

7 days to die recently managed to change their system which generated much like ours to a socket-based system, with cities having a industrial, residential, and commercial district, and one that supported buildings of all shapes and sizes.

Coolthulhu commented 6 years ago

a) subways and sewers need to transferred into json. Unfortunately subways and sewers use a loop to create them rather than being defined in json. b) roads needs to be transferred into json.

They can't be - algorithms for connecting cities with all of those are necessarily hardcoded.

Frost-wood commented 6 years ago

They can't be - algorithms for connecting cities with all of those are necessarily hardcoded.

That's why it's so time-consuming to change mapgen in general-everything is hard coded and linked together.

ZhilkinSerg commented 6 years ago

That's why it's so time-consuming to change mapgen in general-everything is hard coded and linked together.

Many mapgen things were already moved out to json, but it is not possible to move out everything.

vache commented 6 years ago

Well the whole moving things to json is a tangent to this conversation in general, improving city/worlds is more overmap gen focused, rather than mapgen, which is focused on how to generate a specific tile. I'm not sure how you'd define how to create roads in cities through json, except for maybe through a bunch of generic parameters for city construction. I don't believe there's anything wrong with the way roads and subways and sewers are generated currently, except for the weird situations with subways, sewers, and basements.

I will say that the algorithm for generating actual cities is very dense and confusing (as of the last time I looked at it at least). IMO, city generation would really benefit from a several step process (probably with the implementation pulled out of the overmap class) that tracks info relating to the generation process throughout, and makes it available whenever new cities are generated.

BorkBorkGoesTheCode commented 6 years ago

-Thoughts, current subway tiles are at z-1 but if most building have basements/foundations there is no room after sewers are accounted for. Keep sewers on z-1, push subways to z-2? Now would be the time as I'm adding subway stops.

I'd agree with that. Maybe add larger sewers at -3. Basements deeper than -1 could be quite interesting.

You could add abandoned sewers, with a small number of them repurposed as smuggler's tunnels.

BorkBorkGoesTheCode commented 6 years ago

Projects (ocean of undead)

Office building (covered in bees?)

Don't really like the "projects are filled with undead" and "Corporate drone" ideas, otherwise this looks good.

Coolthulhu commented 6 years ago

Started working on this. I've got some questions:

acidia commented 6 years ago

My thoughts were to keep everything 2x1 or 2x2 just to make everything look more organized with blocks always being an even number of spaces oriented N/S or E/W. All buildings I'm drawing have main entrances at the south, assume that there will be buildings at e/w, and a road/back entrance at the N if it is 2x2... Before rotation. If that's standardized then coding will be much easier?

Having parks sounds like a good idea but we might want to keep them in the same 2x2 or 2x1 json format so we can control what actually spawns (as opposed to a normal forest with a large respawning bush food source).

I'd like if suburbs could also be assumed to be gridded in similar format. I have a couple is Mcmansions that are 2x2 that assume the garage entrance is in the back of the building.

As far as zoning goes, make it as simple or complex as you want. Long term it would be cool to have a block do all it's pulls from a single tag or list, so we can have "historic block" or "community college block" but it certainly isn't necessary when all we have now is R1/R3/C3.

I'm 100% down if you want to tackle the actual coding of mapgen, let me know if I need to change or add something to make it easier for you.

Coolthulhu commented 6 years ago

If that's standardized then coding will be much easier?

Yeah, but it's not necessary. It wouldn't be much more difficult to have blocks that allow mixed sizes, for example, assuming only square buildings (just for the example, not code), it could be filled with:

+---------+
|224444111|
|224444333|
|224444333|
|224444333|
+---------+

The 4 size building could be a big hospital or a park. The 2s here are two separate buildings.

All buildings I'm drawing have main entrances at the south, assume that there will be buildings at e/w, and a road/back entrance at the N if it is 2x2... Before rotation.

Wait, all assume buildings at e/w? What about the ones at the extreme end? Also, what about:

+----
|aaxx
|aaxx
|bbxx
|bbxx
+----

The building at a could be rotated north or west, while b could be rotated south or west. But according to your examples, the west option would be dropped. Is this the desired behavior? I mean, it may actually be easier to have random directions (out of the proper ones), but it may be undesired.

vache commented 6 years ago

Can you include support for something like

+---- ... ----+
|WMMM ... MMME|
+---- ... ----+

Where W is a west end-cap, M is a middle item, and E is an east end cap?

I've been tinkering with some expandable townhomes that can fill any width, and I'm close to having them ready to PR, but there's no framework to support their spawning right now.

Coolthulhu commented 6 years ago

I was thinking of something more generic, like allowing any rectangular filling of the "main" square, including 1x4 blocks. You'd define a special with 0 occurrences, then declare it as potential city building for given city type. Then when generating a city block, it would sometimes be picked to fill in a properly shaped void.

vache commented 6 years ago

Well I was thinking of something like an expandable building, so it can be 1xN and can fit any rectangle of that size. Ideally the same method could be used for larger sizes, but I can't think of a great use case for that right now.

What I have mocked up right now has a left end cap, and then X middle items, and then a right end cap, but the code isn't there to support that, so I was suggesting that as something you might include.

Coolthulhu commented 6 years ago

Requiring the other cap complicates things. Not that much, though. While I won't add support for it with my first PR, I could make it easy to add it later.

The idea is that when filling out the block, I'd generate a map of counts of possible sizes to fill in - only rectangles (at least at first) to simplify things. This would probably be brute-forced (O(n^4), but that's fine for block sizes below 20, at least with some minor caching). I could add support for caps by including boundary data in the "max rectangle" results. So a rectangle would be width, height, road_north, road_east... with road_x being true if the rectangle is bounded by road from this side. Now that I think about it, it may actually be useful even without variable size buildings.

Variable size buildings could be then added on top of that, by including them on the list of buildings of given size.

acidia commented 6 years ago

Hmmm, I see it becoming very difficult to produce enough buildings of varying sizes to prevent wasted space/repeats if we include larger buildings expanding a block along the short axis. Wouldn't it be simpler to have 3x3+ structures occupy their own block and design them assuming being surrounded by road? 2 deep blocks guarantee access for a fire exit/alt entrance in the back, keep a consistent store front along their major access, and have a well organized appearance.

vache commented 6 years ago

If we're aiming for realism, we could probably just pad in some of the blocks with parking lots and everything would still look and feel correct, and we wouldn't have to wonder why all these buildings are just hanging out with no parking.

Coolthulhu commented 6 years ago

Wouldn't it be simpler to have 3x3+ structures occupy their own block and design them assuming being surrounded by road?

But then blocks of sizes like 3x4 would need to have a lot of 1x1 padding. Or could only have contents out of a very small selection.

I see it becoming very difficult to produce enough buildings of varying sizes to prevent wasted space/repeats if we include larger buildings expanding a block along the short axis.

Some repeats are mandatory. We have a lot of 1x1 buildings, those could easily be used to pad bad attempts if the numbers were low. The smaller buildings would generally only be placed after placing large ones fails.

The block would not expand once placed. Rather, it would be placed first and then filled out. This is easier to implement cleanly because those two phases can be separated.

Coolthulhu commented 6 years ago

Update: This is very painful and I feel terrible about my problem solving ability when working on this.

I went with 4x[something] block size at start. But this means that the blocks look quite bland.

Here's my idea of the algorithm:

/**
 * New city building goes like this:
 *  Place center block (nesw_road)
 *  Extend main roads from center block to city size (or less, if blocked)
 *  Create a queue of { origin, direction }
 *  For direction in { north, east, south, west }:
 * * Enqueue { city center, direction }
 *  For every element in queue:
 * * Take it down from the queue
 * * Calculate leftover area from city size and distance from city center
 * * If the leftover area is too small, go to old citygen (overmap::build_city_street)
 * * If the area is big enough, try to build a rectangle on the right side of the road
 *  * The rectangle must have size of at least 4x4 (2 for roads, then 2x2 in the center)
 *  * The rectangle must be bounded from two sides by main roads
 *  * Create the roads that form boundaries of the rectangle
 *  * While the rectangle is not filled:
 *   * Brute force all possible sizes of buildings (O(n^4), but n<10)
 *   * Pick a building to place and place it
 * * If the rectangle was placed, decrease leftover city area by area of new rectangle
 * * If leftover city area is greater than some constant:
 *  * Find two corners of the rectangle: one in current direction, other to the side
 *  * Enqueue { corner in front, direction }
 *  * Enqueue { corner to side, rotate_clockwise( direction ) }
 */

Here are some results, currently with no buildings, because I want the roads working before I start working on building placement:

blocks

acidia commented 6 years ago

What's it look like with the inside of blocks being between 2x4 and 2x8? Just saying, we can fill those pretty well and it'll make the streets busier for a given town size :)

vache commented 6 years ago

Those blocks seem WAY too big to me. IMO, 2 to 3 by makes sense for most city sizes, 4 by would probably only work for large cities, and smaller cities should probably use something closer to current city generation. Maybe it could be 1-4: current, 5-9: 2-3 by, 10+: 4 by.

I-am-Erk commented 5 years ago

I think at this point this is fairly antiquated to the current way we're planning to progress in urban development - ie with land use codes and zoning. I'm going to close it, but if someone more active in the city development stuff wants to contradict me that's fine I'll reopen.

ZhilkinSerg commented 5 years ago

We can still scrap new overmap terrains from https://github.com/CleverRaven/Cataclysm-DDA/pull/23748/files.