Page 1 of 2
Referencing object functions?
Posted: Thu Nov 16, 2017 10:15 am
by ivan
Greetings, I'm the process of porting a few games to Love2d and my question is:
How do I get a reference to object functions like "body.getPosition" or "joint.getAnchors".
What I mean is, I need a reference to the C-functions, prior to creating any objects at all.
For example:
Code: Select all
local Body_getPosition = ?
local body = love.physics.newBody(world, 0, 0, "dynamic")
local x, y = Body_getPosition(body)
Basically, I'm trying to localize the references to these functions, PRIOR to creating an instance of the object itself.
Thanks for taking a look!
Re: Referencing object functions?
Posted: Thu Nov 16, 2017 11:15 am
by grump
I don't think it's possible. Body is not a table, it's userdata. It does not exist in Lua space before the call to newBody. ffi tricks wouldn't work either, because ffi can't access C++ declarations, only C.
Re: Referencing object functions?
Posted: Thu Nov 16, 2017 11:22 am
by ivan
grump wrote: ↑Thu Nov 16, 2017 11:15 am
I don't think it's possible. Body is not a table, it's userdata
Are you sure? I've used this technique with the "tolua" binder and it works for userdata too, but I don't know how it's setup in Love2d.
Re: Referencing object functions?
Posted: Thu Nov 16, 2017 11:34 am
by grump
No, I'm not sure. But I got curious and wrote this function to search the whole environment for identifiers:
Code: Select all
local function searchVar(name, scope, scopeName)
local stack, path = {}, {}
local function descend(var, name, search)
if stack[var] then return end
stack[var] = name
table.insert(path, name)
for key, v in pairs(var) do
if key == search then
print(table.concat(path, ".") .. "." .. tostring(key), v)
end
local meta = getmetatable(v)
if meta then
descend(meta, key, search)
end
if type(v) == "table" then
descend(v, key, search)
end
end
table.remove(path, #path)
stack[var] = nil
end
return descend(scope or _G, scopeName or "_G", name)
end
returns nothing.
returns functions in love.audio, mouse, window and touch, but not physics.
Code: Select all
body = love.physics.newBody(love.physics.newWorld())
searchVar("getPosition")
additionally returns getPosition in the body instance.
So at least I'm sure it does not exist in Lua space.
Re: Referencing object functions?
Posted: Thu Nov 16, 2017 11:39 am
by ivan
Yea, that's too bad, a simpler test:
Code: Select all
local w = love.physics.newWorld()
local b1 = love.physics.newBody(w, 0, 0)
local b2 = love.physics.newBody(w, 0, 0)
print(b1.getPosition,b2.getPosition)
assert(b1.getPosition==b2.getPosition)
Suggests that the function references are the same for each body instance, so it should be possible in theory.
Re: Referencing object functions?
Posted: Thu Nov 16, 2017 11:44 am
by Nixola
Why do you need a reference to the function before creating any object at all? Can't you just create a dummy body, get a reference, dispose of the body, then do everything you need to do?
Re: Referencing object functions?
Posted: Thu Nov 16, 2017 11:48 am
by ivan
Regarding your search function - perhaps boot.lua removes these function references...
or perhaps they don't exist until at least one body is created.
Nixola wrote: ↑Thu Nov 16, 2017 11:44 am
Why do you need a reference to the function
before creating any object at all? Can't you just create a dummy body, get a reference, dispose of the body, then do everything you need to do?
Yep, that would be one way to do it.
PS. On a further note, I found a small redundancy in physics API:
body:setMass(mass) and body:setMassData(x,y,mass,inertia)
could be merged into:
body:setMassData(mass, x,y, inertia) -- where the last 3 arguments are optional
Re: Referencing object functions?
Posted: Thu Nov 16, 2017 12:25 pm
by grump
ivan wrote: ↑Thu Nov 16, 2017 11:48 am
or perhaps they don't exist until at least one body is created.
Sure, that's what I said before.
I looked at the C++ code, and while I don't claim to fully understand what is going on after looking at it for 5 minutes, it does seem like there is no table representation of the Body
class (or for any other object type created through the love API), only for instances/objects. The instance gets pushed with luax_pushtype, and the documentation of that function says:
Code: Select all
* Pushes a Lua representation of the given object onto the stack, creating and
* storing the Lua representation in a weak table if it doesn't exist yet.[/code
Re: Referencing object functions?
Posted: Sun Feb 25, 2018 10:48 am
by grump
ivan wrote: ↑Thu Nov 16, 2017 10:15 am
For example:
Code: Select all
local Body_getPosition = ?
local body = love.physics.newBody(world, 0, 0, "dynamic")
local x, y = Body_getPosition(body)
Still looking for a way to do this? I seem to have stumbled upon a way to achieve what you want while I experimented with
debug.getregistry:
Code: Select all
local Body_getPosition = debug.getregistry().Body.getPosition
local body = love.physics.newBody(love.physics.newWorld(), 23, 42, 'dynamic')
local x, y = Body_getPosition(body)
I just remembered this thread. Maybe this is still useful to you.
Re: Referencing object functions?
Posted: Sun Feb 25, 2018 1:30 pm
by ivan
Great find Grumps, I've used your solution since it's much cleaner than the "dummy" option mentioned before.
I know it's not considered proper, but I like to add extra functions to box2d objects, for example "wrapping" prismatic joints so they loop:
Code: Select all
local reg = debug.getregistry()
function reg.PrismaticJoint:setJointTranslation(t2)
-- note affects the second body only!
local _, b = self:getBodies()
local x, y = b:getPosition()
local _, _, x2, y2 = self:getAnchors()
-- offset anchor by the body's position
x2, y2 = x2 - (x2 - x), y2 - (y2 - y)
-- find the origin, where translation = 0
local t1 = self:getJointTranslation()
local nx, ny = self:getAxis()
local ox, oy = x2 - nx*t1, y2 - ny*t1
-- move the body to desired translation
b:setPosition(ox + nx*t2, oy + ny*t2)
end
PS. Hope you don't mind, but I've added your nickname to the game's end credits.