Hello everyone! So, here I’ve written a Vec3 metatable class, just for myself.
Source Code
local Vec2 = require(script.Parent.Vec2)
-- Just a Vec2 class, like this current class. It is needed for Vec3-to-Vec2 conversion.
local Vec3 = {__type = "Vec3"}
local mt = {__index = Vec3}
-- Is |__index = Vec3| actually necessary here? Please explain why and what it actually does.
mt.__add = function(a, b)
if (typeof(a) == "number") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a + b.x, a + b.y, a + b.z)
elseif a.__type and (a.__type == "Vec3") and (typeof(b) == "number") then
return Vec3.new(a.x + b, a.y + b, a.z + b)
elseif a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a.x + b.x, a.y + b.y, a.z + b.z)
end
end
mt.__sub = function(a, b)
if (typeof(a) == "number") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a - b.x, a - b.y, a - b.z)
elseif a.__type and (a.__type == "Vec3") and (typeof(b) == "number") then
return Vec3.new(a.x - b, a.y - b, a.z - b)
elseif a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a.x - b.x, a.y - b.y, a.z - b.z)
end
end
mt.__mul = function(a, b)
if (typeof(a) == "number") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a * b.x, a * b.y, a * b.z)
elseif a.__type and (a.__type == "Vec3") and (typeof(b) == "number") then
return Vec3.new(a.x * b, a.y * b, a.z * b)
elseif a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a.x * b.x, a.y * b.y, a.z * b.z)
end
end
mt.__div = function(a, b)
if (typeof(a) == "number") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a / b.x, a / b.y, a / b.z)
elseif a.__type and (a.__type == "Vec3") and (typeof(b) == "number") then
return Vec3.new(a.x / b, a.y / b, a.z / b)
elseif a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a.x / b.x, a.y / b.y, a.z / b.z)
end
end
mt.__mod = function(a, b)
if (typeof(a) == "number") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a % b.x, a % b.y, a % b.z)
elseif a.__type and (a.__type == "Vec3") and (typeof(b) == "number") then
return Vec3.new(a.x % b, a.y % b, a.z % b)
elseif a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a.x % b.x, a.y % b.y, a.z % b.z)
end
end
mt.__pow = function(a, b)
if (typeof(a) == "number") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a ^ b.x, a ^ b.y, a ^ b.z)
elseif a.__type and (a.__type == "Vec3") and (typeof(b) == "number") then
return Vec3.new(a.x ^ b, a.y ^ b, a.z ^ b)
elseif a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return Vec3.new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z)
end
end
mt.__eq = function(a, b)
if a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return (a.x == b.x) and (a.y == b.y) and (a.z == b.z)
end
end
mt.__lt = function(a, b)
if a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return (a.x < b.x) and (a.y < b.y) and (a.z < b.z)
end
end
mt.__le = function(a, b)
if a.__type and (a.__type == "Vec3") and b.__type and (b.__type == "Vec3") then
return (a.x <= b.x) and (a.y <= b.y) and (a.z <= b.z)
end
end
mt.__tostring = function(a)
return a.x .. " " .. a.y .. " " .. a.z
end
mt.__unm = function(a)
return Vec3.new(-a.x, -a.y, -a.z)
end
mt.__index = function(t, i)
--[[
This is what I'm talking about: Recursive indexes
Like say, you want to index Vec3 with xxy to get values of x, x, and y, in order,
as a new Vec3, and then again you might want to index Vec3 with xyx, and so on.
]]
-- to Vec3 conversion (modify order)
if i == "xxx" then return Vec3.new(t.x, t.x, t.x) end
if i == "xxy" then return Vec3.new(t.x, t.x, t.y) end
if i == "xxz" then return Vec3.new(t.x, t.x, t.z) end
if i == "xyx" then return Vec3.new(t.x, t.y, t.x) end
if i == "xyy" then return Vec3.new(t.x, t.y, t.y) end
if i == "xyz" then return Vec3.new(t.x, t.y, t.z) end
if i == "xzx" then return Vec3.new(t.x, t.z, t.x) end
if i == "xzy" then return Vec3.new(t.x, t.z, t.y) end
if i == "xzz" then return Vec3.new(t.x, t.z, t.z) end
if i == "yxx" then return Vec3.new(t.y, t.x, t.x) end
if i == "yxy" then return Vec3.new(t.y, t.x, t.y) end
if i == "yxz" then return Vec3.new(t.y, t.x, t.z) end
if i == "yyx" then return Vec3.new(t.y, t.y, t.x) end
if i == "yyy" then return Vec3.new(t.y, t.y, t.y) end
if i == "yyz" then return Vec3.new(t.y, t.y, t.z) end
if i == "yzx" then return Vec3.new(t.y, t.z, t.x) end
if i == "yzy" then return Vec3.new(t.y, t.z, t.y) end
if i == "yzz" then return Vec3.new(t.y, t.z, t.z) end
if i == "zxx" then return Vec3.new(t.z, t.x, t.x) end
if i == "zxy" then return Vec3.new(t.z, t.x, t.y) end
if i == "zxz" then return Vec3.new(t.z, t.x, t.z) end
if i == "zyx" then return Vec3.new(t.z, t.y, t.x) end
if i == "zyy" then return Vec3.new(t.z, t.y, t.y) end
if i == "zyz" then return Vec3.new(t.z, t.y, t.z) end
if i == "zzx" then return Vec3.new(t.z, t.z, t.x) end
if i == "zzy" then return Vec3.new(t.z, t.z, t.y) end
if i == "zzz" then return Vec3.new(t.z, t.z, t.z) end
-- to Vec2 conversion
if i == "xx" then return Vec2.new(t.x, t.x) end
if i == "xy" then return Vec2.new(t.x, t.y) end
if i == "xz" then return Vec2.new(t.x, t.z) end
if i == "yx" then return Vec2.new(t.y, t.x) end
if i == "yy" then return Vec2.new(t.y, t.y) end
if i == "yz" then return Vec2.new(t.y, t.z) end
if i == "zx" then return Vec2.new(t.z, t.x) end
if i == "zy" then return Vec2.new(t.z, t.y) end
if i == "zz" then return Vec2.new(t.z, t.z) end
end
function Vec3.new(x, y, z)
Vec3.x = x or 0
Vec3.y = y or 0
Vec3.z = z or 0
return setmetatable(
Vec3,
mt
)
end
function Vec3:Dot(a, b) -- This doesn't work apparently, it may be the script doing something wrong, OR the algorithm is incorrect.
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z)
end
return Vec3
However, I felt like the code was garbage due to the fact that it has a repeating if “ladder” (repeating “if” per line) at least something like Vec3.xyz = something something, would be nicer than millions of if statements.
Now, Is there any way to improve this? I have a feeling there is, but I also have a feeling that there isn’t. Please let me know.
mt.__index = function(t, i)
--[[
This is what I'm talking about: Recursive indexes
Like say, you want to index Vec3 with xxy to get values of x, x, and y, in order,
as a new Vec3, and then again you might want to index Vec3 with xyx, and so on.
]]
-- to Vec3 conversion (modify order)
if i == "xxx" then return Vec3.new(t.x, t.x, t.x) end
if i == "xxy" then return Vec3.new(t.x, t.x, t.y) end
if i == "xxz" then return Vec3.new(t.x, t.x, t.z) end
if i == "xyx" then return Vec3.new(t.x, t.y, t.x) end
if i == "xyy" then return Vec3.new(t.x, t.y, t.y) end
if i == "xyz" then return Vec3.new(t.x, t.y, t.z) end -- haha i could do .xyz.xyz.xyz.xyz all the time, useless. :D
if i == "xzx" then return Vec3.new(t.x, t.z, t.x) end
if i == "xzy" then return Vec3.new(t.x, t.z, t.y) end
if i == "xzz" then return Vec3.new(t.x, t.z, t.z) end
if i == "yxx" then return Vec3.new(t.y, t.x, t.x) end
if i == "yxy" then return Vec3.new(t.y, t.x, t.y) end
if i == "yxz" then return Vec3.new(t.y, t.x, t.z) end
if i == "yyx" then return Vec3.new(t.y, t.y, t.x) end
if i == "yyy" then return Vec3.new(t.y, t.y, t.y) end
if i == "yyz" then return Vec3.new(t.y, t.y, t.z) end
if i == "yzx" then return Vec3.new(t.y, t.z, t.x) end
if i == "yzy" then return Vec3.new(t.y, t.z, t.y) end
if i == "yzz" then return Vec3.new(t.y, t.z, t.z) end
if i == "zxx" then return Vec3.new(t.z, t.x, t.x) end
if i == "zxy" then return Vec3.new(t.z, t.x, t.y) end
if i == "zxz" then return Vec3.new(t.z, t.x, t.z) end
if i == "zyx" then return Vec3.new(t.z, t.y, t.x) end
if i == "zyy" then return Vec3.new(t.z, t.y, t.y) end
if i == "zyz" then return Vec3.new(t.z, t.y, t.z) end
if i == "zzx" then return Vec3.new(t.z, t.z, t.x) end
if i == "zzy" then return Vec3.new(t.z, t.z, t.y) end
if i == "zzz" then return Vec3.new(t.z, t.z, t.z) end
-- to Vec2 conversion
if i == "xx" then return Vec2.new(t.x, t.x) end
if i == "xy" then return Vec2.new(t.x, t.y) end
if i == "xz" then return Vec2.new(t.x, t.z) end
if i == "yx" then return Vec2.new(t.y, t.x) end
if i == "yy" then return Vec2.new(t.y, t.y) end
if i == "yz" then return Vec2.new(t.y, t.z) end
if i == "zx" then return Vec2.new(t.z, t.x) end
if i == "zy" then return Vec2.new(t.z, t.y) end
if i == "zz" then return Vec2.new(t.z, t.z) end
-- to number conversion already exists, x, y, and z.
end
I have a couple other questions as well, and well, these are:
-
Why is __index = table in the first few lines necessary and what does it do?
My guess is that it allows code to index in the primary Vec3 table, albeit, I’m not sure. -
How would I go about making custom functions, and variables such as Vec3:Dot, Vec3:Cross, Vec3.Unit (Constant), Vec3.Magnitude (Constant), etc.?
-
Are there other arithmetic meta-methods?
-fronthd