---@alias Vec2Like { x: number, y: number} ---@class Vector2 ---@field x number ---@field y number ---@operator add: Vector2 ---@operator sub: Vector2 local Vector2 = {} Vector2.__index = Vector2 ---@param x number ---@param y number ---@return Vector2 function Vector2.new(x, y) return setmetatable({ x = x or 0, y = y or 0 }, Vector2) end ---@return Vector2 function Vector2:copy() return Vector2.new(self.x, self.y) end ---@return string function Vector2:__tostring() return string.format("Vector2(%.3f, %.3f)", self.x, self.y) end ---@param v Vector2 | Vec2Like ---@return Vector2 function Vector2:add(v) return Vector2.new(self.x + v.x, self.y + v.y) end ---@param v Vector2 | Vec2Like ---@return Vector2 function Vector2:sub(v) return Vector2.new(self.x - v.x, self.y - v.y) end ---@param scalar number ---@return Vector2 function Vector2:mul(scalar) return Vector2.new(self.x * scalar, self.y * scalar) end ---@param scalar number | Vec2Like ---@return Vector2 function Vector2:div(scalar) return Vector2.new(self.x / scalar, self.y / scalar) end ---@param self Vector2 | Vec2Like ---@param v Vector2 | Vec2Like ---@return Vector2 function Vector2.__add(self, v) return Vector2.new(self.x + v.x, self.y + v.y) end ---@param self Vector2 | Vec2Like ---@param v Vector2 | Vec2Like ---@return Vector2 function Vector2.__sub(self, v) return Vector2.new(self.x - v.x, self.y - v.y) end ---@return number function Vector2:length() return math.sqrt(self.x^2 + self.y^2) end ---@return number function Vector2:lengthSq() return self.x^2 + self.y^2 end ---@param dx number ---@return Vector2 function Vector2:addX(dx) self.x = self.x + dx return self end ---@param dy number ---@return Vector2 function Vector2:addY(dy) self.y = self.y + dy return self end ---@return Vector2 function Vector2:normalize() local len = self:length() if len == 0 then return Vector2.new(0, 0) end return Vector2.new(self.x / len, self.y / len) end ---@param v Vector2 | Vec2Like ---@return number function Vector2:dot(v) return self.x * v.x + self.y * v.y end ---@param v Vector2 | Vec2Like ---@return number function Vector2:distanceTo(v) return (self:sub(v)):length() end ---@param v Vector2 | Vec2Like ---@return number function Vector2:distanceToSq(v) return (self:sub(v)):lengthSq() end ---@param v Vector2 | Vec2Like ---@param epsilon number ---@return boolean function Vector2:equals(v, epsilon) epsilon = epsilon or 1e-5 return math.abs(self.x - v.x) < epsilon and math.abs(self.y - v.y) < epsilon end ---@param func function ---@return Vector2 function Vector2:map(func) return Vector2.new(func(self.x), func(self.y)) end ---@return Vec2Like function Vector2:toTable() return { x = self.x, y = self.y } end ---@param tbl Vec2Like ---@return Vector2 function Vector2.fromTable(tbl) return Vector2.new(tbl.x, tbl.y) end ---@param tbl table ---@return Vector2 function Vector2.fromArray(tbl) return Vector2.new(tbl[1], tbl[2]) end ---@return table function Vector2:toArray() return {self.x, self.y} end ---@return number ---@return number function Vector2:unpack() return self.x, self.y end return Vector2