GoPositionSetter Native extension
Fast way to update position for thousands of game objects.
30000 bunnies 53.71 fps
30000 bunnies 67.69 fps
Tested on my PC.
What changed and why it’s faster
function update(self, dt)
bunnymark.update()
local bunnies = bunnymark.bunnies
for i=#bunnymark.bunnies,1,-1 do
local bunny = bunnies[i]
bunny.velocity = bunny.velocity - 1200 * dt
local p = bunny.position
p.y = p.y + bunny.velocity * dt
if p.y < 50 then
p.y = 50
bunny.velocity = -bunny.velocity
end
--go.set_position(p, bunny.id)--this is used in update single
end
self.position_setter:update() --this is used in go_position_setter
label.set_text("#label", ("Bunnies: %d FPS: %.2f. Click to add more"):format(bunnymark.get_bunny_count(), bunnymark.get_fps()))
end
It is faster because:
- It uses one C++ call instead of thousands of go.set_position calls.
- It avoids some checks. You as the developer guarantee that the vector and gameobject are valid and available.
//This is how go.set_position works:
static Instance* ResolveInstance(lua_State* L, int instance_arg)
{
ScriptInstance* i = ScriptInstance_Check(L);
Instance* instance = i->m_Instance;
if (lua_gettop(L) == instance_arg && !lua_isnil(L, instance_arg)) {
dmMessage::URL receiver;
dmScript::ResolveURL(L, instance_arg, &receiver, 0x0);
if (receiver.m_Socket != dmGameObject::GetMessageSocket(i->m_Instance->m_Collection->m_HCollection))
{
luaL_error(L, "function called can only access instances within the same collection.");
}
instance = GetInstanceFromIdentifier(instance->m_Collection->m_HCollection, receiver.m_Path);
if (!instance)
{
luaL_error(L, "Instance %s not found", lua_tostring(L, instance_arg));
return 0; // Actually never reached
}
}
return instance;
}
int Script_SetPosition(lua_State* L)
{
Instance* instance = ResolveInstance(L, 2);
dmVMath::Vector3* v = dmScript::CheckVector3(L, 1);
dmGameObject::SetPosition(instance, dmVMath::Point3(*v));
return 0;
}
//this is how go_position_setter.update() works:
//no checks. Just SetPosition to the instance
void PositionSetterUserdata::update() {
for (int i = 0; i < instances.Size(); ++i) {
InstancePositionData instancePositionData = instances[i];
dmGameObject::SetPosition(instancePositionData.rootInstance, dmVMath::Point3(*instancePositionData.position));
}
}
How to use
- Create a go_position_setter.new() in your collection
self.position_setter = go_position_setter.new()
- Add bunny to position_setter
self.position_setter:add(bunny.id, bunny.position)
- Update bunny.position
bunny.position.y = bunny.position.y + bunny.velocity * dt
- Update all positions
self.position_setter:update()
Credits
Based on Defold bunnymark test GitHub - britzl/defold-bunnymark: Defold bunnymark test
Bunny graphics from PixiJS Bunny Mark

