Skip to content

Random Bonuses

noooway edited this page May 21, 2017 · 53 revisions

Currently bonuses generated on bricks destruction are predefined in the level description. In this part I want to add random bonus generation into the game.



First, in the level map some way to denote that a bonus to create on brick destruction should be random is necessary. It's possible to reserve any number or a string for this, but I simply use 00.

function bonuses.bonustype_denotes_random( bonustype )
   return bonustype == 0
end

Bonuses are generated on bricks destruction by bonus.generate_bonus function.

function bricks.brick_hit_by_ball( i, brick, shift_ball, bonuses )
   if bricks.is_simple( brick ) then
      bonuses.generate_bonus(
         vector( brick.position.x + brick.width / 2,
                 brick.position.y + brick.height / 2 ),
         brick.bonustype )
      table.remove( bricks.current_level_bricks, i )
   .....
   end
end

In this function, a bonustype associated with the brick is checked. If it is one of the previously defined "valid" bonustypes (from 11 to 18), a corresponding bonus is generated. Check on random bonustype also should be placed in this function. To explicitly tell, that no bonus should be associated with the brick, it is enough to provide any "invalid" bonustype, such as -1.

function bonuses.generate_bonus( position, bonustype )
   if bonuses.bonustype_denotes_random( bonustype ) then
      bonustype = bonuses.random_bonustype()
   end
   if bonuses.valid_bonustype( bonustype ) then
      bonuses.add_bonus( bonuses.new_bonus( position, bonustype ) )
   end
end

function bonuses.valid_bonustype( bonustype )
   if bonustype and bonustype > 10 and bonustype < 19 then
      return true
   else
      return false
   end
end

Random bonus generation is done under following scheme. There are valuable bonuses and common bonuses; valuable are "Add Life" and "Next Level", common are everything else. I want a common bonus to appear approximately each 10 brick, and a valuable bonus - approximately once in 5 levels. There are maximum 8*11 ~ 90 bricks in each level. Since usually there are some unbreakable and missing bricks, there are, roughly 80 bricks per level or 400 bricks in 5 levels. So, on brick destruction, a common bonus (of randomly decided type) should drop with probability 1/10 and one of the valuable bonuses - with probability 1/400. It might be reasonable to increase those probabilities for armored blocks compared to simple, but I don't want to do this.

If a random number in interval [1,400] is generated, a probability to get a certain predefined number, say 293 or 400, is exactly 1/400. To obtain an event with probability of 1/10, it is necessary to agree on 40 such numbers ( 40 numbers * 1/400 prob for each number = 1/10), an interval [360, 399] for example.

It is possible to generate a bonus with two rolls of dice: on the first roll decide whether a valuable bonus should be generated, a common, or no bonus at all. Then in the two former cases decide an exact type with the second roll.

local bonustype_rng = love.math.newRandomGenerator( os.time() )    --(*1)

function bonuses.random_bonustype()
   local bonustype
   local prob = bonustype_rng:random( 400 )
   if prob == 400 then
      bonustype = bonuses.choose_random_valuable_bonus()
   elseif prob >= 360 then
      bonustype = bonuses.choose_random_common_bonus()
   else
      bonustype = nil
   end
   return bonustype
end

function bonuses.choose_random_valuable_bonus()
   local valuable_bonustypes = { 17, 18 }
   return valuable_bonustypes[ bonustype_rng:random( #valuable_bonustypes )]
end

function bonuses.choose_random_common_bonus()
   local common_bonustypes = { 11, 12, 13, 14, 15, 16 }
   return common_bonustypes[ bonustype_rng:random( #common_bonustypes )]
end

(*1): To generate random bonustype first it is necessary to initialize random number generator.

Instead of using two calls to a random number generator, it is possible to generate a bonus in a single call. For this, it is necessary to map a correspondence between certain intervals and bonustypes, instead of dividing the range simply into "common bonuses" and "valuable bonuses".

The "valuable bonus" event with probability 1/400 consists of two events "Next Level" and "Add Life" with probabilities 1/800 (1/800 prob for "add life" + 1/800 prob for "next level" = 1/400 prob for "valuable bonus"). Thus, instead of using range [1,400] it is necessary to use [1,800]. Let's assign 800 to "Add Life", and 799 to "Next Level". A common bonus should be generated if the number falls in a range [798-800/10=718, 798]. It should be split in 6 intervals and a common bonustype assigned to each one, e.g. "Slowdown" is in the range [718, 718 + (798-718)/6], "Accelerate" is in the range [718 + 4*(798-718)/6, 718 + 5*(798-718)/6] and so on.



local bonustype_rng = love.math.newRandomGenerator( os.time() )

function bonuses.random_bonustype()
   local bonustype
   local common_bonuses = { 11, 12, 13, 14, 15, 16 }
   local common_bonus_range = (798 - 718) / ( #common_bonuses )
   local prob = bonustype_rng:random( 800 )
   if prob == 800 then
      bonustype = 18
   elseif prob == 799 then
      bonustype = 17
   elseif prob >= 718 then
      bonustype = 
         common_bonuses[1 + math.floor(( prob - 718 ) / common_bonus_range)]  --(*1)
   else
      bonustype = nil
   end
   return bonustype
end

(*1): such method introduces rounding which results in uneven probabilities, but the difference is not very significant.

    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