Skip to content

Arx 08 Changing Levels

noooway edited this page Jan 15, 2017 · 1 revision

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

    Home
    Acknowledgements
    Todo

Chapter 1: Prototype

  1. The Ball, The Brick, The Platform
  2. Game Objects as Lua Tables
  3. Bricks and Walls
  4. Detecting Collisions
  5. Resolving Collisions
  6. Levels

    Appendix A: Storing Levels as Strings
    Appendix B: Optimized Collision Detection (draft)

Chapter 2: General Code Structure

  1. Splitting Code into Several Files
  2. Loading Levels from Files
  3. Straightforward Gamestates
  4. Advanced Gamestates
  5. Basic Tiles
  6. Different Brick Types
  7. Basic Sound
  8. 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

  1. Improved Ball Rebounds
  2. Ball Launch From Platform (Two Objects Moving Together)
  3. Mouse Controls
  4. Spawning Bonuses
  5. Bonus Effects
  6. Glue Bonus
  7. Add New Ball Bonus
  8. Life and Next Level Bonuses
  9. Random Bonuses
  10. Menu Buttons
  11. Wall Tiles
  12. Side Panel
  13. Score
  14. Fonts
  15. More Sounds
  16. Final Screen
  17. Packaging

    Appendix D: GUI Layouts
    Appendix E: Love-release and Love.js

Beyond Programming:

  1. Game Design
  2. Minimal Marketing (draft)
  3. Finding a Team (draft)

Archive

Clone this wiki locally