LUA: Avoiding passing by reference

244 views Asked by At

I'm just starting to learn LUA and I've got an issue that I'm unsure which way to "properly" solve. When I pass a Defold vmath.vector3 to my function it appears to be passed by reference and is therefore altered.
If I multiply it by anything this is solved however.
Is there another more correct way to solve this? I don't want to modify the original vector that I pass as an argument.

function M.get_nearest_tile(x, y)
    if y then -- if we've got 2 inputs, use x & y
        x = math.floor(x / M.TILE_SIZE)
        y = math.floor(y / M.TILE_SIZE)
        return x, y
    else -- if we've only got 1 input, use as vector
        local vec = x * 1 -- multiplying by 1 to avoid modifying the real vector
        vec.x = math.floor(vec.x / M.TILE_SIZE) 
        vec.y = math.floor(vec.y / M.TILE_SIZE) 
        return vec.x, vec.y
    end
end
3

There are 3 answers

3
luther On BEST ANSWER

Since you're returning x and y as two values, you could implement both branches the same way without modifying any tables:

function M.get_nearest_tile(x, y)
    local newX, newY
    if y then -- if we've got 2 inputs, use x & y
        newX = math.floor(x / M.TILE_SIZE)
        newY = math.floor(y / M.TILE_SIZE)
    else -- if we've only got 1 input, use as vector
        newX = math.floor(x.x / M.TILE_SIZE)
        newY = math.floor(x.y / M.TILE_SIZE)
    end
    return newX, newY
end
0
britzl On

Defold provides a number of special data structures that are all very useful in game development:

  • vector3 - vmath.vector3(x,y,z), useful for describing positions or direction in a 3D coordinate system
  • vector4 - vmath.vector4(x,y,z,w), used for color, tint etc (red, green, blue, alpha)
  • quat - vmath.quat() a quaternion describing a rotation
  • matrix4 - vmath.matrix4() a 4x4 matrix of values. Useful for view and projection matrices among other things

All of the above are used by the Defold game engine, but you'll find the same kind of data structures in other game engines as well.

The data structures above have one thing in common: They are of the Lua type userdata

print(type(vmath.vector3())) -- "userdata"

User data is passed by reference always and that is why you're seeing the behaviour that you describe. Defold does provide ways to make copies though:

local copy = vmath.vector3(original) -- copy the vector3 'original' local copy = vmath.vector4(original) -- copy the vector4 'original' local copy = vmath.quat(original) -- copy the quaternion 'original' local copy = vmath.matrix4(original) -- copy the matrix4 'original'

0
Paul Kulchenko On

You already have a solution in your else branch: you'll have to create a copy of your vectors before applying "modifying" operations to them.

In terms of other options, it may be possible to come up with a way to do using proxy tables, but it's going to be much more complex than just creating a copy.