Skip to content

Arx 12 Different Brick Types

noooway edited this page Jan 25, 2017 · 2 revisions

So far all of the bricks react on the ball collision similarly - they disappear on the first hit. In this part I'm going to add bricks, that can take several hits.

To implement different reactions, it is necessary to change the brick response on collision with the ball. The idea is simple: we know the type of each brick, and we need to check it in collision. That is, most of the changes will concern the Brick:react_on_ball_collision function.

Currently, the brick type is encoded by a two-digit number. We can continue to work with that, however, it helps the code readability to define human readable types. It is possible to create a table, that maps two-digit types to human readable descriptions. Instead, I'll use a simpler approach and just define several methods that determine brick properties based on it's type number.

Brick colors are blue, green, orange, orange, purple, red and yellow. In the first row bricks are 'simple', in the second -- 'armored', third -- 'scratched', fourth -- 'cracked'. Fifth row is 'heavyarmored'.

The appropriate methods are following:

function Brick:is_simple()
   local row = math.floor( self.bricktype / 10 )
   return ( row == 1 )
end

function Brick:is_armored()
   local row = math.floor( self.bricktype / 10 )
   return ( row == 2 )
end

function Brick:is_scratched()
   local row = math.floor( self.bricktype / 10 )
   return ( row == 3 )
end

function Brick:is_cracked()
   local row = math.floor( self.bricktype / 10 )
   return ( row == 4 )
end

function Brick:is_heavyarmored()
   local row = math.floor( self.bricktype / 10 )
   return ( row == 5 )
end

If the brick is 'simple', it is destroyed on the collision with the ball. If it is 'armored', after collision it's type is changed to 'scratched'. 'Scratched' becomes 'cracked'. 'Cracked' is destroyed on collision. 'Heavyarmored' bricks are unaffected by collisions.

Here is a template for case analysis in the Brick:react_on_ball_collision:

function Brick:react_on_ball_collision( another_shape, separating_vector )
   local big_enough_overlap = 0.5
   local dx, dy = separating_vector.x, separating_vector.y
   if ( math.abs( dx ) > big_enough_overlap ) or
      ( math.abs( dy ) > big_enough_overlap ) then
         if self:is_simple() then
            .....
         elseif self:is_armored() then
            .....
         elseif self:is_scratched() then
            .....
         elseif self:is_cracked() then
            .....
         elseif self:is_heavyarmored() then
            .....
         end
   end
end

If the brick should be destroyed, it is enough to simply raise the to_destroy flag. To change brick type, it is convenient to have a special functions: armored_to_scratched and scratched_to_cracked. We can implement them simply by adding 10 to the brick type. After brick type is changed we also have to redefine it's quad; this is done by calling the bricktype_to_quad method.

function Brick:armored_to_scratched()
   self.bricktype = self.bricktype + 10
   self.quad = self:bricktype_to_quad()
end

function Brick:scratched_to_cracked()
   self.bricktype = self.bricktype + 10
   self.quad = self:bricktype_to_quad()
end

With these functions, the collision resolution code looks like this:

function Brick:react_on_ball_collision(	another_shape, separating_vector )
   local big_enough_overlap = 0.5
   local dx, dy = separating_vector.x, separating_vector.y
   if ( math.abs( dx ) > big_enough_overlap ) or
	  ( math.abs( dy ) > big_enough_overlap ) then
	 if self:is_simple() then
		self.to_destroy = true
	 elseif self:is_armored() then
		self:armored_to_scratched()
	 elseif self:is_scratched() then
		self:scratched_to_cracked()
	 elseif self:is_cracked() then
		self.to_destroy = true
	 elseif self:is_heavyarmored() then
	 end
   end
end

It is also necessary not to forget to remove 'heavyarmored' bricks from check for next level switch:

function BricksContainer:check_if_no_more_bricks()
   local empty_row = true
   for _, brick_row in pairs( self.bricks ) do
      local __, brick = next( brick_row )
      if brick == nil then                  --(*1)
         empty_row = empty_row and true
      else
         if brick:is_heavyarmored() then    --(*2)
            empty_row = empty_row and true
         else
            empty_row = empty_row and false 
         end
      end
   end
   self.no_more_bricks = empty_row
end

(*1): If there are no more bricks in the row, the row is empty.
(*2): If there are bricks, but their type is 'heavyarmored', we ignore them.

    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