I’m a big fan of data in transparent formats that allow or encourage hand editing by humans. For Triverse, I’ve imposed the constraint that all ships and maps have a textual representation that captures all information about them through the arrangement of parts.
Other metadata might be useful, such as weapon group definitions or forward direction, but I’m hoping to generate reasonable defaults or possibly to cache user-customized weapon groups for layouts on the client. (Actually, since I first wrote this, I’ve been thinking more in the direction of disallowing arbitrary forward direction and forcing it to be a function of layout.)
A small ship:
/.\p/.\ \i/.\i/ \u/.\o/.\u/ \u/u\u/
This form is also acceptable (slash required):
. p . i . i u . o . u u u u/
And the resulting ship in-game:
A larger ship:
/.\p/.\./.\p/.\ /.\./o\./u\./o\./.\ /i\./.\u/ \u/.\./i\ /.\./o\u/ \g/o\g/ \u/o\./.\ \./.\./u\ /u\./u\ /u\./.\./ \i/.\o/.\./p\./.\o/.\i/ \./.\i/ \i/.\./
And the result:
Each letter represents a type of part. Only one slash must be present to define cell orientation, but I find it helpful in visualizing the ship to include them throughout. This format was not obvious; I went through several other variations before settling on it. I’ve also considered using images to store large maps, which are stored the same as ships internally but would be wasteful in a text format without compression. Margins are irrelevant; they can be trimmed and would have no significant performance impact.
Part types are read in and mapped to a part definitions using a table. This table defines character codes (‘i’, ‘u’, ‘.’, ‘o’, etc) and attributes of parts, including energy requirements, weapon behavior, and any other information related purely to gameplay logic. Other info, such as visuals and audio, are decoupled from these definitions and placed in a separate table. I can imagine modding scenarios where one or both tables could be easily swapped out or added to. However, this use of character codes does impose a convention on custom tables if a modder wants to support existing ships: if a thruster is suddenly mapped to a weapon, the ships wouldn’t work as intended.
Creating this visual serialization is one of the best things I’ve done for testing and development in general. I implemented it early in the project, and it makes defining test cases incredibly easy and allows for quick comparison of results. For example, code to rotate a grid (I’ll cover the math in another post):
let cg = grid @" /i\./u\ /u\./i\ \./.\o/.\i/u\i/.\o/.\./ \i/.\./u\ /u\./.\i/ \u/.\./o\./.\u/ \./p\./p\./ " for i in 0 .. 6 do let rot = GridVector.Rotation i cg.RotateTriGrid rot |> formatTriGrid |> printf "%s\n\n"
And the output:
/i\./u\ /u\./i\ \./.\o/.\i/u\i/.\o/.\./ \i/.\./u\ /u\./.\i/ \u/.\./o\./.\u/ \./p\./p\./ /.\i/.\ \u/o\./i\ /i\./.\./u\ /i\u/ \u/.\./.\ /.\u/o\./.\u/.\o/.\p/ \i/.\./i\./u\./.\p/ /i\./.\i/.\u/.\./p\ \./u\o/.\./u\./o\./p\ \i/u\ /u\./.\./ \i/.\./.\u/ /u\o/.\i/ \./i\./ /.\p/.\p/.\ /u\./.\o/.\./u\ /i\./.\u/ \u/.\./i\ /.\./o\./i\u/i\./o\./.\ \i/.\u/ \u/.\i/ /p\./.\u/.\i/.\./i\ /p\./o\./u\./.\o/u\./ \./.\./u\ /u\i/ \u/.\./.\i/ \i/.\o/u\ \./i\./ /.\i/.\ /i\./o\u/ /u\./.\./i\ /.\./.\u/ \u/i\ \p/.\o/.\u/.\./o\u/.\ \p/.\./u\./i\./.\i/ /i\./u\ /u\./i\ \./.\o/.\i/u\i/.\o/.\./ \i/.\./u\ /u\./.\i/ \u/.\./o\./.\u/ \./p\./p\./
I imagine copy+paste as a useful way to get ships in and out of the game in a sandbox mode, but Unity3D does not expose any cross-platform way to access the clipboard. Dragging + dropping files into a game window would also be convenient. For a browser deployment, I’ll probably have to use a text box outside the game and use Unity’s interop to access it.
Working with text this way, and especially getting rotation working, makes me ponder roguelike potential here. Making time and space discrete would avoid a lot of work, and there might be a better overall game along those lines. Might be fun to prototype, but for now I’m still going down the original path of a real-time continuous world.