I'm creating a simple matrix like follows:
for x = 0, 50 do
current_level[x] = {}
for y = 0, 50 do
current_level[x][y] = grabTile();
end
end
After that i try to read it, but somehow the x is now a object not a number, while y seems perfectly fine!
How i try reading it:
for x,value in pairs(self.map) do
if value == ni then print("none"); return;end;
for y,object in pairs(value) do
if object == ni then print("none"); return;end;
object:render(x,y); -- Here x is an object
end
end
I'm new to working with lua, so i might be doing something obvious terribly wrong.
How would i make this work?
What i get for x is something like: table: 0x07c8d530
This value stays the same along the complete iteration
object:render(x,y); -- Here x is an object
This line is using colon syntax. It is a syntactic sugar for object.render(object,x,y) call.
So your render() function must have the first self argument declared either explicitly as function render(self, x, y) or implicitly with another syntactic sugar for definition: function object:render(x,y).
Unrelated hint. The first loop will be faster/smaller if transformed to:
for x = 0, 50 do
local row = {}
for y = 0, 50 do
row[y] = grabTile();
end
current_level[x] = row
end
Related
I have this code:
function createRect(x, y, w, h)
local rect = {
type = "rect",
x = x,
y = y,
w = w,
h = h,
translate = function(rect, vector)
assert(vector.type == "vector2d")
local rect = shapes.createRect(rect.x + vector.x, rect.y + vector.y, rect.w, rect.h)
end,
}
return rect
end
translate = function(rect, vector)
assert(vector.type == "vector2d")
local rect = shapes.createRect(rect.x + vector.x, rect.y + vector.y, rect.w, rect.h)
end
local o = createRect(2,3,4,5)
local q = createRect(2,3,4,5)
print(o.translate, q.translate, translate)
Which is some very easy code and is written to test factory functions in Lua and is very reminiscent of the JS module pattern. Something people usually complain about when talking about factory functions is the memory footprint.
Because o and q are just assigned, of course they have different translate() functions, I assumed.
However I was proven wrong:
function: 0x7fcdbe600d50 function: 0x7fcdbe600d50 function: 0x7fcdbe600d90
Why is this? How can this even be? I assumed to be o.translate and q.translate to be different functions, however they are the same...
How can this even be? I assumed to be o.translate and q.translate to be different functions, however they are the same...
Normally you are correct, however Lua 5.2 introduced an optimization where anonymous functions may be cached if certain conditions are met. Specifically, if the values it references doesn't change between construction then the first created instance of that anonymous function gets reused.
Running your example in repl.it, Lua 5.1, shows this as one possible output:
function: 0xb81f30 function: 0xb81f00 function: 0xb82ca0
But running it under melpon.org/wandbox, Lua 5.2+, shows:
function: 0x14f0650 function: 0x14f0650 function: 0x14efb40
In your example, createRect creates and returns a different rect table for every call but the field rect.translate is being assigned the same anonymous function as the lua value due to this optimization.
Also see
http://lua-users.org/lists/lua-l/2010-07/threads.html#00339
http://lua-users.org/lists/lua-l/2010-07/msg00862.html
http://lua-users.org/lists/lua-l/2010-05/threads.html#00617
Assume I have a function that returns multiple values. I happen to be working with LÖVE's (Image):getDimensions. This returns two values, which I know to be width,height. I want to assign them to a new table, as an array. I would like named (string) keys. So for instance, I would like to assign the return values of the getDimensions() function to a new table with keys width and height, respectively.
I know the following works...
image = {}
image.data = love.graphics.newImage('myimage.png')
image.size = {}
image.size.width, image.size.height = image.data:getDimensions()
I'm wondering if there is any sort of syntactic sugar I can use, or any use of standard library functions that will allow a syntax more along the lines of...
image.size = { width, height = image.data:getDimensions() }
I know the above line does not work, along with many variations I've tried, including various attempts to use unpack(). I'm new to Lua (~2 days in now), so maybe there is another standard function or best practice that I'm unaware of that will associate a table of keys to an array-like table. Thanks!
You can write your own functions:
local function set_fields(tab, fields, ...)
-- fields is an array of field names
-- (use empty string to skip value at corresponging position)
local values = {...}
for k, field in ipairs(fields) do
if field ~= "" then
tab[field] = values[k]
end
end
return tab
end
local function get_fields(tab, fields)
local values = {}
for k, field in ipairs(fields) do
values[k] = tab[field]
end
return (table.unpack or unpack)(values, 1, #fields)
end
Usage example #1:
image.size = set_fields({}, {"width", "height"}, image.data:getDimensions())
Usage example #2:
Swap the values on-the-fly!
local function get_weekdays()
return "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
end
-- we want to save returned values in different order
local weekdays = set_fields({}, {7,1,2,3,4,5,6}, get_weekdays())
-- now weekdays contains {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
Usage example #3:
local function get_coords_x_y_z()
return 111, 222, 333 -- x, y, z of the point
end
-- we want to get the projection of the point on the ground plane
local projection = {y = 0}
-- projection.y will be preserved, projection.x and projection.z will be modified
set_fields(projection, {"x", "", "z"}, get_coords_x_y_z())
-- now projection contains {x = 111, y = 0, z = 333}
Usage example #4:
If require("some_module") returns a module with plenty of functions inside, but you need only a few of them:
local bnot, band, bor = get_fields(require("bit"), {"bnot", "band", "bor"})
Using a class construct, I have come up with the following...
Size = {}
Size.mt = {}
Size.prototype = { width = 0, height = 0 }
function Size.new (dimensions)
local size = setmetatable({}, Size.mt)
if dimensions ~= nil and type(dimensions) == 'table' then
for k,v in pairs(dimensions) do
size[k] = v
end
end
return size
end
Size.mt.__index = function (t, k)
if k == 'width' or k == 'height' then
rawset(t, k, Size.prototype[k])
return t[k]
else
return nil
end
end
Size.mt.__newindex = function (t, k, v)
if k == 1 or k == 'width' then
rawset(t, 'width', v)
elseif k == 2 or k == 'height' then
rawset(t, 'height', v)
end
end
Then I can initialize a Size object in a number of ways
Using multiple return values:
image.size = Size.new{image.data:getDimensions()}
image.size = Size.new(table.pack(image.data:getDimensions())
Using default values:
image.size = Size.new()
image.size = Size.new{}
image.size = Size.new({})
Using mixed array and hash tables:
image.size = Size.new({height=20, width=30})
image.size = Size.new({height=20, 30})
There are pros and cons to this approach vs. Egor's (utility function), which is what I was considering doing if there wasn't a simple syntax trick or an existing function that I was unaware of.
Pros:
(personal) learning experience with OO constructs in Lua
I can limit the number of actual keys on the table, while allowing 'synonyms' for those keys to be added by expanding the accepted values in the if/else logic of __index and __newindex
Explicit definition of fields in the table, without needing to worry about syncing a table of keys with a table of values (as with a general purpose utility function)
Cons
would need to repeat this pattern for each data structure where I wanted this behavior
costly, a lot of overhead for what amounts to a very small difference to the consumer
I'm sure I can make this approach more robust in time, but I would appreciate any feedback.
Why isn't this working? I'm trying to put all my object tables in a single table and use a forloop to iterate through each of them and draw. It shows an error message saying: "}" expected near "=" at line 5
function love.load()
solidstatic = {
ground = {x = 0,y = 160,width = 1000,height = 1000},
box = {x = 80,y = 100,width = 15,height = 15}
}
end
function love.draw()
for i,obj in ipairs(solidstatic) do
love.graphics.rectangle("fill",obj[x],obj[y],obj[width],obj[height])
end
end
(edit) solved the error problem, I was running the wrong .lua file. But still, it doesn't draw anything on the screen
Two things.
Firstly, you must use pairs instead of ipairs to list keys that are not numbers.
for i, v in pairs(table) do
...
end
You must also index the variables as a string.
t = {
x = 1
}
t['x'] = 1
-- or
t.x = 1
This is because doing it without quotes would be indexing with the global variable x, which doesn't exist.
You need to use pairs instead of ipairs to iterate over elements in solidstatic as there are no array keys in that table.
I am trying to do:
function objects:add(namespace, x, y, w, h, mode, density, r)
then make a new table. objects.namespace = {}
then return the table by:
return objects.namespace
but i want the 'namespace' to actually be defined in the function... how would I go about doing that?
and when i try to call something inside the table I.E: print(objects.newBox.x)
it gives me 'NIL'
Even if I try:
function test(name)
print(name)
[name] = {"yo"}
end
test(doit)
It gives me an error: 'attempt to index a nil value'
I must be doing something wrong...
table = {}
function table:add(name, x, y)
table.[name] = {}
table.[name].x = x
table.[name].y = y
return table.[name]
end
table:add(box1, 300, 100)
print("table.box1.x: " ..table.box1.x)
print("table.box1.y: " ..table.box1.y)
-- [name] is to be defined in the function arg.
-- then i want to return the table and use it's contents for other uses I.E line 10 and 11
-- gets the following error: '<name>' expected near '['
Here is a working version:
t = {}
function t:add(name, x, y)
t[name] = {} -- or use t[name] = {x=x, y=y} and remove the next 2 lines
t[name].x = x
t[name].y = y
return t[name] -- necessary?
end
t:add('box1', 300, 100)
print("t.box1.x: " ..t.box1.x)
print("t.box1.y: " ..t.box1.y)
Naming a variable table will hide the table library so I have changed it to t
When you call t:add(box1, 300, 100) box1 is not defined so it's value is nil, which isn't a valid key for a table
you want to use "box1" as the key since t.box1 is just sugar for t["box1"]
In your function t:add you want to index t with the value of name, the syntax is t[name]
You also aren't using the return value and you can get to it from t with t.box1. it seems unnecessary
using : suggests you want to implement objects? If that is the case, see PIL Object Oriented Programming for an introduction on how to implement that
I am starting to learn Lua from Programming in Lua (2nd edition)
I didn't understand the following in the book. Its very vaguely explained.
a.) w={x=0,y=0,label="console"}
b.) x={math.sin(0),math.sin(1),math.sin(2)}
c.) w[1]="another field"
d.) x.f=w
e.) print (w["x"])
f.) print (w[1])
g.) print x.f[1]
When I do print(w[1]) after a.), why doesn't it print x=0
What does c.) do?
What is the difference between e.) and print (w.x)?
What is the role of b.) and g.)?
You have to realize that this:
t = {3, 4, "eggplant"}
is the same as this:
t = {}
t[1] = 3
t[2] = 4
t[3] = "eggplant"
And that this:
t = {x = 0, y = 2}
is the same as this:
t = {}
t["x"] = 0
t["y"] = 2
Or this:
t = {}
t.x = 0
t.y = 2
In Lua, tables are not just lists, they are associative arrays.
When you print w[1], then what really matters is line c.) In fact, w[1] is not defined at all until line c.).
There is no difference between e.) and print (w.x).
b.) creates a new table named x which is separate from w.
d.) places a reference to w inside of x. (NOTE: It does not actually make a copy of w, just a reference. If you've ever worked with pointers, it's similar.)
g.) Can be broken up in two parts. First we get x.f which is just another way to refer to w because of line d.). Then we look up the first element of that table, which is "another field" because of line c.)
There's another way of creating keys in in-line table declarations.
x = {["1st key has spaces!"] = 1}
The advantage here is that you can have keys with spaces and any extended ASCII character.
In fact, a key can be literally anything, even an instanced object.
function Example()
--example function
end
x = {[Example] = "A function."}
Any variable or value or data can go into the square brackets to work as a key. The same goes with the value.
Practically, this can replace features like the in keyword in python, as you can index the table by values to check if they are there.
Getting a value at an undefined part of the table will not cause an error. It will just give you nil. The same goes for using undefined variables.
local w = {
--[1] = "another field"; -- will be set this value
--["1"] = nil; -- not save to this place, different with some other language
x = 0;
y = 0;
label = "console";
}
local x = {
math.sin(0);
math.sin(1);
math.sin(2);
}
w[1] = "another field" --
x.f = w
print (w["x"])
-- because x.f = w
-- x.f and w point one talbe address
-- so value of (x.f)[1] and w[1] and x.f[1] is equal
print (w[1])
print ((x.f)[1])
print (x.f[1])
-- print (x.f)[1] this not follows lua syntax
-- only a function's has one param and type of is a string
-- you can use print "xxxx"
-- so you print x.f[1] will occuur error
-- in table you can use any lua internal type 's value to be a key
-- just like
local t_key = {v=123}
local f_key = function () print("f123") end
local t = {}
t[t_key] = 1
t[f_key] = 2
-- then t' key actualy like use t_key/f_key 's handle
-- when you user t[{}] = 123,
-- value 123 related to this no name table {} 's handle