How to split systems in multiple files
Gladius1 opened this issue · comments
Hello
First of all. Great work. I really like to code with polymorph.
I'm working on a small project. Right now it's about 300 lines long. I'd like to split it into multiple files because it's clear that it will grow some more. Unfortunately polymorph is giving me some issues.
Consider the following example.
main.nim
import polymorph as pl
import system_a
import system_b
pl.commitSystems "runSystems"
generateA("Hello")
generateB("World")
for i in 0 ..< 4:
runSystems()
system_a.nim
import polymorph as pl
pl.register defaultCompOpts:
type
A = object
value: string
pl.makeSystem "A", [A]:
all:
echo item.a.value
pl.makeEcs()
proc generateA* (value: string) =
let
a = newEntityWith(
A(value: value)
)
system_b.nim
import polymorph as pl
pl.register defaultCompOpts:
type
B = object
value: string
pl.makeSystem "B", [B]:
all:
echo item.b.value
pl.makeEcs()
proc generateB* (value: string) =
let
b = newEntityWith(
B(value: value)
)
Is there another place where I can call makeEcs() so that the newEntityWith() makro is available for both generateA() and generateB()?
I'm very new to Nim btw. Maybe this is an issue with the Nim language?
Hi @Gladius1,
Each makeEcs
in your example will generate an independent, sealed ECS that can't interact with the others. To seal them into a single ECS, remove the other makeEcs
and place one in main.nim
before commitSystems
.
import polymorph, system_a, system_b
makeEcs() # Can see both a and b components/systems
commitSystems "runSystems"
generateA("Hello")
generateB("World")
for i in 0 ..< 4:
runSystems()
Is there another place where I can call makeEcs() so that the newEntityWith() makro is available for both generateA() and generateB()?
The missing key is the onEcsBuilt
macro. This queues code to be inserted after the next makeEcs
has finished, so you can write procs, init stuff, and other code that uses the ECS there.
I'd like to split it into multiple files because it's clear that it will grow some more.
For larger projects, it's worth creating the ECS in a separate module (e.g., ecs.nim
) which imports the component and system definitions, then runs makeEcs
. This module can then be imported wherever you want to use or run the ECS.
As we're working across modules, the component types and fields also need to be annotated with *
so they can be seen outside the module.
The following example shows how this might look:
## system_a
import polymorph as pl
pl.register defaultCompOpts:
type
A* = object
value*: string
pl.makeSystem "A", [A]:
all:
echo item.a.value
onEcsBuilt:
proc generateA* (value: string) =
let
a = newEntityWith(
A(value: value)
)
## system_b
import polymorph as pl
pl.register defaultCompOpts:
type
B* = object
value*: string
pl.makeSystem "B", [B]:
all:
echo item.b.value
onEcsBuilt:
proc generateB* (value: string) =
let
b = newEntityWith(
B(value: value)
)
## ecs
import polymorph, system_a, system_b
export system_a, system_b # Export component types
makeEcsCommit "runSystems" # makeEcs() + commitSystems("runSystems")
## main
import polymorph, ecs
generateA("Hello")
generateB("World")
for i in 0 ..< 4:
runSystems()
Hello
World
Hello
World
Hello
World
Hello
World
Alternatively, if you don't want to use onEcsBuilt
for your procs, you can put them in another module that imports ecs
:
## utils
import polymorph, ecs
proc generateB* (value: string) =
let
b = newEntityWith(
B(value: value)
)
proc generateA* (value: string) =
let
a = newEntityWith(
A(value: value)
)
## main
import polymorph, ecs, utils
generateA("Hello")
generateB("World")
for i in 0 ..< 4:
runSystems()
I'm very sorry, I totally forgot about this.
Your answer was really helpful. Many thanks.