Page 1 of 1

Object not in table despite being inserted

Posted: Sat Apr 23, 2016 4:42 am
by stouty
Hello,
So I am trying to insert a "cannonball" object into a "cannonballs" table, yet despite being created and inserted into the table, the object doesn't seem to be in the table.

This code is inside "Player.lua":

Code: Select all

function self.keypressed(key)
    if (key == "space") then
      cannonball = Cannonball.new(self.x+self.image:getWidth()/2, self.y+self.image:getHeight()/2, self.rot+90, math.random(30,35))
      table.insert(self.cannonballs, cannonball)
      print(#self.cannonballs)
    end
 end
 
Here's the "constructor" for the cannonball inside "Cannonball.lua":

Code: Select all

Cannonball = {}

Cannonball.new = function(x,y,dir,speed)
  local self = self or {}
  self.x = x
  self.y = y
  self.dir = dir
  self.rot = 0
  self.speed = speed
  -- etc.
Upon pressing "space" the console reads "CREATED" (printed from later in Cannonball.lua) and "0", which is the length of the "cannonballs" table.
I'm fairly new to LOVE, so any tips or tricks are highly appreciated. I am also probably setting up my objects completely wrong, so if anyone could point me to a source or tutorial that explains this further would be great.
I've included the .love file if further details are needed. Be aware, it's a mess.
Thank you.

Re: Object not in table despite being inserted

Posted: Sat Apr 23, 2016 6:01 am
by ivan
Regarding your question why the table size doesn't change:

Code: Select all

      cannonball = Cannonball.new(self.x+self.image:getWidth()/2, self.y+self.image:getHeight()/2, self.rot+90, math.random(30,35))
      table.insert(self.cannonballs, cannonball)
      print(#self.cannonballs)
The "Cannonball.new" doesn't return a value ("nil") and when you insert "nil" in a numerically indexed table nothing happens.
This is an important property of numerically indexed tables: their "size" is counted from index 1 until the first "nil" element.
So the table {1,2,nil,4} would have a size of "2" since the third index is "nil".

For starters, "Cannonball.new" needs to return a new table.
Also let's NOT use "self" in the "Cannonball.new" function in order to avoid confusion.

Code: Select all

Cannonball.new = function(x,y,d,s)
  local c = { x = x, y = y, dir = d, speed = s, rot = 0, destroy = false }
  c.image = maid64.newImage("cannonball.png")
  c.image:setFilter("nearest", "nearest")

  print("CREATED")
  setmetatable(c, {__index = Cannonball}) -- use all of the functionality from Cannonball
  return c -- let's return the newly created table
end

function Cannonball:update(dt)
   -- go ahead, you can now use "self."
end
So yea, you need to study up on how metatables work, before you can figure out what's going on.

Re: Object not in table despite being inserted

Posted: Sat Apr 23, 2016 6:09 am
by Tjakka5
You're on the right track, you just need to return 'self' in your cannonball create function, after line 29.

I also noticed a few other things;
1. You are creating a new image everytime a cannonball is created, its better to make the image once, and then create references to it:

Code: Select all

Cannonball = {}
Cannonball.image = love.graphics.newImage("cannonball.png")

Cannonball.new = function(x, y, dir, speed)
	local self = {}
	self.x = x
	-- etc
	self.image = Cannonball.image
	
	--etc
	return self
end
2. I also noticed that, whenever you create a image you are doing ':setFilter('nearest', 'nearest')
While this is fine, I'd suggest using love.graphics.setDefaultFilter('nearest', 'nearest') instead, as its much cleaner.

Re: Object not in table despite being inserted

Posted: Sat Apr 23, 2016 8:13 am
by airstruck
ivan wrote:This is an important property of numerically indexed tables: their "size" is counted from index 1 until the first "nil" element.
So the table {1,2,nil,4} would have a size of "2" since the third index is "nil".
This is not quite accurate. The length of a table can be any non-nil index that's followed by a nil index (behavior is implementation-dependent, PUC Lua and LuaJIT often give different results for the same code). From the manual:
If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).
This sounds like nitpicking, but it's important to note because if table length did work that way, you would expect certain things to work that actually don't work, for example you might expect table.insert to fill up any holes in a sparse table before appending elements to the end (I've seen someone make that mistake recently).

Re: Object not in table despite being inserted

Posted: Sat Apr 23, 2016 3:30 pm
by stouty
Thanks, everyone, for the help. That was certainly an easy fix that I should've seen.
ivan wrote:

Code: Select all

Cannonball.new = function(x,y,d,s)
  local c = { x = x, y = y, dir = d, speed = s, rot = 0, destroy = false }
  c.image = maid64.newImage("cannonball.png")
  c.image:setFilter("nearest", "nearest")

  print("CREATED")
  setmetatable(c, {__index = Cannonball}) -- use all of the functionality from Cannonball
  return c -- let's return the newly created table
end

function Cannonball:update(dt)
   -- go ahead, you can now use "self."
end
So yea, you need to study up on how metatables work, before you can figure out what's going on.

From what I understand, metatables used in this way change the functionality of when Cannonball is called?
What are the advantages using metatable versus whatever I was doing?
I also noticed in your example, you use "Cannonball:update(dt)." Why wouldn't it be "Cannonball.update(dt)?"
Thank you.

Re: Object not in table despite being inserted

Posted: Sat Apr 23, 2016 5:38 pm
by Skeletonxf
You use meta tables to create object orientation of sorts in lua. Lua will look to the meta table of a table if it can't find something in the table. If you want inheritance for objects, say you want an object to represent a point and another to represent a rectangle you make the rectangle inherit from the point by making its meta table the point's table. The point itself will have be the meta table of the 'self' that acts like the instance of this table.

You tell the rectangle object to say move up and lua looks if you had the function for that in rectangle, which you don't because it's a function for point, so then lua looks at point and finds the function and runs that. In point you then have the 'self' which is that particular point so when running you want to move only that instance of the point move up, so you do self.y = self.y + dy to jump one more meta table in and manipulate the data for that instance.

Re: Object not in table despite being inserted

Posted: Sat Apr 23, 2016 8:37 pm
by pgimeno
Also, please don't do this:

Code: Select all

  local self = self or {}
That's referencing a global variable 'self' which is normally not defined. There's no reason to do that.