Search code examples
luametatable

__add not working in custom Vector3 class


I am making a custom Vector3 class for a 3D engine I am making. I am kinda new to lua and not at the stage I should be making a 3D engine, but who cares. My Vector3 script looks like this.

#Vector3.lua
function Vector3(x,y,z) end

Vector3 = 
{
  __add = function(a,b)
    return Vector3(
      a.x + b.x,
      a.y + b.y,
      a.z + b.z
    )
  end
}
Vector3.__index = Vector3

function Vector3.new(x,y,z)
  local instance = 
  {
    x = x or 0,
    y = y or 0,
    z = z or 0
  }
  setmetatable(instance, Vector3)
  return instance
end

function Vector3:printX()
  return self.x
end

and my main like this:

#main.lua
require "Vector3"

vec1 = Vector3.new(1,2,3)
vec2 = Vector3.new(5,1,0)
vec3 = vec1 + vec2

print(vec3.x)

But it gives an error when I run it:

attempt to index global 'Vector3' (a function value)
stack traceback

I did this trying to have the __add function able to add two Vector3 classes. I know I am doing it incorrectly and I can't find a solution. How would I add the __add function to my script? This is the original Vector3.lua:

#Vector3.lua
Vector3 = {}
Vector3.__index = Vector3

function Vector3.new(x,y,z)
  local instance = 
  {
    x = x or 0,
    y = y or 0,
    z = z or 0
  }
  setmetatable(instance, Vector3)
  return instance
end

function Vector3:printX()
  return self.x
end

Solution

  • The first definition of Vector3 that you have at the top of Vector3.lua is overwritten immediately:

    function Vector3(x,y,z) end
    
    Vector3 = 
    {
    -- ...
    }
    

    Global Vector3 is now a table and not a function. Later on in __add you try to call constructor via simplified Vector3():

    __add = function(a, b)
      return Vector3(
    --       ^^^^^^^^ here
        a.x + b.x,
        a.y + b.y,
        a.z + b.z
      )
    end
    

    Update that call to Vector3.new(...) or implement __call metamethod to construct the object (see 2.3 - Metatables and Metamethods). The error message suggests that there is another mix-up but if you clean up the code and implement one of the previous options it should be resolved.