1- # TO DO: pylint the code, clean up play mechanic a bit
2-
31"""
42Dragon Drop: a simple game for Adafruit MACROPAD. Uses OLED display in
53portrait (vertical) orientation. Tap one of four keys across a row to
2321
2422# CONFIGURABLES ------------------------
2523
26- MAX_EGGS = 7 # Some are fireballs; max count of all projectiles
24+ MAX_EGGS = 7 # Max count of all projectiles; some are fireballs
2725PATH = '/dragondrop/' # Location of graphics, fonts, WAVs, etc.
2826
2927
@@ -51,8 +49,8 @@ def show_screen(group):
5149# pylint: disable=too-few-public-methods
5250class Sprite :
5351 """ Class holds sprite (eggs, fireballs) state information. """
54- def __init__ (self , column , start_time ):
55- self .column = column # 0-3
52+ def __init__ (self , col , start_time ):
53+ self .column = col # 0-3
5654 self .is_fire = (random .random () < 0.25 ) # 1/4 chance of fireballs
5755 self .start_time = start_time # For drop physics
5856 self .paused = False
@@ -94,6 +92,7 @@ def __init__(self, column, start_time):
9492 tile_height = SHADOW_BITMAP .height , x = 0 ,
9593 y = MACROPAD .display .height - SHADOW_BITMAP .height )
9694PLAY_GROUP .append (SHADOW )
95+ SHADOW_SCALE = 5 / (MACROPAD .display .height - 20 ) # For picking shadow sprite
9796LIFE_BAR = HorizontalProgressBar ((0 , 0 ), (MACROPAD .display .width , 7 ),
9897 value = 100 , min_value = 0 , max_value = 100 ,
9998 bar_color = 0xFFFFFF , outline_color = 0xFFFFFF ,
@@ -118,7 +117,7 @@ def __init__(self, column, start_time):
118117 90 )))
119118
120119
121- # MAIN LOOP -- alternates play and end-game screens
120+ # MAIN LOOP -- alternates play and end-game screens --------
122121
123122show_screen (TITLE_GROUP ) # Just do this once on startup
124123
@@ -128,7 +127,7 @@ def __init__(self, column, start_time):
128127
129128 SPRITES = []
130129 SCORE = 0
131- PLAY_GROUP [- 1 ].text = '0'
130+ PLAY_GROUP [- 1 ].text = '0' # Score text
132131 LIFE_BAR .value = 100
133132 AUDIO .stop ()
134133 MACROPAD .display .show (PLAY_GROUP )
@@ -158,91 +157,90 @@ def __init__(self, column, start_time):
158157 # Traverse sprite list backwards so we can pop() without index problems
159158 for i in range (len (SPRITES ) - 1 , - 1 , - 1 ):
160159 sprite = SPRITES [i ]
161- COLUMN = sprite . column
162- TILE = PLAY_GROUP [ i + 1 ] # Corresponding TileGroup for sprite
163- ELAPSED = NOW - sprite .start_time # Time since add or pause event
160+ tile = PLAY_GROUP [ i + 1 ] # Corresponding 1x1 TileGrid for sprite
161+ column = sprite . column
162+ elapsed = NOW - sprite .start_time # Time since add or pause event
164163
165164 if sprite .is_fire :
166- TILE [0 ] = FIRE_SPRITE
165+ tile [0 ] = FIRE_SPRITE # Animate all flame sprites
167166
168- if sprite .paused :
169- if ELAPSED > 0.75 : # Hold position for 3/4 second,
170- for x in range (0 , 9 , 4 ):
167+ if sprite .paused : # Sprite at bottom of screen
168+ if elapsed > 0.75 : # Hold position for 3/4 second,
169+ for x in range (0 , 9 , 4 ): # then LEDs off,
171170 MACROPAD .pixels [x + sprite .column ] = (0 , 0 , 0 )
172- SPRITES .pop (i ) # then delete Sprite object and
173- PLAY_GROUP .pop (i + 1 ) # element from displayio group
171+ SPRITES .pop (i ) # and delete Sprite object and
172+ PLAY_GROUP .pop (i + 1 ) # element from displayio group
174173 continue
175174 if not sprite .is_fire :
176- COLUMN_MAX [COLUMN ] = max (COLUMN_MAX [COLUMN ], MACROPAD .display .height - 22 )
177- else :
178- y = SPEED * ELAPSED * ELAPSED - 16
179- COLUMN_MIN [COLUMN ] = min (COLUMN_MIN [COLUMN ], y )
175+ COLUMN_MAX [column ] = max (COLUMN_MAX [column ],
176+ MACROPAD .display .height - 22 )
177+ else : # Sprite in motion
178+ y = SPEED * elapsed * elapsed - 16
179+ # Track top of all sprites, bottom of eggs only
180+ COLUMN_MIN [column ] = min (COLUMN_MIN [column ], y )
180181 if not sprite .is_fire :
181- COLUMN_MAX [COLUMN ] = max (COLUMN_MAX [COLUMN ], y )
182- TILE .y = int (y ) # Sprite's vertical position in PLAY_GROUP list
182+ COLUMN_MAX [column ] = max (COLUMN_MAX [column ], y )
183+ tile .y = int (y ) # Sprite's vertical pos. in PLAY_GROUP
183184
185+ # Handle various catch or off-bottom actions...
184186 if sprite .is_fire :
185- if y >= MACROPAD .display .height :
186- SPRITES .pop (i )
187+ if y >= MACROPAD .display .height : # Off bottom of screen,
188+ SPRITES .pop (i ) # remove fireball sprite
187189 PLAY_GROUP .pop (i + 1 )
188190 continue
189- else :
190- # Animate fire sprites
191- TILE [0 ] = 3 + int ((NOW * 6 ) % 2.0 )
192- # Fire catch logic
193- if y >= MACROPAD .display .height - 40 and COLUMN_PRESSED [COLUMN ]:
194- background_sound ('sizzle.wav' )
195-
191+ elif y >= MACROPAD .display .height - 40 :
192+ if COLUMN_PRESSED [column ]:
193+ # Fireball caught, ouch!
194+ background_sound ('sizzle.wav' ) # I smell bacon
196195 sprite .paused = True
197196 sprite .start_time = NOW
198- TILE .y = MACROPAD .display .height - 20
197+ tile .y = MACROPAD .display .height - 20
199198 LIFE_BAR .value = max (0 , LIFE_BAR .value - 5 )
200199 for x in range (0 , 9 , 4 ):
201200 MACROPAD .pixels [x + sprite .column ] = (255 , 0 , 0 )
202- else :
201+ else : # Is egg...
203202 if y >= MACROPAD .display .height - 22 :
204203 # Egg hit ground
205204 background_sound ('splat.wav' )
206- TILE .y = MACROPAD .display .height - 22
207- TILE [0 ] = 1 # Broken egg
208205 sprite .paused = True
209206 sprite .start_time = NOW
207+ tile .y = MACROPAD .display .height - 22
208+ tile [0 ] = 1 # Change sprite to broken egg
210209 LIFE_BAR .value = max (0 , LIFE_BAR .value - 5 )
211210 MACROPAD .pixels [8 + sprite .column ] = (255 , 255 , 0 )
212- elif y >= MACROPAD . display . height - 40 :
213- if COLUMN_PRESSED [ COLUMN ] :
211+ elif COLUMN_PRESSED [ column ] :
212+ if y >= MACROPAD . display . height - 40 :
214213 # Egg caught at right time
215214 background_sound ('rawr.wav' )
216- TILE .y = MACROPAD .display .height - 22
217- TILE [0 ] = 2 # Dragon hatchling
218- SCORE += 10
219- PLAY_GROUP [- 1 ].text = str (SCORE )
220215 sprite .paused = True
221216 sprite .start_time = NOW
217+ tile .y = MACROPAD .display .height - 22
218+ tile [0 ] = 2 # Hatchling
222219 MACROPAD .pixels [4 + sprite .column ] = (0 , 255 , 0 )
223- elif y >= MACROPAD .display .height - 58 :
224- if COLUMN_PRESSED [COLUMN ]:
225- # Egg caught too soon
220+ SCORE += 10
221+ PLAY_GROUP [- 1 ].text = str (SCORE )
222+ elif y >= MACROPAD .display .height - 58 :
223+ # Egg caught too early
226224 background_sound ('splat.wav' )
227- TILE .y = MACROPAD .display .height - 40
228- TILE [0 ] = 1 # Broken egg
229225 sprite .paused = True
230226 sprite .start_time = NOW
227+ tile .y = MACROPAD .display .height - 40
228+ tile [0 ] = 1 # Broken egg
231229 LIFE_BAR .value = max (0 , LIFE_BAR .value - 5 )
232230 MACROPAD .pixels [sprite .column ] = (255 , 255 , 0 )
233231
234- # Select shadow bitmaps based on each column's lowest sprite
232+ # Select shadow bitmaps based on each column's lowest egg
235233 for i in range (4 ):
236- SHADOW [i ] = min (4 , int (5 * COLUMN_MAX [i ] / ( MACROPAD . display . height - 20 ) ))
237-
238- # Time to introduce a new sprite?
239- if len (SPRITES ) < MAX_EGGS and random .random () < 0.05 :
240- if max (COLUMN_MIN ) > 16 : # At least one column has space
241- while True :
242- COLUMN = random . randint ( 0 , 3 )
243- if COLUMN_MIN [ COLUMN ] <= 16 :
244- continue
245- # Found a spot. Add sprite and break loop
234+ SHADOW [i ] = min (4 , int (COLUMN_MAX [i ] * SHADOW_SCALE ))
235+
236+ # Time to introduce a new sprite? 1/20 chance each frame, if space
237+ if ( len (SPRITES ) < MAX_EGGS and random .random () < 0.05 and
238+ max (COLUMN_MIN ) > 16 ):
239+ # Pick a column randomly...if it's occupied, keep trying...
240+ while True :
241+ COLUMN = random . randint ( 0 , 3 )
242+ if COLUMN_MIN [ COLUMN ] > 16 :
243+ # Found a clear spot. Add sprite and break loop
246244 SPRITES .append (Sprite (COLUMN , NOW ))
247245 PLAY_GROUP .insert (- 2 , displayio .TileGrid (SPRITE_BITMAP ,
248246 pixel_shader = SPRITE_PALETTE ,
0 commit comments