Page 1 of 1

Classes and Inheritance

Posted: Sat Jun 06, 2009 9:16 pm
by lynerd
Just started with the engine, but have never worked with Lua before. I come from using c++ and c# and miss having classes with the capability for inheritance. I found a piece of code from another game engine, called Verge, that allows for the use of inheritance. I believe the code is made for Lua and is not Verge specific though.

I simply tried to make a base "Entity" class to test out the use of the added classes and inheritance. Love is showing a stack overflow error with the new class though. Thanks for any help someone can offer.

Error

Code: Select all

[string "Object.lua"]:105: C stack overflow
stack traceback:
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	...
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "Object.lua"]:105: in function <[string "Object.lua"]:105>
	[string "main.lua"]:4: in main chunk
Object.lua - has a lot of comments I left in that might be useful

Code: Select all

--------------------------------------------------------------------------------
-- PROJECT:     General
-- FILE:        vklua_Object.lua
-- DESCRIPTION:
--  Defines the base Object for deriving other objects.
--
-- INTERFACE:
--  <object>:clone() - return a clone of <object>
--  <object>:isa(<object_type>) - return true if <object_type> is in <object>'s
--     inheritance hierarchy
--
-- USAGE/DISCUSSION:
--  Object is very simple, but it may be a different OO paradigm than you are
--  used to if you are coming from C++ or Java. Unlike these "prototyping" 
--  languages, this uses a "cloning" paradigm. 
--
--  To create a new object, simply call :clone() on its parent. You will be
--  returned an object that behaves identically to the parent. You can then
--  modify its behaviour as needed. You can then, if you wish, clone this new
--  object to have a copy of the new behaviour.
--
--  For example, say that we have a class called Actor that stores information
--  about an entity in your gameworld. To create the Actor template, you would
--  say...
--
--    Actor = Object:clone()
--
--  At this point, Actor is a simple object with no methods or data members.
--  You would define all the defaults for any members that an Actor of any type
--  will have, say...
--
--    Actor.health = 100
--    Actor.evil = false
--    Actor.powerlevel = 10
--
--  If you wanted to make an instance of an Actor, you would use...
--
--    Darin = Actor:clone()
--
--  Darin is now an Actor with 100 health and a power level of 10, and his evil
--  flag is set to false. If you were to write...
--
--    Darin.powerlevel = 9001
--
--  At this point, Darin still has 100 health and is still not evil, but he now 
--  has a power level over 9000. Any new person made with Actor:clone() will
--  still only have a powerlevel of 10.
--
--  Say that we now want to make another class of Actors called Monsters. You
--  would say...
--
--    Monster = Actor:clone()
--    Monster.evil = true
--    Monster.special_ability = "nothing"
--    fairy = Monster:clone()
--    troll = Monster:clone()
--
--  Monster is now a new type of Actor. Monsters, unlike normal run-of-the-mill
--  Actors, are evil by default, and they have a special_ability that defaults
--  to "nothing". Note that we can still write...
--
--    fairy.evil = false
--    troll.special_ability = "bad smell"
--    troll.power_level = 500
--
--  And we can even say...
--
--    fairy.magic_wand_type = "star"
--
--  We didn't define magic_wand_type anywhere else; only the fairy has it. But
--  that's okay. A troll doesn't need a magic wand, he smells bad.
--
--  And things could keep going. We could start cloning the fairy to give it
--  a bunch of siblings to help take down the troll if we wanted, or we could
--  make a new kind of troll that isn't evil, whatever.
--
--  If we're not sure whether a particular actor, say Spekkio, is a monster
--  or not, we can use the isa() function, like so...
--
--   Spekkio:isa(Monster)
--
--  This will return true if Spekkio inherits from Monster (no matter how many
--  generations back) and false otherwise.
--
--  If you have an object defined with various members, and want to set them
--  when you clone it, then you can pass a table to the :clone() method. The
--  clone will work as normal and then, as a last step, it will copy any data
--  from the table into the new object. Like so...
--
--    orc = Monster:clone({
--    	special_ability = "tusk attack",
--    	health = 110 
--    })
--
--  This would define orc to have special_ability "tusk attack" and a greater
--  health than usual, right off the bat. This is exactly equivalent to setting
--  them each separately, as with the troll and fairy example above.
--------------------------------------------------------------------------------

Object = {}
Object.prototype = nil

function Object.clone(parent,init)
	local newobj = { prototype = parent }
	local meta = { __index = function(obj,key) return obj.prototype[key] end }
	setmetatable(newobj,meta)
	
	if init then
		for k,v in pairs(init) do
			newobj[k] = v
		end
	end
	
	return newobj
end

function Object:isa(type)
	if self.prototype == type then
		return true
	end
	
	if not self.prototype then
		return false
	end
	
	return self.prototype:isa(type) 
end
Entity.lua

Code: Select all

love.filesystem.require("Object.lua")

Entity = Object.clone()

Entity.Name = "IMA NAME"
main.lua

Code: Select all

love.filesystem.require("Object.lua")
love.filesystem.require("Entity.lua")

Player = Entity.clone()

function load()
	
	local font = love.graphics.newFont(love.default_font, 24)
	love.graphics.setFont(font)
	
end

function update(dt)
	
	
	
end

function draw()
	
	
	
end

Re: Classes and Inheritance

Posted: Sat Jun 06, 2009 10:21 pm
by Star Crunch
This is most likely because you do "Object.clone()" and "Entity.clone" where you mean "Object:clone()" and "Entity:clone()".

This leaves parent nil... and thus prototype is nil, so when your __index method tries to index that and finds it missing,
it does an __index again... and again, and again... :P

Re: Classes and Inheritance

Posted: Sat Jun 06, 2009 10:57 pm
by lynerd
Thank you for helping work out my beginner mistake. I had even just read a tutorial on using "object:function()" and "object.function(self)".

I am in "Love" with how I can type up some quick code in this engine and not have to recompile a bunch of stuff like I would in XNA. I always liked to use Verge for this reason, but it never really had a big community to support it. Plus, it seems like tons of games are using the Lua scripting engine for interfaces and more lately. Maybe I can transfer over some experience to making WoW addons.