A point of order: In the last entry I talked about deforming the walls to give them some interest. In my final example screenshot, I showed an image of hallways that bulged out in the middle. I didn’t make it totally clear how I planned to use this, and as a result some people were left with the impression that my plan was to have bare bulbous walls everywhere.
The bulbous walls were just a minimum-effort demonstration of the idea. My plan is to have the shape of the wall vary by room type. Maybe the corridors will be wide but short, like the ship in Alien. Maybe some walls will be very narrow and tall like in the first level of System Shock 2. Whatever.
There was also the concern that bare walls would get boring, and I should add greebles. I’m currently planning on using the “furniture” idea for this. Something like this image from System Shock 2:
If that doesn’t work out, then maybe I’ll back up and try something else. But let’s try this easy thing first.
With that cleared up, let’s talk about…
There are things known and things unknown and in between are the doors.
– Jim Morrison
No, not that kind of Doors. I mean doors between rooms.
If you remember from last time, a room is made up of line segments. Each segment is based on the grid. You can grab an arbitrary line and follow it to the next one, and the next one, and it will take you around the room counter-clockwiseLast entry I said clockwise. Wrong. I’ve lost track of the number of times I’ve gotten that mixed up and created a bug. My brain just really WANTS it to be clockwise I guess. until you go all the way around and land back where you started.
Note: If we’re dealing with an interior support pillar, then the lines go around clockwise. That’s not something I programmed, that’s just a natural result of how the system works. In both cases, you can take the direction the line is pointing, turn left, and be pointing directly into the room.
Internally, I call these lines of wall segments “chains”. So if you’ve got a room with a lone support pillar in the middle, then the room will have two chains. One chain will be the outer wall, and the other chain will be the outside of the pillar.
So now we need to create doors. That’s not as simple as blowing random holes in the walls. To create a door we need to do a lot of checks:
1) Obviously, we’re only looking at the chains that make up the outer walls. There’s nothing to be gained by attempting to put a doorway to access the void space inside a pillar. You’d just fall out of the level.
2) We need to find a straight section of lines that’s at least 3 segments long. The marching squares system we’re using will create walls that can face any of the four cardinal directions, or the four ordinal directions. You can picture a simple “round” room as being shaped like a STOP sign. Any of those eight sides are fine, but we want to avoid putting a door directly touching one of the corners because we’re going to need to blend a door frame object into the level geometry and if we do that at a corner then we’ll get messy intersections and it won’t look right.
In practical terms, to be a viable candidate for a wall, we’re looking for a line segment that’s the same shape as the one directly before it and the one directly after it. The ones in green are valid here:
3) We’re going to assume that the main corridor is how we’ll move from one section of the level to the next. So any side-rooms MUST have access to the main corridor. If rooms A and B only connect to each other, then the player won’t be able to enter them. So we’re going to place doorways from the perspective of the side-rooms. The corridor will not attempt to make any doorways for itself. Instead the rooms will search around their outer walls, looking for a connection to the main corridor, or access to rooms that have corridor access.
4) Once a room finds a straight section of wall, it needs to look on the opposite side of the wall to make sure the wall is also straight on the flip side.
5) Once we’re happy with a spot, we create a door. This door punches holes in the two rooms, enabling one of them to gain corridor access from the other.
We pass over the list of rooms again and again, until everyone gains corridor access or the process halts. If we go all the way through the list of rooms and nothing changes, then we know we’ve created all the doors we can. If we get to the end of this process and discover that we still somehow have rooms with no access, we can just throw them out and leave their assigned space empty.
One final thing we do is to go over all the chains and do a bit of rounding.
You’ll notice that point A (Fig.1) is on the edge of two walls that face different directions. For one wall A is the beginning, and for the previous wall A is the end. To allow them to share this point without leaving a crack / distortion in the wall, we average their normals (Fig.2) so that A is midway between both.
That’s a good start, but we can take this a step further if we want to round the walls even more. Let’s take a few lines between the neighbors of A (the green lines in Fig.3) and turn those lines left to get even more normals. Average everything together. If you have many walls facing the same way (such as all of the line segments on the far left of A in Fig.1) then they’ll all face the same direction, which would be south in this case. But as you approach the corner, the points will begin to gradually curve. This allows us to create a wall with gently sloping curves, as in Fig.4. (The amount of curve is exaggerated here for demonstration purposes.)
And here is what the level looks like:
Next I guess we’d better add some floors and ceilings so this can start feeling like a proper level.
I Forgot What I was Doing
At this point in the project, I had to set it aside for a couple of weeks to finish up my SWJFO series and do some general blog maintenanceDid anyone notice that I added a few dozen new entries to the “From the Archives” thing at the end of every post? No? To be honest, me neither. It’s fine. Those things are mostly there for newer readers to get them to hang around and see a little more of the site before they wander off.. When I came back, I’d forgotten a lot of fundamental things.
I’m constantly amazed at how quickly you can forget this kind of stuff. I can still remember names, faces, quotable lines, and bits of music from movies I haven’t seen since the 90’s. But the structure of the code I wrote last week? That might as well have been written by someone else.
Like I demonstrated above, the marching squares system will create divisions within a grid square. But when I got back, I was picturing it incorrectly in my head.
Note how the blue arrows line up with the grid in the right-hand image. I expected straight sections of wall to be aligned like this, and I assumed that I’d just need to do something special to handle the spots where the wall travels diagonally.
To make the floor. I just made a simple square for all parts of the grid that were inside a room. What alarmed me was that all along the walls, I’d see floor tiles from the neighboring room sticking into this one. The two rooms would have different floor textures, and I could see the ghastly z-fighting between them.
Because I’d forgotten what I was doing, I assumed this was a bug.
Oops. Looks like my walls are off the grid by 0.5 and I didn’t notice. No problem. Easy to fix.
Spoiler: This did not fix it.
Um. Oh! I see. One room is reaching into its neighbor. I’ve probably got an off-by-one error somewhere.
No Shamus, there isn’t an off-by-one error.
Uh? What am I doing wrong? Am I making floor tiles too big? Are my walls the wrong size? Do I have a bug in the code I use to look up what rooms occupy which points on the grid?
No, no, and no.
Oh! The floor object itself has probably been nudged off- center within the Unity scene. Happens sometimes when you mis-click. I’ll make sure the objects are all positioned at the world origin.
C’mon dude. I thought you were smarter than this. Stop wasting our time.
I don’t get it. It’s like each room has half a tile that sticks into the next room, as if I needed to chop the tile in half.
You’re getting closer, dummy.
But marching squares… Oh wait.
YEAH. HOW ‘BOUT THOSE MARCHING SQUARES?
This isn’t a bug in the code. This is literally how marching squares work. They cut cells by dividing them in half or taking off a corner. By definition, EVERY tile around the edge of a room is going to need to be a partial tile.
Once I get my head on straight, I stop and write some code specifically to handle those literal edge-cases. When I’m done…
You know, that looks kinda cool. It makes the floor a little more interesting to have a border like this. I think I’ll add a feature so that the artist can assign different textures to the edge and the main part of the floor.
Once I have that working, it’s trivial to fill in the rest of the floor and then make the exact same shape for the ceiling. Then while I’m at it, I might as well slap some polygons inside the door frame. We’ll fill in the door properly once we have furniture, but I just want to avoid having a gap where you can see out of the level.
Okay. We now have a fully enclosed level. My system is working, and the spaces are interesting yet easy to generate from simple input data. The space can be navigated and I’m happy with the shape of things for now.
We’re miles from being done, but I think this is a really important milestone.
 Last entry I said clockwise. Wrong. I’ve lost track of the number of times I’ve gotten that mixed up and created a bug. My brain just really WANTS it to be clockwise I guess.
 Did anyone notice that I added a few dozen new entries to the “From the Archives” thing at the end of every post? No? To be honest, me neither. It’s fine. Those things are mostly there for newer readers to get them to hang around and see a little more of the site before they wander off.
What is this silly word, why did some people get so irritated by it, and why did it fall out of use?
Please Help I Can’t Stop Playing Cities: Skylines
What makes this borderline indie title so much better than the AAA juggernauts that came before?
Revisiting a Dead Engine
I wanted to take the file format of a late 90s shooter and read it in modern-day Unity. This is the result.
The Mistakes DOOM Didn't Make
How did this game avoid all the usual stupidity that ruins remakes of classic titles?
What did web browsers look like 20 years ago, and what kind of crazy features did they have?