About a year ago I was curious about building an ECS-based game engine with world simulations like in dwarf fortress, but obviously at much smaller scale while playing Starfield. Something cool started to materialise after tinkering so I thought why not turn it into a space-sim roguelike with a simulated living world.
I use swift because it gives me fantastic devex with all its great type inference and macros + raylib gives me cross platform input handling / rendering and window management.
C-interop setup is basically instant - you point compiler to c headers and the API becomes immediately visible on swift side
As for swift ergonomics, I particularly love that I can now write very readable code, like:
a lot of cool-looking stuff in my ECS is supported by Swift parameter packs; however, once you start using them a lot you find limits pretty soon.
One example: the following wouldn't compile in swift:
func query<each T, each K>(
_ body: ((repeat each T), (repeat each K)) -> Void
) { ... }
so you kinda work around it with extra type wrappers but this looks ugly - I've been using macros to hide some of the ugliness away xD
edit: the example is oversimplified just to show the point - in this example compiler can't really tell where T ends and K starts, so its logical; but I had more complex cases where a human would've been able to infer types correctly
About a year ago I was curious about building an ECS-based game engine with world simulations like in dwarf fortress, but obviously at much smaller scale while playing Starfield. Something cool started to materialise after tinkering so I thought why not turn it into a space-sim roguelike with a simulated living world.
I use swift because it gives me fantastic devex with all its great type inference and macros + raylib gives me cross platform input handling / rendering and window management.
C-interop setup is basically instant - you point compiler to c headers and the API becomes immediately visible on swift side
As for swift ergonomics, I particularly love that I can now write very readable code, like:
> world.addRelation(attacker, Attacks.self, target) > world.addRelation(player, Owns.self, sword)
or
> for (entity, position) in world.query(Position.self).with(Health.self, Velocity.self).without(Enemy.self) {}