swarm-game / swarm

Resource gathering + programming game
Other
837 stars 52 forks source link

Add spawning robots to output of `WorldFun` #29

Open byorgey opened 3 years ago

byorgey commented 3 years ago

[Note, I no longer think this original issue description is a good idea, but leaving it here for context. Read all the way through the comments below to see how my thinking has changed.]

Right now a World is specified by a WorldFun, defined as

type WorldFun t e = Coords -> (t, Maybe e)

This is just a function that specifies a terrain value and possible entity for every cell. However, this has several limitations. For one thing, it is difficult to specify things that should be coherent across multiple cells (i.e. structures). For another, if we want the world to contain creatures that move around (implemented as system robots), there is no good way to specify when they should spawn.

The implementation of Worlds already uses a notion of tiles for efficiency, and we can build on this to solve the limitations above. Instead of specifying a world cell by cell, we specify it tile by tile. That is, a WorldFun will now be something like

type WorldFun t e = TileCoords -> (TerrainTile t, EntityTile e, [Robot])

which says that the world function takes as input the coordinates of a tile and generates an entire tile's worth of terrain and entities all at once, in addition to some robots which should spawn when this tile is loaded. When calling the function, it will build tiles first by filling in initial values based on a Coords -> (t, Maybe e) function as before, but then has the opportunity to further modify them, e.g. by deciding where to draw in certain structures.

byorgey commented 2 years ago

As a first step, we should just refactor the existing game to work this way, but generate exactly the same world (with no robots or structures) that we currently do.

byorgey commented 2 years ago

Maybe we should keep the old type WorldFun t e = Coords -> (t, Maybe e) (since we will certainly still want that type) and define type TiledWorldFun t e = TileCoords -> (TerrainTile t, EntityTile e, [Robot]). Then as a starting point we can define

simpleTiledWorldFun :: WorldFun t e -> TiledWorldFun t e

which just fills in everything according to the WorldFun. Maybe we can also make TiledWorldFun a Monoid such that the lists of robots compose and entities and tiles on the right overwrite ones on the left. We would have to make a special distinguished "empty terrain" value to serve as the identity. EntityTiles will already contain Maybe es so Nothing can serve as the identity. Given this monoid, we can start with a base generated by a WorldFun and then layer on things like structures etc.

byorgey commented 2 years ago

Here is another idea which is hopefully both simpler and more flexible: let's just keep the WorldFun type similar to how it is now, but to the output we can add [Robot] (i.e. WorldFun t e = Coords -> (t, Maybe e, [Robot])), describing robots which should spawn when the given cell is first loaded.

byorgey commented 1 year ago
  • As for spawning robots, we know when a particular tile is first loaded, and at that time we can pay attention to all the [Robot] values. Otherwise, we simply ignore them.

I suppose this would happen in the loadRegion function in Swarm.Game.World, which would probably need to be modified to return any newly spawned robots as well?