Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Metatable Making a Function Nil?

I started learning Metatables from a YouTube series on Lua this morning and I have run into a peculiar error while practicing Metatables. I made an advanced table previously and it had worked but it appears that the Metatable has caused it to break and I can't tell why. It prints out the coordinates and names correctly and then breaks when it attempts to connect to the move function. An explanation of what is going on and how it could be fixed would be greatly appreciated.

Error:

Workspace.Script:60: attempt to call field 'move' (a nil value)

Player = {
        x = 0, y = 0, z = 0,
        name = "",
 
        mt = {},
 
        new = function()
                local p = {}
                setmetatable(p, Player.mt)
                return p
        end,

		move = function(p, x, y, z)
                p.x = p.x + x
                p.y = p.y + y
                p.z = p.z + z
        end
}
 
Player.mt.__add = function(p1, p2)
        local p = Player.new()
        p.x = p1.x + p2.x
        p.y = p1.y + p2.y
        p.z = p1.z + p2.z
        return p
end
 
Player.mt.__sub = function(p1, p2)
        local p = Player.new()
        p.x = p1.x - p2.x
        p.y = p1.y - p2.y
        p.z = p1.z - p2.z
        return p
end
 
Player.mt.__eq = function(p1, p2)
        return p1.x == p2.x and p1.y == p2.y and p1.z == p2.z
end
 
Player.mt.__tostring = function(p)
        return "("..p.x..", "..p.y..", "..p.z..")"
end
 
p1 = Player.new()
p2 = Player.new()
 
p1.x = 20
p1.y = 10
p1.z = 0
p1.name = "Player1"
 
p2.x = 40
p2.y = 80
p2.z = 120
p2.name = "Player2"

print(tostring(p1), p1.name)
print(tostring(p2), p2.name)
 
p1.move(p1, 50, -40, 60)
p2.move(p2, 30, 10, -10)
 
print(p1.x, p1.y, p1.z)
print(p2.x, p2.y, p2.z)
 
p3 = p1 + p2
p4 = p2 - p1

print(p3)
print(p4)
print(p3 == p4)

1 answer

✓ Accepted answer

Your problem is that your function new, returns a newly created table instead of the original, Player table, in which move is located. Therefore, move does not exist in the table returned by new. You can easily fix that without changing much of your code by doing the following.


You could use the __index metamethod to refer back to the prototype table Player. The event itself fires when table[key] is indexed. You would then configure it to return the function move.

Player.mt.__index = function (_, key)
    return Player[key] 
end

The first argument represents the table being indexed, which we do not care for, and the following argument is the indexed key.

1 comment

0

Thank you, it worked.

This discussion is preserved as it was. New answers, comments, and votes are closed.