How to mark roof for show/hide?

Started by
11 comments, last by suliman 8 years, 4 months ago

Hi!
Im doing a top-down tilebased game in c++. Players can enter houses in which case roofs should be hidden (so you can see the enterior of the house. Right now i simply do:

if player is standing on a ground-tile that has a roof (player is inside a house) skip drawing ALL roof tiles.

I would like to only skip drawing the roof of that SPECIFIC building (not skip ALL roofs). Any clever way to do this? I need to find all "touching" roof-tiles and mark these for "hide"?

I could mark all those tiles with an unique ID when I place the building and hide/show based on that, but i would prefer a more flexible solution (if there are any).

Thanks!
Erik

Advertisement

Put a sensor, that is a rectangle of a tile size if you want. Place this sensor near the door, since the player can only enter from there. When the player passes over the sensor, the sensor will act like a light switch, turn on / off light, but in this case, turn on / off the roof.


if ( sensor.detect == true ) {
    building.roof.visible = !building.roof.visible;
}

but the problem is how do i find all roof-tiles belonging to that building? Buildings are not classes, they are just a section of the map that happens to have roof painted on those tiles.

I need like a spreading search to find all adjacent roof-tiles which are not 0 (meaning no roof for that tile).

Generally speaking, you will eventually want a bit more information about the world than just inside/outside. What I suggest may be a bit overkill for the specific question, but a subset could do what you are looking for.

I start by determining rules that I can use to make general categorization of the area. For instance, I might start by saying that any tile which is roofed and can be entered from a tile that is not roofed constitutes a transition between indoors and outdoors. Then I may say any roofed tile which connects to another roofed tile is considered part of the same indoor area. By running a relatively simple flood fill style algorithm I can uniquely identify various groups of tiles which are joined together to form a single indoor area.

Starting with something this simple, you can now find which tiles are connected interiors and only disable drawing of the roofs for those tiles. Expand on these rules and you can do things such as identifying special 'types' of rooms based on contents, internal divisions such as doors between room areas etc. The nice thing is that a fairly simple set of rules can categorize a relatively large number of things so if you have AI involved they can do relatively intelligent looking things when wandering around.

I've just solved this problem in my own game by having camera detect the best view distance (camera z position) based on what's directly above the player.

Trace a line vertically upwards from the player characters head (in my case just using the up vector) for a maximum height, in my case I chose 250 "units" in height. If you don't encounter any collision on your line trace before you get to 250 units, then your camera height is 250 units plus the players z coordinate. If you encounter a collision, e.g. a building roof, cave roof, tunnel, etc, then the cameras height above the player is the height of that obstruction minus a few pixels, also plus the players z coordinate.

This means you can always see something. Note though that if the roof is very low your field of view will also be very low so be aware of this when you design your level geometry.

This is a good solution as it will even work with multi storey buildings etc, without needing to add any metadata to your map.

Have fun!

I haven't yet implemented this in my game, but I intend to solve this by using rectangles to define a building's region, and using the rectangles to mask out anything from layers above the player, and then inverting the mask to darken areas outside the building.

The most fool-proof and reliable solution is to have a second "tile" map that just identifies the building covered by the roof tiles. All the tiles making up your Item Shop may then be marked as building 1 while all the tiles making up your Inn are marked as building 2 and so on. Open air is marked as not being a building, e.g. "building 0".

If the player is standing in a tile that has a building - that is, the building tile map has a non-zero value in it - then do not draw the ceiling tiles that match that building number.

This is also far more flexible than the other solutions. You can very easily mark up all building, you can split a single building into multiple areas (e.g. the hallway could be marked as 1 while the dining room is marked as 2, even though they're the same "building" conceptually). You can paint non-rectangular building easily. You aren't limited to trigger zones and hence will have fewer builds and an easier time modifying levels. You can mark camera-facing wall tiles in isometric views just like you can mark roofs.

It can be made even more flexible with very little work, too. If you want to have adjoining buildings where you see part of it in one place and all of it in another, making the building tilemap store bitmasks instead of ids; the logic then is to hide any overlay tile whose masks intersects with the mask of the tile the player is in.

If you have multi-story buildings, just split up each story its own set of tilemaps. Disable all rendering of any tiles on any layer at or above the player's layer matching the current building id.

Sean Middleditch – Game Systems Engineer – Join my team!

@Sean and @Servant, these are good solutions but they are kind of art heavy.

In my case my game is entirely developed just by me, and it is quite a large game so to fit it all in and release it I need to be smart in making the game identify most things itself without them having to be defined by an artist or programmer.

If you have a dedicated team of artists or a very simple level design you can manually mark out all your ceiling tiles etc, defining bitmasks for tile types etc.

It seems also that creating this game as a tile based isometric game generates much more art overhead, but this is usually the case with hand drawn isometric art...

Mine's not art heavy (no new art needs to be created), it is "developer heavy", in that the developer has to decide what locations to mark, but it'd be very little effort (depending on your map editing tools), and take very little memory. You'd store a few rects (four ints), I would guess it'd be about 4 to 20 bytes per house - less than a single KB for a large village. Virtually nothing. You could compact it further with short ints if necessary. Honestly not an area I'd focus memory optimization on, it's small enough with too little gains already.

From the rects you'd:

A) Detect if the player is within one set of rects (one building) vs another set

B) Generate a stencil mask or screen-space alpha mask from the

C) Use the mask to prevent (roof/whatever) overdraw of the building (or just a single room, if you prefer) that you are in.

D) Use the inverse of the mask to darken everything outside of the building - not entirely black, but say, 50% darker.

As mentioned, I haven't implemented this in my game yet, but I don't seen any reason why it'd be an excessive memory hog or performance bottleneck, other than the costs of the mask buffer.

I would suggest to find all roof tiles adjacent to the roof tile above the player via a simple flood fill style algorithm. Easy to implement and will only hide all tiles which touch other roof tiles which are connected to the roof tile above the player. If you want to separate roofs which have no spacing in between you would need to add additional criteria for the neighborhood check (e.g. same roof tile set or something similar).

But the easiest to do would be to ensure a space of at least one non-roof covered tile between two houses..

See here for the algorithm: https://en.wikipedia.org/wiki/Flood_fill

This topic is closed to new replies.

Advertisement