Referencing object functions?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Referencing object functions?

Post 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!
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Referencing object functions?

Post 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.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Referencing object functions?

Post 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.
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Referencing object functions?

Post 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

Code: Select all

searchVar("Body")
returns nothing.

Code: Select all

searchVar("getPosition")
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.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Referencing object functions?

Post 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.
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: Referencing object functions?

Post 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?
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Referencing object functions?

Post 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
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Referencing object functions?

Post 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
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: Referencing object functions?

Post 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.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Referencing object functions?

Post 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.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot], Google [Bot] and 6 guests