-
Notifications
You must be signed in to change notification settings - Fork 17
Game Objects as Lua Tables
In the first part, several game objects have been introduced. Before moving further, it is useful to establish a way the game objects are represented in the code.
In complex games a number of interacting game objects can be wast and it is common to use object-oriented approach in the code to organize and structure them. In such case, each game object is represented as an instance of a class. For simple games, such as this one, it is not necessary, and it is suffice to use basic Lua functionality and represent each game object as a simple Lua table. However, I plan to demonstrate how to use an object-oriented approach in the appendices.
Regarding the initial code, a first thing to notice is that love.update
and love.draw
can be split into several functions, corresponding to update and draw of independent game objects:
function love.update( dt )
ball.update( dt )
platform.update( dt )
.....
end
function love.draw()
ball.draw()
platform.draw()
.....
end
The ball.update
and ball.draw
are defined as
function ball.update( dt )
ball.position_x = ball.position_x + ball.speed_x * dt
ball.position_y = ball.position_y + ball.speed_y * dt
end
function ball.draw()
local segments_in_circle = 16
love.graphics.circle( 'line',
ball.position_x,
ball.position_y,
ball.radius,
segments_in_circle )
end
The functions for the platform are similar.
With bricks, however, the situation is more complicated.
First of all, there are going to be several of them, each one with it's own characteristics.
I rename the brick
table from the previous part into bricks
, where I'm going to store all the relevant information. Individual bricks themselves are going to be stored in the bricks.current_level_bricks
table, which will be populated on level construction.
local bricks = {}
bricks.current_level_bricks = {}
.....
Each single brick is represented as a table with position_x
, position_y
, width
and height
fields.
I define a special function bricks.new_brick
to construct such objects:
function bricks.new_brick( position_x, position_y, width, height )
return( { position_x = position_x,
position_y = position_y,
width = width or bricks.brick_width, --(*1)
height = height or bricks.brick_height } )
end
(*1): x = a or b
is a common idiom in Lua. If a
is not nil
and not false
, than the result of a or b
expression is a
and x = a
, otherwise the result of a or b
is b
and x = b
. It is commonly used in function definitions to provide default values to variables where it has a form local_to_function_variable = function_argument or default_value
. If the user does not provide function_argument
to the function call, it's value is nil
and default_value
is used. In this case, if width
is supplied as an argument to the bricks.new_brick
call, than that value is used; otherwise the default one bricks.brick_width
is used.
To draw an individual brick, the following function is used:
function bricks.draw_brick( single_brick )
love.graphics.rectangle( 'line',
single_brick.position_x,
single_brick.position_y,
single_brick.width,
single_brick.height )
end
As before, there is nothing to update
in brick:
function bricks.update_brick( single_brick )
end
To add a newly constructed brick to bricks.current_level_bricks
table, special function is defined:
function bricks.add_to_current_level_bricks( brick )
table.insert( bricks.current_level_bricks, brick )
end
For demonstration purposes, I explicitly construct several bricks in love.load
:
function love.load()
bricks.add_to_current_level_bricks( bricks.new_brick( 100, 100 ))
bricks.add_to_current_level_bricks( bricks.new_brick( 160, 100 ))
.....
end
It is possible to update and draw each brick by iterating over bricks.current_level_bricks
and
calling the corresponding function for each individual brick:
function bricks.draw()
for _, brick in pairs( bricks.current_level_bricks ) do --(*1)
bricks.draw_brick( brick )
end
end
function bricks.update( dt )
for _, brick in pairs( bricks.current_level_bricks ) do
bricks.update_brick( brick )
end
end
(*1): an underscore _
is a valid Lua name, that is commonly used for dumb variables,
that are not necessary in the further code.
Calls to these functions have to be placed in the love.update
and love.draw
.
function love.update( dt )
ball.update( dt )
platform.update( dt )
bricks.update( dt )
end
function love.draw()
ball.draw()
platform.draw()
bricks.draw()
end
← 1.1 - The Ball, The Brick, The Platform
↑ To the top
1.3 - Bricks and Walls →
Feedback is crucial to improve the tutorial!
Let me know if you have any questions, critique, suggestions or just any other ideas.
Chapter 1: Prototype
- The Ball, The Brick, The Platform
- Game Objects as Lua Tables
- Bricks and Walls
- Detecting Collisions
- Resolving Collisions
- Levels
Appendix A: Storing Levels as Strings
Appendix B: Optimized Collision Detection (draft)
Chapter 2: General Code Structure
- Splitting Code into Several Files
- Loading Levels from Files
- Straightforward Gamestates
- Advanced Gamestates
- Basic Tiles
- Different Brick Types
- Basic Sound
- Game Over
Appendix C: Stricter Modules (draft)
Appendix D-1: Intro to Classes (draft)
Appendix D-2: Chapter 2 Using Classes.
Chapter 3 (deprecated): Details
- Improved Ball Rebounds
- Ball Launch From Platform (Two Objects Moving Together)
- Mouse Controls
- Spawning Bonuses
- Bonus Effects
- Glue Bonus
- Add New Ball Bonus
- Life and Next Level Bonuses
- Random Bonuses
- Menu Buttons
- Wall Tiles
- Side Panel
- Score
- Fonts
- More Sounds
- Final Screen
- Packaging
Appendix D: GUI Layouts
Appendix E: Love-release and Love.js
Beyond Programming: