Simulation Performance Comparison, GDScript vs Nim #229
Replies: 3 comments 5 replies
-
Interesting topic. Default Score: 190 1. Optimize compile optionsScore: 625 It should not be used during development as it will invalidate all debugging information and safety checks. # config.nims
--define: release
--define: danger
--opt: speed 2. Avoid to use DictionaryScore: 200 (If do not For your project, you can replace it with type MainNim* {.gdsync.} = ptr object of Node2D
...
forces_to_apply: seq[Vector2] method ready(self: MainNim) {.gdsync.} =
...
self.forces_to_apply.setLen(self.agent_count) # Dictionary: Agent Node -> Accumulated Force Vector
self.calculation_times = newTypedArray[uint64]() method physics_process(self: MainNim; delta: float64) {.gdsync.} =
# --- Apply Forces (O(N)) ---
# This part is outside the timed section, as we primarily want to measure the calculation cost.
for i, agent in self.agents:
# Check if the agent instance is still valid before calling method
if is_instance_valid(variant agent):
# if is_instance_valid(agent) and agent.has_method("apply_separation_force"):
let force:Vector2 = self.forces_to_apply[i]
agent.apply_separation_force(force, delta) 3. Avoid dispatching physics_processScore: 198 AgentNim is an object that appears hundreds in one scene, right? # gdagentnim.nim
proc physics_process*(self: AgentNim; delta: float64) =
... # gdmainnim.nim
method physics_process(self: MainNim; delta: float64) {.gdsync.} =
if self.agents.len == 0:
echo "Empty agents!"
for agent in self.agents:
agent.physics_process(delta)
... Total (1 + 2 + 3) Score: 642 |
Beta Was this translation helpful? Give feedback.
-
Hi, and thanks for this detailed tutorial. I think it would do this extension really well, if it had a section where typical GDScript code can be compared to typical Nim code. |
Beta Was this translation helpful? Give feedback.
-
I will note the optimization method I recently discovered. Misc: Use position as much as possible and avoid using global_position. Main topic: Referencing Godot object properties incurs a significant cost, so for properties such as position that are referenced multiple times per frame, it is faster to define virtual properties and synchronize them as needed, similar to the virtual DOM in HTML. type MyNode* {.gdsync.} = ptr object of Node3D
p: Vector3
proc pushProps(self: MyNode) =
self.position = self.p
proc pullProps(self: MyNode) =
self.p = self.position
method ready(self: MyNode) {.gdsync.} =
self.pullProps()
method process(self: MyNode; delta: float64) {.gdsync.} =
if PropsCanBeChangedFromExternal:
self.pullProps()
# process...
self.pushProps() |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm currently exploring the performance characteristics of GDScript for simulation-style games in Godot, particularly when dealing with a large number of moving objects. This led me to wonder if leveraging a compiled language like Nim via GDExtension could offer significant performance gains.
As a learning exercise in both Nim and GDExtension, I've created a simple 'boids' simulation to compare the performance. You can see my initial findings and the code here.
Interestingly, while Nim showed a considerable advantage with 180 agents, the performance became quite similar with 190. Given that this is a learning project and my implementation is likely far from optimal, I'm curious if anyone has insights or suggestions on how to further optimize the Nim implementation for better performance?
GDScript version on 180 agents:

Nim version on 180 agents:

thanks to @panno8M for updating the extension, with the rotation working towards the velocity angle, the boids look better :)
Beta Was this translation helpful? Give feedback.
All reactions