-
Notifications
You must be signed in to change notification settings - Fork 17
Arx 08 Changing Levels
The next logical step is to deal with the change of levels when there are no more bricks.
For testing purposes I define another level similar to 01.lua
with just minor rearrangements to make it distinct.
return {
name = "second",
bricks = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
{3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
}
}
Levels are switched when there are no more bricks.
So, we need a function inside the BricksContainer
that is going to check, how many bricks are left.
To switch to the next level, it is necessary to read the level from file, create corresponding brick arrangement, reposition the ball and the platform, and update the level counter.
These actions involve interaction with different objects, that bricks_container
doesn't have access to.
Those objects are defined in the main.lua
and that is the place where they should be manipulated.
Therefore, an idea is following: during the update phase, bricks_container
checks the number of remaining blocks.
If there are none, it raises a flag. This flag is checked at the end of love.update
callback at the main.lua
.
function love.update( dt )
.....
bricks_container:update( dt ) --(*1)
.....
resolve_collisions( dt )
switch_to_next_level() --(*2)
end
function BricksContainer:update( dt )
.....
self:check_if_no_more_bricks() --(*3)
end
function BricksContainer:check_if_no_more_bricks() --(*4)
local empty_row = true
for _, brick_row in pairs( self.bricks ) do
if next( brick_row ) == nil then
empty_row = empty_row and true
else
empty_row = empty_row and false
end
end
self.no_more_bricks = empty_row
end
(*1): Number of remaining bricks is checked inside the bricks_container:update()
.
(*2): If there are none, switch to the next level (see below).
(*3), (*4): Actual function that performs remaining bricks check.
Just for consistency I also add the no_more_bricks
field to the BricksContainer
constructor.
function BricksContainer:new( o )
.....
if not o.level then
o:default_level_construction_procedure()
else
o:construct_from_level()
end
o.no_more_bricks = o.no_more_bricks or false
return o
end
The switch_to_next level
function should, in the first place, check bricks_container.no_more_bricks
flag.
If it is true
, it should destroy all objects, that are not necessary any longer, and modify those, that are needed for the next level.
Bricks arrangement should be created from a different level file and the ball and the platform should be repositioned to the start-of-the-level position. Since walls do not need any change, there is no need to touch them.
In practice, instead of repositioning the ball and the platform, I'm just going to destroy and create the new ones.
destroy()
methods for different objects are similar to Brick:destroy()
, defined previously.
function switch_to_next_level()
if bricks_container.no_more_bricks then
level_counter = level_counter + 1
if level_counter > #level_sequence.sequence then
love.event.quit()
else
ball:destroy(); ball = nil
platform:destroy(); platform = nil
bricks_container:destroy(); bricks_container = nil
level_filename = "levels/" .. level_sequence.sequence[ level_counter ]
level = require( level_filename )
ball = Ball:new( { collider = collider } )
platform = Platform:new( { collider = collider } )
bricks_container = BricksContainer:new( { level = level,
collider = collider } )
end
end
end
The one last thing we need is some machinery to handle order of the levels.
This is done by creating levels/sequence.lua
file, which is going to store level files in the
needed order.
return {
name = "level_sequence" ,
sequence = {
"01",
"02",
}
}
On level switch, we update the current level counter and extract the relevant filename from the .sequence
field.
We also need some updates in love.load()
to load levels/sequence
and initialize the level_counter
.
function love.load()
level_sequence = require "levels/sequence"
level_counter = 1
if level_counter > #level_sequence.sequence then
love.event.quit()
end
level_filename = "levels/" .. level_sequence.sequence[ level_counter ]
level = require( level_filename )
collider = HC.new()
.....
end
Optional:
To facilitate the process of bricks destruction, it is possible to add brick:mousepressed()
callback:
if you click inside the area of any of the bricks, the brick.to_destroy
flag is raised.
function love.mousepressed( x, y, button, istouch )
bricks_container:mousepressed( x, y, button, istouch )
end
function BricksContainer:mousepressed( x, y, button, istouch )
for _, brick_row in pairs( self.bricks ) do
for _, brick in pairs( brick_row ) do
brick:mousepressed( x, y, button, istouch )
end
end
end
function Brick:mousepressed( x, y, button, istouch )
if button == 'l' or button == 1 then
if self.position.x < x and x < ( self.position.x + self.width ) and
self.position.y < y and y < ( self.position.y + self.height ) then
self.to_destroy = true
end
end
end
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: