1313# Overclock. It doesn't seem to run above 250MHz
1414freq (266_000_000 )
1515
16- from thumbyButton import buttonA , buttonB , buttonU , buttonD , buttonL , buttonR , dpadPressed
16+ from thumbyButton import buttonA , buttonB , buttonU , buttonD , buttonL , buttonR , dpadPressed , inputJustPressed
1717from thumbyHardware import reset
1818from random import randint , randrange , choice
1919from time import sleep
2020from utime import ticks_us , ticks_diff
2121from math import sin , pi , cos , exp
2222from array import array
2323from gc import collect
24+ import json
2425
2526WIDTH = const (72 )
2627HEIGHT = const (40 )
9394 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,2 ,6 ,15 ,30 ,24 ,32 ,96 ,96 ,224 ,192 ,128 ,128 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,128 ,128 ,192 ,128 ,128 ,192 ,224 ,208 ,240 ,224 ,224 ,224 ,112 ,112 ,56 ,46 ,14 ,15 ,7 ,3 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
9495 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 ,3 ,3 ,3 ,6 ,4 ,4 ,4 ,6 ,6 ,6 ,6 ,6 ,7 ,7 ,7 ,3 ,1 ,1 ,3 ,2 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ])
9596
97+ #DEFAULT_KEYS = array('A', #FIRE
98+ # 'B', #SHIFT
99+ # 'L', #MOVE_LEFT
100+ # 'R', #MOVE_RIGHT
101+ # 'D', #MOVE_UP
102+ # 'U', #MOVE_DOWN
103+ # 'U', #AFTERBURNER
104+ # 'D', #BREAK
105+ # 'R', #TARGET_NEXT
106+ # 'L') #TARGET_PREV
107+
108+ DEFAULT_KEYS = {
109+ "FIRE" : "A" ,
110+ "SHIFT" : "B" ,
111+ "MOVE_LEFT" : "L" ,
112+ "MOVE_RIGHT" : "R" ,
113+ "MOVE_UP" : "D" ,
114+ "MOVE_DOWN" : "U" ,
115+ "AFTERBURNER" : "U" ,
116+ "BREAK" : "D" ,
117+ "TARGET_NEXT" : "R" ,
118+ "TARGET_PREV" : "L"
119+ }
120+
96121def copySprite (obj :Sprite ):
97122 newSprite = Sprite (obj .width , obj .height ,(bytearray (obj .bitmapByteCount ), bytearray (obj .bitmapByteCount )),0 ,0 ,obj .key ,obj .mirrorX ,obj .mirrorY )
98123 newSprite .setFrame (obj .currentFrame )
@@ -215,20 +240,6 @@ def qsort(inlist):
215240
216241@micropython .native
217242def apply_physics (damping : int , desired_vel : int , initial_vel : int , t : int ) -> int :
218- """
219- Apply physics calculations independent of frame rate.
220-
221- Args:
222- damping: Damping factor. Zero means instant velocity change
223- desired_vel: Target velocity
224- initial_vel: Starting velocity
225- t: Elapsed time since last call
226-
227- Returns:
228- tuple containing:
229- - new_vel: Current velocity
230- """
231-
232243 if damping < MIN_DAMPING :
233244 return desired_vel , (desired_vel * t ) >> 16
234245 else :
@@ -248,7 +259,39 @@ def apply_physics(damping: int, desired_vel: int, initial_vel: int, t: int) -> i
248259def getSprite (z , shape ):
249260 OBJECTS [shape ].setScale (fpdiv ((71 << 16 )- abs (z ), 60 << 16 ))
250261 return OBJECTS [shape ]
251-
262+
263+ def button_exists (button_name ):
264+ try :
265+ for part in button_name :
266+ if not "button" + part in globals ():
267+ return False
268+ return True
269+ except :
270+ return False
271+
272+ def load_keymaps ():
273+ try :
274+ with open (loc + "keymap.json" , "r" ) as f :
275+ loaded_keys = json .loads (f .read ())
276+ complete_keys = DEFAULT_KEYS .copy ()
277+ for key , value in loaded_keys .items ():
278+ if button_exists (value ):
279+ complete_keys [key ] = value
280+ return complete_keys
281+ except :
282+ return DEFAULT_KEYS .copy ()
283+
284+ def save_keymaps (keymap ):
285+ try :
286+ with open (loc + "keymap.json" , "w" ) as f :
287+ f .write (json .dumps (keymap ))
288+ except :
289+ pass
290+
291+
292+ # Global variable to store key mappings
293+ KEYMAPS = load_keymaps ()
294+
252295class Stars :
253296 def __init__ (self , num :int , scale_pos :int = 4 , stable = 80 ):
254297 stars = array ('O' , [None ] * num )
@@ -674,8 +717,8 @@ def move_me(self, enemies):
674717 if (ta > 250000 ):
675718 self .afterburner_time = 0
676719 player_target_speed = 1 << 16
677- if buttonB . pressed ():
678- if buttonR . justPressed ():
720+ if getattr ( globals ()[ "button" + KEYMAPS [ "SHIFT" ]], " pressed" ) ():
721+ if getattr ( globals ()[ "button" + KEYMAPS [ "TARGET_NEXT" ]], " justPressed" ) ():
679722 if enemies :
680723 for i in range (len (enemies )):
681724 e = enemies [i ]
@@ -686,7 +729,7 @@ def move_me(self, enemies):
686729 break
687730 else :
688731 if enemies [0 ] != None : enemies [0 ][8 ] = 1
689- elif buttonL . justPressed ():
732+ elif getattr ( globals ()[ "button" + KEYMAPS [ "TARGET_PREV" ]], " justPressed" ) ():
690733 if enemies :
691734 for i in range (len (enemies ) - 1 , - 1 , - 1 ):
692735 e = enemies [i ]
@@ -697,60 +740,31 @@ def move_me(self, enemies):
697740 break
698741 else :
699742 if enemies [0 ] != None : enemies [len (enemies ) - 1 ][8 ] = 1
700- elif buttonU . justPressed () and (self .afterburner_time == 0 ):
701- player_target_speed = 7 << 16 ;
743+ elif getattr ( globals ()[ "button" + KEYMAPS [ "AFTERBURNER" ]], " justPressed" ) () and (self .afterburner_time == 0 ):
744+ player_target_speed = 5 << 16 ;
702745 self .afterburner_time = new_time
703- elif buttonD . justPressed ():
746+ elif getattr ( globals ()[ "button" + KEYMAPS [ "BREAK" ]], " justPressed" ) ():
704747 player_speed = 1 << 16
705- elif buttonR . pressed ():
748+ elif getattr ( globals ()[ "button" + KEYMAPS [ "MOVE_RIGHT" ]], " pressed" ) ():
706749 player_angle [0 ] -= 1 << 16
707750 player_angle [2 ] = - 3
708751 self .cockpit_sprite .x = SHIP_X - 1
709- elif buttonL . pressed ():
752+ elif getattr ( globals ()[ "button" + KEYMAPS [ "MOVE_LEFT" ]], " pressed" ) ():
710753 player_angle [0 ] += 1 << 16
711754 player_angle [2 ] = 3
712755 self .cockpit_sprite .x = SHIP_X + 1
713- elif buttonU . pressed ():
756+ elif getattr ( globals ()[ "button" + KEYMAPS [ "MOVE_DOWN" ]], " pressed" ) ():
714757 player_angle [1 ] -= 1 << 16
715758 self .cockpit_sprite .y = SHIP_Y - 1
716- elif buttonD . pressed ():
759+ elif getattr ( globals ()[ "button" + KEYMAPS [ "MOVE_UP" ]], " pressed" ) ():
717760 player_angle [1 ] += 1 << 16
718761 self .cockpit_sprite .y = SHIP_Y + 1
719- elif buttonA . justPressed ():
762+ elif getattr ( globals ()[ "button" + KEYMAPS [ "FIRE" ]], " justPressed" ) ():
720763 if (self .laser_energy > 0 ):
721764 self .laser .append (Laser (player_angle [0 ], player_angle [1 ]))
722765 self .target_sprite = Sprite (7 ,7 ,(targetactive ,targetactiveSHD ),CENTER_X - 3 , CENTER_Y - 3 ,0 )
723766 self .fire_couter += 20
724767 self .laser_energy -= 1
725- #elif buttonB.justPressed():
726- # if enemies:
727- # for i in range(len(enemies)):
728- # e = enemies[i]
729- # if e[8] == 1:
730- # e[8] = 0
731- # if (i+1) < len(enemies): enemies[i+1][8] = 1
732- # else: hudShip = None
733- # break
734- # else:
735- # if enemies[0] != None: enemies[0][8] = 1
736-
737-
738- #else:
739- # delta_x = sign(player_angle[0])
740- # player_angle[0] -= delta_x<<16
741- # self.cockpit_sprite.x = SHIP_X-delta_x
742- # delta_y = sign(player_angle[1])
743- # player_angle[1] -= delta_y<<16
744- # self.cockpit_sprite.y = SHIP_Y-delta_y
745- # if delta_x > 0:
746- # player_angle[2] = -3
747- # elif delta_x < 0:
748- # player_angle[2] = +3
749- # else:
750- # player_angle[2] = 0
751- # self.cockpit_sprite.x = SHIP_X
752- # if (player_angle[1] == 0):
753- # self.cockpit_sprite.y = SHIP_Y
754768 else :
755769 player_angle [2 ] = 0
756770 self .cockpit_sprite .x = SHIP_X
@@ -770,6 +784,7 @@ def move_me(self, enemies):
770784 if player_angle [1 ] > 2162688 : player_angle [1 ] = 2162688
771785
772786 player_speed = apply_physics (1 << 16 , player_target_speed , player_speed , t )
787+ inputJustPressed ()
773788
774789
775790class Laser :
@@ -874,27 +889,164 @@ def menu():
874889 display .drawText ("Dog Fight" ,21 ,30 ,3 )
875890 elif i == 1 :
876891 display .drawText ("Dog Fight" ,21 ,20 ,1 )
877- display .drawText ("Exit Game " ,21 ,30 ,3 )
892+ display .drawText ("Settings " ,21 ,30 ,3 )
878893 elif i == 2 :
879- display .drawText ("Dog Fight" ,21 ,20 ,3 )
894+ display .drawText ("Settings" ,21 ,20 ,1 )
895+ display .drawText ("Exit Game" ,21 ,30 ,3 )
896+ elif i == 3 :
897+ display .drawText ("Settings" ,21 ,20 ,3 )
880898 display .drawText ("Exit Game" ,21 ,30 ,1 )
881899 display .update ()
882900 if buttonD .justPressed ():
883901 i += 1
884- if i > 2 : i = 2
902+ if i > 3 : i = 3
885903 rot = - 5
886904 elif buttonU .justPressed ():
887905 i += - 1
888906 if i < 0 : i = 0
889907 rot = 5
890908 return i
909+
910+ class SettingsMenu :
911+ def __init__ (self ):
912+ self .update_menu ()
913+ self .selected = 0
914+ self .remapping = False
915+ self .current_remap = ""
916+ self .background = Stars (20 , 4 , 0 )
917+ display .setFont ("/lib/font3x5.bin" , 3 , 5 , 1 )
918+ # wait for button release
919+ inputJustPressed ()
891920
921+ def update_menu (self ):
922+ self .settings_items = [
923+ "FIRE: " + KEYMAPS ["FIRE" ],
924+ "SHIFT: " + KEYMAPS ["SHIFT" ],
925+ "MOVE LEFT: " + KEYMAPS ["MOVE_LEFT" ],
926+ "MOVE RIGHT: " + KEYMAPS ["MOVE_RIGHT" ],
927+ "MOVE UP: " + KEYMAPS ["MOVE_UP" ],
928+ "MOVE DOWN: " + KEYMAPS ["MOVE_DOWN" ],
929+ "AFTERBURNER: " + KEYMAPS ["SHIFT" ]+ "+" + KEYMAPS ["AFTERBURNER" ],
930+ "BREAK: " + KEYMAPS ["SHIFT" ]+ "+" + KEYMAPS ["BREAK" ],
931+ "TGT NEXT: " + KEYMAPS ["SHIFT" ]+ "+" + KEYMAPS ["TARGET_NEXT" ],
932+ "TGT PREV: " + KEYMAPS ["SHIFT" ]+ "+" + KEYMAPS ["TARGET_PREV" ],
933+ "RESET DEFAULTS" ,
934+ "BACK"
935+ ]
936+ def run (self ):
937+ global KEYMAPS
938+ display .setFPS (30 )
939+
940+ while True :
941+ display .fill (0 )
942+ self .background .run (0 )
943+
944+ # Draw title
945+ display .drawText ("SETTINGS" , 22 , 2 , 1 )
946+ display .drawLine (0 , 9 , 72 , 9 , 1 )
947+
948+ # If in remapping mode
949+ if self .remapping :
950+ display .fill (0 )
951+ # Draw title
952+ display .drawText ("PRESS NEW KEY FOR:" , 2 , 2 , 1 )
953+ display .drawLine (0 , 9 , 72 , 9 , 1 )
954+ display .drawText (self .current_remap , 16 , 14 , 3 )
955+ display .update ()
956+
957+ # Wait for a button press
958+ while not (buttonA .pressed () or buttonB .pressed () or dpadPressed ()):
959+ pass
960+
961+ # Determine which button was pressed
962+ new_key = ""
963+ if buttonA .pressed (): new_key = "A"
964+ elif buttonB .pressed (): new_key = "B"
965+ elif buttonU .pressed (): new_key = "U"
966+ elif buttonD .pressed (): new_key = "D"
967+ elif buttonL .pressed (): new_key = "L"
968+ elif buttonR .pressed (): new_key = "R"
969+
970+ # Update mapping if valid
971+ if new_key != "" :
972+ KEYMAPS [self .current_remap ] = new_key
973+ self .update_menu ()
974+
975+ # Wait for button release
976+ sleep (0.3 )
977+ inputJustPressed ()
978+
979+ self .remapping = False
980+ sleep (0.3 )
981+ continue
982+
983+ # Draw menu items
984+ start_idx = max (0 , min (self .selected - 2 , len (self .settings_items ) - 5 ))
985+ for i in range (start_idx , min (start_idx + 5 , len (self .settings_items ))):
986+ y_pos = 12 + (i - start_idx ) * 6
987+ text_color = 1 if i == self .selected else 3
988+ display .drawText (self .settings_items [i ], 4 , y_pos , text_color )
989+
990+ # Draw scrollbar if needed
991+ if len (self .settings_items ) > 5 :
992+ scrollbar_height = min (35 , 35 * 5 / len (self .settings_items ))
993+ scrollbar_pos = 12 + (35 - scrollbar_height ) * self .selected / (len (self .settings_items ) - 1 )
994+ display .drawFilledRectangle (70 , int (scrollbar_pos ), 2 , int (scrollbar_height ), 1 )
995+
996+ display .update ()
997+
998+ # Handle input
999+ if buttonU .justPressed ():
1000+ self .selected = (self .selected - 1 ) % len (self .settings_items )
1001+ sleep (0.15 )
1002+ elif buttonD .justPressed ():
1003+ self .selected = (self .selected + 1 ) % len (self .settings_items )
1004+ sleep (0.15 )
1005+ elif buttonA .justPressed ():
1006+ # Handle selection
1007+ if self .selected < 10 : # Key remapping options
1008+ self .remapping = True
1009+ if self .selected == 0 :
1010+ self .current_remap = "FIRE"
1011+ elif self .selected == 1 :
1012+ self .current_remap = "SHIFT"
1013+ elif self .selected == 2 :
1014+ self .current_remap = "MOVE_LEFT"
1015+ elif self .selected == 3 :
1016+ self .current_remap = "MOVE_RIGHT"
1017+ elif self .selected == 4 :
1018+ self .current_remap = "MOVE_UP"
1019+ elif self .selected == 5 :
1020+ self .current_remap = "MOVE_DOWN"
1021+ elif self .selected == 6 :
1022+ self .current_remap = "AFTERBURNER"
1023+ elif self .selected == 7 :
1024+ self .current_remap = "BREAK"
1025+ elif self .selected == 8 :
1026+ self .current_remap = "TARGET_NEXT"
1027+ elif self .selected == 9 :
1028+ self .current_remap = "TARGET_PREV"
1029+ elif self .selected == 10 : # Reset defaults
1030+ for key in DEFAULT_KEYS :
1031+ KEYMAPS [key ] = DEFAULT_KEYS [key ]
1032+ # Update menu text
1033+ self .update_menu ()
1034+ sleep (0.3 )
1035+ elif self .selected == 11 : # Back
1036+ save_keymaps (KEYMAPS )
1037+ return
1038+ sleep (0.15 )
1039+ elif buttonB .justPressed ():
1040+ # Go back
1041+ save_keymaps (KEYMAPS )
1042+ return
1043+
8921044#Intro finished
8931045Intro .finish ()
8941046
8951047while True :
8961048 lifes = 5
897- player_speed = float2fp (1 )
1049+ player_speed = player_target_speed = float2fp (1 )
8981050 player_angle = [0 , 0 , 0 ]
8991051 score = 0
9001052 # Show the Menu
@@ -933,5 +1085,8 @@ def menu():
9331085 display .update ()
9341086 die ()
9351087 game_over ()
1088+ elif (game == 2 ):
1089+ settings = SettingsMenu ()
1090+ settings .run ()
9361091 else :
9371092 reset ()
0 commit comments