Page 1 of 1

Changing one of the methods in a LÖVE object

Posted: Wed Dec 12, 2018 1:50 pm
by wolfboyft
I made a deterministic maths library, and I want to make LÖVE's Transform objects use my sine and cosine algorithms for its rotate method. How can I do this?

I tried:

Code: Select all

local rotate = function(self, angle)
	-- TODO
	print("It worked.")
end

local originalNewTransform = love.math.newTransform
function love.math.newTransform(...)
	local new = originalNewTransform(...)
	new.rotate = rotate
	return new
end

local transform = love.math.newTransform()
transform:rotate(math.pi / 2)
OK, so I can't index Transforms because Transforms are userdata values. Metatables?

Code: Select all

local rotate = function(self, angle)
	-- TODO
	print("It worked.")
end

local transformMetatable = {
	__index = function(table, key)
		return key == "rotate" and rotate or rawget(table, "key")
	end
}

local originalNewTransform = love.math.newTransform
function love.math.newTransform(...)
	return setmetatable(originalNewTransform(...), transformMetatable)
end

local transform = love.math.newTransform()
transform:rotate(math.pi / 2)
I can't put metatables on userdata.

Help! What do I do? I thought maybe I could use FFI to replace the Transform class from LÖVE with a subclass that has its rotate method replaced (I could make my sine and cosine in C) but A: ffi.c.love doesn't exist and B: LÖVE is C++ and already compiled, so... yeah! Completely stumped.

Any help is appreciated! Thank you.

Re: Changing one of the methods in a LÖVE object

Posted: Wed Dec 12, 2018 2:22 pm
by pgimeno
You can't set a new metatable from Lua, but you can alter its existing metatable. The details get tricky, though, as the __index metamethod is already being used.

Code: Select all

local rotate = function(self, angle)
	-- TODO
	print("It worked.")
end

local originalNewTransform = love.math.newTransform
function love.math.newTransform(...)
	local obj = originalNewTransform(...)
	local mt = getmetatable(obj)
	local originalIndex = mt.__index
	getmetatable(obj).__index = function(table, key)
		local idx = mt.__index
		mt.__index = originalIndex
		local result = key == "rotate" and rotate or table[key]
		mt.__index = idx
		return result
	end
	return obj
end

local transform = love.math.newTransform()
transform:rotate(math.pi / 2)
print(transform.type())
I personally think that's an aberration. The C++ code is certainly not going to call your overriden methods. Making your own transform class in Lua is a saner approach.

Re: Changing one of the methods in a LÖVE object

Posted: Wed Dec 12, 2018 2:52 pm
by grump
Another way to do this is by altering the Transform table in the registry that holds all LÖVE classes.

Replacing the rotate function globally, for all calling Lua code:

Code: Select all

debug.getregistry().Transform.rotate = function(self, angle)
	print("It worked.")
end

love.math.newTransform():rotate(math.pi)
This only solves the "I want to replace this function" problem though, which is not enough to reach your goal. The actual math is not happening in the rotate function.

I agree with pgimeno, better roll your own Transform implementation. setMatrix and getMatrix can be used to convert between LÖVE's and your own transforms.