TeamPorcupine / ProjectPorcupine

Project Porcupine: A Base-Building Game...in Space!
GNU General Public License v3.0
484 stars 278 forks source link

Pressure and depressurization #1286

Open Skalicon opened 8 years ago

Skalicon commented 8 years ago

So I am looking at starting to implement a pressure system that calculates room pressure based on the gasses in the room.

This will allow us to implement things like sudden depressurization of a room when an airlock is open which would apply physics to loose objects and characters sucking them out of the airlock, and cause damage to fixed objects like the airlock and possibly surrounding walls, or furniture in the room depending on the Delta pressure.

I'd love feedback on the idea or additional things that should be taken into consideration.

Thanks.

koosemose commented 8 years ago

The first part is already in Room code, GetGasPressure() for the total pressure (measured in atmospheres) and GetGasPressure(string) for a specific gas' pressure.

Currently depressurization and such things is rather naively done, when two rooms are joined (such as when a wall between them is broken) both end up getting the same gas mix (from one of the two rooms), and of course if it's outside it gets set immediately to 0 gasses.

Skalicon commented 8 years ago

Okay, I've done some investigation into what we currently have and I have considered a few options. I'd like some input on the solution I have come up with. It does mean that I would have to completely rewrite the current gas code, but there isn't much there yet anyway.

Tiles will have a size limit which can be filled, either by gas water or possibly solid objects but at this point I don't think I'll worry about that. Pressure on a tile is determined by how much matter is in that tile * properties of that matter. Likely pressure would be stored on a room by room basis.

Room enclosure furniture will get a force rating which is the amount of force they can withstand before being broken.

When a room enclosure element becomes unsealed by either breaking or opening this triggers a depressurization event.

When a depressurization event occurs the rooms involved will be checked to see a pressure difference. The high pressure room is considered "inside" and the tiles adjacent to the breach inside the room are checked for pressure equalisation, where the tile will subsequently check it's neighbour tiles for a difference in pressure and then it will try and offload it's pressure equally to all tiles that have lower pressure. This will continue radially outwards into the "inside" room to cascade the movement of pressure. At this point we do the opposite cascade outwards from the breach into the "outside" room.

To prevent infinite splitting of pressures down to very small floats all gas pressure will be converted to INTS.

The amount of pressure offloaded will be based on its speed which will be calculated by pressure with a cap of the speed of sound. This will determine how we push characters or items in this tile.

The edges of the map will always be 0 pressure so this will allow all outside space to filter off it's pressure to any map edge tile.

This is still quite a high level concept of the implementation, I need to look at the speed of cascades and figure out if it will be a cheep enough operation to get away with using on intervals. If not we might need to fake a tile by tile pressure system and operate on room or sector scale to make it work.

The benefits of the system that I proposed are that it should be more realistic and granular, so we can properly simulate multiple simultaneous events. The air slow would also move realistically where as the system equalizes it becomes less violent and the size of the breach would have a real and direct impact in the flow of gas and speed of depressurization.

koosemose commented 8 years ago

I'm glad you're keeping in mind potential simplifications, in case needed for performance reasons, though you should additionally keep in mind that even if it performs well, if it pushes it to the edge of "performing well" it's taking "performance space" away from other systems that might need to be implemented in the future (though "space" might be opened up by improvements in other areas that are in the works as well).

Also when dealing with things of this nature (where some people may not understand some of the details) be sure to comment on what the numbers actually mean. Also be aware of what else uses the current gas system and may need changed (leaks through doors, and airlock doors when they open, and the O2 Generator. In the case of the O2 generator it currently produces at a rate roughly balanced based on a reasonable time to fill a 5x5 room, currently measured in atmospheres per tile, where 1 is 1 atm in one tile space).

Skalicon commented 8 years ago

I hate the limited functionality of this on phones. Regarding optimization there is actually a lot we can do. We should only do any of this stuff on an actual depressurization event, so things like adding or removing gas from a room can be split across all tiles in that room since the simulation of filling the room, at this point, is not significantly important. So a depressurization event only fires on breach or airlock open, which could create some weirdness if room enclosure furniture gets removed in an unexpected way, but we can handle that on a case by case basis.

The main concern is that when an event occurs in a large room, or to the outside, which is really just a large room, it will be too much to do per tick.

However, theoretically since all tiles in a room prior to the event are equal pressure each row radially outwards from the event, excluding the tiles on each end of the row, behave exactly the same. So we can save a lot of processing power there and that should even mean that the size of the room doesn't really effect the performance since it will always be 3 calculations regardless of row size, start end, all middle tiles, end tile. And this is true also for each row after the first row in the internal room. If I am correct about this it would probably be very quick and efficient.

pderuiter77 commented 8 years ago

This is the same method i suggested in other thread for heat transfer. When a tile updates its temperature / pressure, it signals the neighboring tiles to do the same on the next tick (or every 2 ticks, whatever). That should give a nice cascade effect.

About the speed : I would suggest just looking at the pressure change, and when that reaches a threshold, move the furniture. No need for complicated calculations. If pressure delta is more than i.e. 0.5, the furniture gets moved 1 tile.

Skalicon commented 8 years ago

The cascade should happen technically at the speed of sound, which for the scales we are dealing with should be basically instant. So I think the full cascade should happen each tick and the Delta change is capped at what can change at the rate of the speed of sound. But doing things over multiple frames might be required for distributing the load of the request.

pderuiter77 commented 8 years ago

And to give players a chance to react. It's no fun to see your character and all the furniture be blown outside in 2 frames :)

Tranberry commented 8 years ago

@pderuiter77 isn't that the definition of ¡FUN!? 😉

pderuiter77 commented 8 years ago

Haha, this isn't DF...yet :)

abackwood commented 8 years ago

I think a room draining slow enough for the player to react in real time will just look silly. At that speed no furniture would definitely move either. I see two ways to let the player deal with decompression:

1) If a room breaches, the game is auto-paused and focused on the event. The player then can give orders in that time freeze dealing with it before unpausing.

2) The player prepared for this by building the base to survive this, probably by putting airlocks in that compartmentalise the base. The player could be helped in this by automatic character behaviour, auto-locking doors, etc.

I like the second option myself. Good base design is an integral part of base-building games and that reinforces it.

vogonistic commented 8 years ago

We need teachable moments to show the user how thick walls needs to be.

I'm ok with suspending reality for moving slower, or doing an animation for the event where the user is locked out.

I worry the pressure and heat system discussions are aiming for a realism that doesn't help make the game more fun and at a cost of updating a lot of tiles every update.

Isn't the depressurization event almost an entirely different thing from normalizing pressure on tiles, or does the gas moving from one tile to another also have checks to see if they move things?

pderuiter77 commented 8 years ago

Depends how you handle. As i said before, calculations can be as easy as just the diff between tiles. someone is already working on the system, so prformance problems should be easily discovered early on.

A depressurization can be handled like a normal pressure update. So each tick the door tile halves its pressure. Next tick the neighboring tiles update..and so on. If performance really is an issue , you could write special code, but i hope it isnt needed.

vogonistic commented 8 years ago

I've been assuming that the cost of an individual calculation is very low. I'm concerned with the amount of tiles it touches on each update.

I meant a unintentional rapid disassembly of a containing furniture (wall, door, rock, window) so that all the pressure is escaping out into space through a large opening.