Difference between revisions of "Classes"

From GiderosMobile
(Created page with "Lua does not support classes the way languages like C++, Java and ActionScript do. But Lua is a multi-paradigm language and have roots from prototype-based languages. In Lua,...")
 
m (Text replacement - "</source>" to "</syntaxhighlight>")
 
(4 intermediate revisions by 3 users not shown)
Line 9: Line 9:
 
Instances in Gideros is created through new function. For example, to create a Sprite, Texture, Bitmap and a Timer instance:
 
Instances in Gideros is created through new function. For example, to create a Sprite, Texture, Bitmap and a Timer instance:
  
<source lang="lua">
+
<syntaxhighlight lang="lua">
 
local sprite = Sprite.new()
 
local sprite = Sprite.new()
 
local texture = Texture.new("image.png")
 
local texture = Texture.new("image.png")
 
local bitmap = Bitmap.new(texture)
 
local bitmap = Bitmap.new(texture)
 
local timer = Timer.new(1000, 0)
 
local timer = Timer.new(1000, 0)
</source>
+
</syntaxhighlight>
  
 
=== Inheritance ===
 
=== Inheritance ===
Line 20: Line 20:
 
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 now been deprecated). You can inherit from Gideros API's own classes (EventDispatcher, Sprite, etc.) or from your own classes. For example, you can create your own class that inherits from EventDispatcher class like so:
 
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 now been deprecated). You can inherit from Gideros API's own classes (EventDispatcher, Sprite, etc.) or from your own classes. For example, you can create your own class that inherits from EventDispatcher class like so:
  
<source lang="lua">
+
<syntaxhighlight lang="lua">
 
MyEventDispatcher = Core.class(EventDispatcher)
 
MyEventDispatcher = Core.class(EventDispatcher)
</source>
+
</syntaxhighlight>
 +
<br/>
  
 
You can also create a new class by using Core.class with no arguments:
 
You can also create a new class by using Core.class with no arguments:
  
<source lang="lua">
+
<syntaxhighlight lang="lua">
 
MyOwnClass = Core.class()
 
MyOwnClass = Core.class()
</source>
+
</syntaxhighlight>
 +
<br/>
  
 
By using Inheritance, you can design and implement the visual elements of your game separately:
 
By using Inheritance, you can design and implement the visual elements of your game separately:
  
<source lang="lua">
+
<syntaxhighlight lang="lua">
 
-- create your own start button class
 
-- create your own start button class
 +
StartButton = Core.class(Sprite)
  
StartButton = Core.class(Sprite)
 
 
-- create your own menu class
 
-- create your own menu class
 
 
Menu = Core.class(Sprite)           
 
Menu = Core.class(Sprite)           
  
Line 53: Line 54:
 
-- create and add a player instance to the stage
 
-- create and add a player instance to the stage
 
stage:addChild(Player.new())           
 
stage:addChild(Player.new())           
</source>
+
</syntaxhighlight>
 +
<br/>
  
 
When an instance is created, init function is called to do the initialization:
 
When an instance is created, init function is called to do the initialization:
  
<source lang="lua">
+
<syntaxhighlight lang="lua">
 
Player = Core.class(Sprite)
 
Player = Core.class(Sprite)
  
 
function Player:init()
 
function Player:init()
        -- do the initialization of Player instance
+
  -- do the initialization of Player instance
        self.health = 100
+
  self.health = 100
        self.speed = 3
+
  self.speed = 3
 
end
 
end
  
 
-- after Player instance is created, init function is called
 
-- after Player instance is created, init function is called
 
local player = Player.new()                 
 
local player = Player.new()                 
</source>
+
</syntaxhighlight>
 +
<br/>
  
 
Whether to use inheritance or not is related to your programming taste. It's possible to implement a whole game without creating custom classes. You can refer to "Jumping Ball" and "Jumping Balls" examples to see the difference between designing your code with classes or not.
 
Whether to use inheritance or not is related to your programming taste. It's possible to implement a whole game without creating custom classes. You can refer to "Jumping Ball" and "Jumping Balls" examples to see the difference between designing your code with classes or not.
Line 78: Line 81:
 
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 arguments.  You can then pass in any additional 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 arguments.  You can then pass in any additional arguments:
  
<source lang="lua">
+
<syntaxhighlight lang="lua">
 
MyBitmap = Core.class(Bitmap)
 
MyBitmap = Core.class(Bitmap)
  
Line 84: Line 87:
 
   ....
 
   ....
 
end
 
end
</source>
+
</syntaxhighlight>
 +
<br/>
  
 
Here's a very simple example:
 
Here's a very simple example:
  
<source lang="lua">
+
<syntaxhighlight lang="lua">
 
A = Core.class()
 
A = Core.class()
  
Line 102: Line 106:
  
 
B.new("hello","world")
 
B.new("hello","world")
</source>
+
</syntaxhighlight>
 +
<br/>
  
 
This example produces:
 
This example produces:
 
+
<pre>
<source lang="lua">
 
 
A:init(hello)
 
A:init(hello)
 
B:init(hello,world)
 
B:init(hello,world)
</source
+
</pre>
 +
<br/>
  
 
=== Adding Explicit Dependencies for Inherited Classes ===
 
=== Adding Explicit Dependencies for Inherited Classes ===
Line 120: Line 125:
  
 
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:
 
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:
 
+
<syntaxhighlight lang="lua">
<source lang="lua">
 
 
-- --------------------------------------
 
-- --------------------------------------
  
Line 141: Line 145:
 
   self.text = "I'm a B"
 
   self.text = "I'm a B"
 
end
 
end
 
  
 
function B:method(arg1)
 
function B:method(arg1)
Line 153: Line 156:
 
b = B.new("hello","world")
 
b = B.new("hello","world")
 
b:method()
 
b:method()
</source>
+
</syntaxhighlight>
 +
<br/>
  
 
This will produce:
 
This will produce:
 
+
<pre>
<source lang="lua">
 
 
I'm a B in B:method()
 
I'm a B in B:method()
 
I'm a B in A:method()
 
I'm a B in A:method()
</source>
+
</pre>
 +
<br/>
  
 
If you try to use "A:method()" in "B:method()" you'll get an error about a nil value for the 'text' field.  That's because you're using the "A" instance that was created in the "A = Core.class()" line (equivalent to "A.method(A)").
 
If you try to use "A:method()" in "B:method()" you'll get an error about a nil value for the 'text' field.  That's because you're 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()"
 
If you try to use "self:method()", you'll be recursively calling "B:method()"
 +
 +
 +
<br/>

Latest revision as of 14:27, 13 July 2023

Lua does not support classes the way languages like C++, Java and ActionScript do. But Lua is a multi-paradigm language and have roots from prototype-based languages. In Lua, each object can define its own behaviour through metatables. Therefore, it is possible to emulate OO programming and classes in Lua.

Note: For the 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.

Creating Instances

Instances in Gideros is created through new function. For example, to create a Sprite, Texture, Bitmap and a Timer instance:

local sprite = Sprite.new()
local texture = Texture.new("image.png")
local bitmap = Bitmap.new(texture)
local timer = Timer.new(1000, 0)

Inheritance

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 now been deprecated). You can inherit from Gideros API's own classes (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 can 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, init function is called to do the initialization:

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's possible to implement a whole game without creating custom classes. You can refer to "Jumping Ball" and "Jumping Balls" examples 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 arguments. 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:

A:init(hello)
B:init(hello,world)


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. 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'm 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'm 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'm a B in B:method()
I'm 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's because you're 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()"