Tool Hey! I re-wrote vec2.lua

Discussion in 'Starbound Modding' started by XanthicDragon, May 21, 2016.

  1. XanthicDragon

    XanthicDragon Void-Bound Voyager

    Effectively I just got rid of the methods like .add and stuff by using metatables and added a few other things.
    In my version, it is possible to directly add, subtract, multiply, or divide vectors without the usage of a method (If you use the vec2.new() function)
    vec2.new(10, 10) * vec2.new(2, 2) is acceptable.
    Shortcuts exist with multiply and divide:
    vec2.new(10, 10) * 2 --OR-- vec2.new(10, 10) * vec2.new(2, 2)

    Furthermore, there are really handy functions: You can find the angle (in radians) between two points, as well as the normal and magnitude.

    Even better, mine comes with a function to interpolate between two points, as well as the ability to print Vectors (using tostring())!
    Code:
    local start = Vector2.new(10, 10)
    local end = Vector2.new(20, 10)
    local point = start:lerp(end, 0.5)
    print(tostring(point))
    > [15, 10]
    For those interested, you can see the source code at the bottom.

    Notice: This can NOT replace the already existing vec2 library because Starbound needs it the way it is internally! Use mine in a separate lua file.






    Code:
    local vec2 = {}
    
    function vec2.new(x, y)
        local x = x or 0
        local y = y or 0
        local v = {
                    [1] = x; --First index x
                    [2] = y; --Second index y
                    X = x; --Uppercase X property
                    Y = y; --Uppercase Y property
                    x = x; --Lowercase x property
                    y = y; --Lowercase y property
                }
               
        v.mt ={} --Our metatable
        setmetatable(v, v.mt)
       
        v.Add = function (a, b)
            if getmetatable(a) ~= "Vector2" or getmetatable(b) ~= "Vector2" then
                return vec2.new()
            end
            local x = a.X + b.X
            local y = a.Y + b.Y
            return vec2.new(x, y)
        end
        v.Subtract = function (a, b)
            if getmetatable(a) ~= "Vector2" or getmetatable(b) ~= "Vector2" then
                return vec2.new()
            end
            local x = a.X - b.X
            local y = a.Y - b.Y
            return vec2.new(x, y)
        end
        v.Multiply = function (a, b)
            if getmetatable(a) ~= "Vector2" or getmetatable(b) ~= "Vector2" then
                return vec2.new()
            end
            local x = a.X * b.X
            local y = a.Y * b.Y
            return vec2.new(x, y)
        end
        v.Divide = function (a, b)
            if getmetatable(a) ~= "Vector2" or getmetatable(b) ~= "Vector2" then
                return vec2.new()
            end
            local x = a.X / b.X
            local y = a.Y / b.Y
            return vec2.new(x, y)
        end
        v.Print = function (a)
            if getmetatable(a) ~= "Vector2" then
                return "[NOT A VECTOR]"
            end
            return "["..tostring(a.X)..", "..tostring(a.Y).."]"
        end
        --
        v.Magnitude = function ()
            local x = v.X
            local y = v.Y
            return math.sqrt((x^2)+(y^2))
        end
        v.Unit = function ()
            local x = v.X
            local y = v.Y
            local d = math.sqrt((x^2)+(y^2))
            local dir = v / vec2.new(d, d)
            return dir
        end
        function v:lerp(a, frac)
            if getmetatable(a) ~= "Vector2" then
                return vec2.new()
            end
            local frac = frac or 0
            if frac < 0 then
                frac = 0
            elseif frac > 1 then
                frac = 1
            end
            local a = (a - v) * vec2.new(frac, frac)
            return a + v
        end
        function v:toAngle(a)
            if getmetatable(a) ~= "Vector2" then
                return vec2.new()
            end
            return math.atan2(a[2] - v[2], a[1] - v[1]) - math.pi
        end
        v.mt.__add = v.Add
        v.mt.__sub = v.Subtract
        v.mt.__div = v.Divide
        v.mt.__mul = v.Multiply
        v.mt.__tostring = v.Print
        v.mt.__metatable = "Vector2"
        return v
    end
    
    --Some collision system just because Starbound has one in vec2 as well.
    
    function vec2.intersects(a, b, c, d)
        --[[
            a = top left corner of rectangle 1 (as Vector2)
            b = rectangle 1 size (as Vector2)
           
            c = top left corner of rectangle 2 (as Vector2)
            d = rectangle 2 size (as Vector2)
        --]]
    
        local surface = ""
        local collide = false
        local x1 = a[1]
        local y1 = a[2]
        local x2 = c[1]
        local y2 = c[2]
        local w1 = b[1]
        local h1 = b[2]
        local w2 = d[1]
        local h2 = d[2]
       
        if  x1 < x2 + w2 + 1 and    --Right
            x1 + w1 > x2 - 1 and    --Left
            y1 < y2 + h2 + 1 and
            y1 + h1 > y2 - 1
        then
            collide = true
            if y1 + h1 > y2 - 1 and y1 + h1 < y2 then
                surface = "top"
            elseif y1 > y2 + h2 and y1 < y2 + h2 + 1 then
                surface = "bottom"
            end
            if x1 + w1 > x2 - 1 and x1 + w1 < x2 then
                surface = "left"
            elseif x1 > x2 + w2 and x1 < x2 + w2 + 1 then
                surface = "right"
            end
           
            --At this point we need to check if we have mixed surfaces (When this happens, we get stuck on corners)
            if  y1 + h1 > y2 - 1 and y1 + h1 < y2 and
                x1 + w1 > x2 - 1 and x1 + w1 < x2 then
                surface = "topleft"
            elseif  y1 + h1 > y2 - 1 and y1 + h1 < y2 and
                    x1 > x2 + w2 and x1 < x2 + w2 + 1 then
                surface = "topright"
            elseif  y1 > y2 + h2 and y1 < y2 + h2 + 1 and
                    x1 + w1 > x2 - 1 and x1 + w1 < x2 then
                surface = "bottomleft"   
            elseif  y1 > y2 + h2 and y1 < y2 + h2 + 1 and
                    x1 > x2 + w2 and x1 < x2 + w2 + 1 then
                surface = "bottomright"
            end
        end
       
        return collide, surface
    end
    
    return vec2
     
    Inf_Wolf14, Errors4l and The | Suit like this.
  2. Errors4l

    Errors4l Spaceman Spiff

    The reason I liked the vec2 library was it being easy to use it with return values from various Lua API functions, such as tech.aimPosition(). These functions return objects such as { 10, 20}.
    I believe this rewrite takes away the ability to pass the coordinates directly (as {x,y}), and instead requires users to manually pass those values.

    An example:
    Code:
    local aimPos = tech.aimPosition()
    local pos = mcontroller.position()
    
    local offset = vec2.new(aimPos[1], aimPos[2]) - vec2.new(pos[1], pos[2])
    
    'Old' code:
    Code:
    local offset = vec2.sub(tech.aimPosition(), mcontroller.position())
    
    Although I really like the idea of using metatables to create extension methods, for me this additional step before being able to use vec2 methods sort of ruins it :/.

    Edit: my apologies, I didn't read your last note before looking at the code. Although I didn't factor in the idea to use this script besides the existing one, I'd love to see the functionality to pass {x,y} objects rather than numbers as separate values.
     
    Last edited: May 22, 2016
  3. XanthicDragon

    XanthicDragon Void-Bound Voyager

    Yeah, I didn't factor that in, it seems! Unfortunately that may not work, since the vec2.new() function creates the metatable there, and manually creating it would be a useless hassle.
     
  4. Errors4l

    Errors4l Spaceman Spiff

    What I meant was parsing the arguments differently based on one or two being passed; vec2.new(x_or_point, y_or_nil).
    The function calls vec2.new(10,15) and vec2.new({10,15}) would both work. This would at least allow for vec2.new(tech.aimPosition()), rather than vec2.new(tech.aimPosition()[1], tech.aimPosition()[2]) or the earlier given example.
     

Share This Page