Page 1 of 1

OOP in Love2D

Posted: Sat Oct 21, 2017 11:12 am
by jthistle
I'm having some trouble with writing a class in Lua with Love2D. I use the following code for my class:

Code: Select all

Planet = {
	bgColour = {0,0,0},
	landColour = {0,0,0},
	size = 100,
	landPoints = {
		
	}
} -- the class table


function Planet:new()
	self = setmetatable({}, self)
	
	self.__index = self -- failed table lookups on the instances should fallback to the class table, to get methods
	
	self.bgColour = {love.math.random(0,255), love.math.random(0,255), love.math.random(0,255)}
	self.landColour = {love.math.random(0,255), love.math.random(0,255), love.math.random(0,255)}
	self.size = 100
	self.landPoints = {}
	
	-- create the terrain
	for j=1,love.math.random(1,10) do
		tempPoints = {}
		
		-- start point
		table.insert(tempPoints, love.math.random(-self.size, self.size))
		table.insert(tempPoints, love.math.random(-self.size, self.size))
	
		-- each continent has a set of points for drawing
		for i=1,love.math.random(5,8) do
			lastPoint = {tempPoints[tableLength(tempPoints)-1], tempPoints[tableLength(tempPoints)]}
			
			sizeCoef = 2
			
			table.insert(tempPoints, love.math.random(lastPoint[1]-(self.size/sizeCoef), lastPoint[1]+(self.size/sizeCoef)))
			table.insert(tempPoints, love.math.random(lastPoint[2]-(self.size/sizeCoef), lastPoint[2]+(self.size/sizeCoef)))
		end

		
		table.insert(self.landPoints, tempPoints)
	end
	
	
	
	
	return self
end

function Planet:getSize()
	return self.size
end

function Planet:draw(centre)
	-- Draw the planet (table centre as {x=number, y=number})
	
	love.graphics.push()
	love.graphics.translate(centre.x, centre.y)
	love.graphics.setColor(self.bgColour)
	love.graphics.circle("fill", 0,0, self.size)
	love.graphics.setColor(self.landColour)
	love.graphics.stencil(function () love.graphics.circle("fill", 0,0, self.size) end , "replace", 1, false)
	love.graphics.setStencilTest("greater", 0)
	
	for ind, points in pairs(self.landPoints) do
		love.graphics.polygon("fill", points)
	end
	
	love.graphics.setStencilTest()
	love.graphics.pop()
end
However, when I create a new instance:

Code: Select all

planet = Planet:new()
and then try to run a method:

Code: Select all

print(planet:getSize())
I get the error:

Code: Select all

Attempt to call method getSize (a nil value)
I've tried rewriting it again and again, in different ways, but this error has always come up. The class constructor is stored in a separate file which I require at the start of the main.lua file. Any help? Thanks in advance.

Re: OOP in Love2D

Posted: Sat Oct 21, 2017 12:03 pm
by Azhukar
Here's how you can implement a class:

Code: Select all

local classMeta = {
	__call = function(self,...) --creates a new class instance
		local new = setmetatable({},self)
		if (self.init ~= nil) then
			new:init(...) --constructor
		end
		return new
	end,
}
local function newClass() --creates a new class
	local class = setmetatable({},classMeta) --allows new class to be called as a function
	class.__index = class
	return class
end

classPlanet = newClass()

classPlanet.size = 100 --default class value

function classPlanet:init()
	self.bgColour = {love.math.random(0,255), love.math.random(0,255), love.math.random(0,255)}
	self.landColour = {love.math.random(0,255), love.math.random(0,255), love.math.random(0,255)}
	self.landPoints = {}
end

function classPlanet:getSize()
	return self.size
end

planet = classPlanet()
print(planet:getSize())
There's many class libraries to pick from if you look.

Re: OOP in Love2D

Posted: Sat Oct 21, 2017 12:20 pm
by bartbes
The problem is fairly simple, and is caused by these lines:

Code: Select all

function Planet:new()
	self = setmetatable({}, self)
	
	self.__index = self -- failed table lookups on the instances should fallback to the class table, to get methods
The problem is that in the last line self points to the object you're constructing, but not the class. I've got to say, replacing self is a fairly confusing thing to do in the first place. The easiest way to solve this is to not try to set __index every time you create an instance (everybody seems to be doing this lately, is there some tutorial that tells people to do this?), but to set it once beforehand. So replacing those lines with the following should work.

Code: Select all

Planet.__index = Planet

function Planet:new()
    self = setmetatable({}, self)
Of course I should recommend not replacing self, so you don't confuse yourself or any future readers.

Re: OOP in Love2D

Posted: Sat Oct 21, 2017 5:47 pm
by jthistle
Ah, thanks bartbes, that worked great. Yes, you're right, I got it from a tutorial - evidently not a very good one. Thanks!

Re: OOP in Love2D

Posted: Sat Oct 21, 2017 7:31 pm
by zorg
jthistle wrote: Sat Oct 21, 2017 5:47 pm Ah, thanks bartbes, that worked great. Yes, you're right, I got it from a tutorial - evidently not a very good one. Thanks!
Could you share which tut you got the info from? maybe they can fix it or something.

Re: OOP in Love2D

Posted: Sun Oct 22, 2017 4:11 pm
by jthistle
Sorry zorg, I can't seem to find it. It was quite an old non Love-related OOP tutorial in Lua though, so I doubt it would be changed now.