Classes in Gideros
The Ultimate Guide to Gideros Studio
Classes in Gideros
Lua does not support classes the way languages like C++, Java or ActionScript do. Lua is a multi-paradigm language and inherits from prototype-based languages.
In Lua, each object can define its own behavior through metatables, therefore, it is possible to emulate OO programming and classes.
Note: for a detailed discussion of object-oriented programming in Lua, please refer to http://www.lua.org/pil/16.html
Gideros follows the same paradigm in its API design. Each instance created by Gideros API is a Lua table with a metatable attached.
Instances in Gideros are created through the .new function. Consider the following examples:
local sprite = Sprite.new() local texture = Texture.new("image.png") local bitmap = Bitmap.new(texture) local timer = Timer.new(1000, 0)
The Core.class function is used to create your own classes through inheritance (older versions of Gideros used the gideros.class function -- this function has been deprecated).
You can inherit from Gideros API's classes e.g. EventDispatcher, Sprite, etc, or from your own classes. For example, you can create your own class that inherits from EventDispatcher class like so:
MyEventDispatcher = Core.class(EventDispatcher)
You can also create a new class by using Core.class with no arguments:
MyOwnClass = Core.class()
By using Inheritance, you design and implement the visual elements of your game separately:
-- create your own start button class StartButton = Core.class(Sprite) -- create your own menu class Menu = Core.class(Sprite) -- create your own player class Player = Core.class(Sprite) function Player:walk() -- walk logic end function Player:jump() -- jump logic end -- create and add a player instance to the stage stage:addChild(Player.new())
When an instance is created, the init function is called first:
Player = Core.class(Sprite) function Player:init() -- do the initialization of Player instance self.health = 100 self.speed = 3 end -- after Player instance is created, init function is called local player = Player.new()
Whether to use inheritance or not is related to your programming taste. It is possible to implement a whole game without creating classes. You can refer to "Jumping Ball" and "Jumping Balls" examples in Gideros Studio, to see the difference between designing your code with classes or not.
Using classes makes it easier to reuse code.
Inheriting From Classes With Constructor Arguments
If you inherit from a class that takes a constructor argument, your new class has to pass in the arguments that the base class expects as its first argument. You can then pass in any additional arguments:
MyBitmap = Core.class(Bitmap) function MyBitmap:init(texture, additional args) .... end
Here's a very simple example:
A = Core.class() function A:init(msg1) print("A:init("..msg1..")") end B = Core.class(A) function B:init(msg1, msg2) print("B:init("..msg1..","..msg2..")") end B.new("hello","world")
This example produces:
Adding Explicit Dependencies for Inherited Classes
You can put class definitions in different files, but if it doesn't work, it may be because the files are being loaded in the wrong order. You can specify file dependencies in the IDE. To do so, select a file, right click, then select "Code Dependencies".
For example, if class A (in classA.lua) inherits from class B (in classB.lua) and you're getting a message like "attempt to index global 'B' (a nil value)" during the initialization process, select "classA.lua" and add a dependency on classB.lua.
Accessing Overridden Functions
If you inherit from a class and override one of its functions, you have to call the overridden function using syntax like "BaseClassName.function(self)". Here's an example:
-- -------------------------------------- A = Core.class() function A:init(msg1) self.text = "I am an A" end function A:method() print(self.text .. " in A:method()") end -- -------------------------------------- B = Core.class(A) function B:init(msg1, msg2) self.text = "I am a B" end function B:method(arg1) print(self.text .. " in B:method()") --A:method() <--- NOT THIS A.method(self) end -- -------------------------------------- b = B.new("hello","world") b:method()
This will produce:
I am a B in B:method() I am a B in A:method()
If you try to use "A:method()" in "B:method()" you'll get an error about a nil value for the 'text' field. That is because you are using the "A" instance that was created in the "A = Core.class()" line (equivalent to "A.method(A)").
If you try to use "self:method()", you'll be recursively calling "B:method()".