The grid system
To keep things simple and dynamic, I decided to use a grid system as it is known from an infinite number of other rp- and strategy-games.
Simply put: every tile of the grid represents a relevant game state, can be interacted with and has a visual representation attached, in the form of a prefab model, according to it's roomType and location relative to other tiles of the same room.
Especially for navigation purpose, this system is the most easy and simplistic way if you plan to move objects around and build facilities inside it.
A similar approach can be found in Maia where the developers decided to use a grid system for structural room placement and a freeform placement system where you can place objects in a room just where you want them to and rotate them around. The latter needs additional collision and pathfinding systems who are able to generate a path through the room furniture, possibly via the navigation mesh or another similar system.
The strict grid-system on the other hand, allows for a simple A* implementation and a more direct modification of the grid and it's contents.
Ships may have multiple etages, connected through elevator or stair tiles. The player navigates between the etages via Page-Up/Page-Down keys and only the topmost current etage is visible, in addition to the etages below.
As the question arises how to implement the roomBuilder and how to include the different etages, the solution was to limit the game to one active etage (the currentEtage) and lock the etage during the room building process.
The room builder
As per design goal, the spaceship is defined through a hull (copper-colored part of the image) and the inside, wall blocks in grey which may become room tiles where objects and pawns are part of.
The player carves rooms out of the grey "clay" with the room blueprint system and once he is happy with the blueprint, and the blueprint is valid, the "real" grid gets modified to match the new room form.
Rooms must be separated from each other with at least one wall-tile and must connect to adjacent rooms with at least one door. Due to the way tiles are designed and I don't want to overcomplicate things, rooms must have a minimum size of 2x2 and depending on the room type, additional constraints might apply.
Before anything could be done with the building and tile system, the decision had to be made how to separate rooms and tiles.
Basically, there are two ways to handle different rooms on the grid which are representet by single tile prefabs:
The left scheme shows two rooms being connected directly without any separating space between them. The separation is detected via the roomType or roomId attribute of the according tiles. The generator sees that tile (2/4) is not the same roomType as tile (2/5) and consequently assigns both grid tiles a wall prefab to visually separate the two rooms and advise the AI Path director, that a pawn (movable objects like crewmen and enemies) can not traverse from (2/4) to (2/5).
This way, space on the grid is used very efficiently. Two rooms with the width of 2 only need 4 tile spaces to exist. Especially with smaller spaceship vessels in mind, this would have been a good way to handle small grids without wasting space for separation walls.
The biggest problem however is, that you are limited on how much decoration you can put on the walls. Like for example pipes (in red) or stronger walls can't simply be attached without having to worry about the space left and if pawns and objects can even be placed on that tile without colliding with it. I would have to check each passable tile, if certain actions can be done with it, which is contrary to the need to use space efficiently. This created more issues with design limitations as it would have improved space efficency.
The right scheme demonstrates, that a separating wall tile has the advantage of concealing inward structures and decorations without rendering the tile unusable. Up to one half of tileWidth can each decorative tile structure extend into the walls, creating a more spaceship feel and allowing a wide variety of structural designnuances known from other spaceships:
The most important part is, that you don't need to check of tile usability other than to check, if tile (x/y) is a wall tile (=> unusable) or a floor tile, in which case it can be part of object placement or pawn interaction.
Also, the room blueprint tool may check for each room blueprint tile, if the blueprint tile sits on top of a wall tile (then it's valid) and each adjacent tiles are wall tiles as well, otherwise the blueprint would violate the rule, that at least one wall tile needs to separate the rooms.
The room style manager
As I wanted to include multiple races and spaceship styles, similar to FTL, there was a need for a system which allows for a solid tile distribution without much headache, which can be expanded as needed.
Basically, the game knows what fraction the player is, what type of room wants to be displayed, for example: Corridor, Medbay, Shipcontrol, Engine room, etc.
So I created the RoomStyleFactory class; A singleton-styled Entity, which reads all available xml files from a special roomStyleDefinitions directory, and sets up a list with all possible combinations of Race and RoomType.
Of course, these presets need to be part of the game before the Start, therefore the xml definitions simply contain a group for each FRACTION_NAME, containing entries for each ROOM_TYPE, containing strings for each tile, which points to the prefab object.
This allows for possible Modding and DLC extensions without having to modify code inside the relevant classes. New fractions could easily be added via new resource packages and one xml file for the fraction.
When the method
public RoomStyle RoomStyleFactory.GetRoomStyle(Fraction fraction, RoomType type) gets called, it returns a RoomStyle Object, which contains the Deserialized strings from the xml definition and offers methods for each tile type to get an instanced GameObject of the needed tile into the game.
After the room builder is implemented and working, work on the Objects and Pawns will start.