Bewegte Bilder auf PicoBoy Color
technische Daten wie beim RPi Pico
Microcontroller RP2040 - 1,69 Zoll Farbdisplay mit 240 x 280 Pixeln
Projekte und Anleitung in CircuitPython 9.x.x
Jetzt wird das Ganze spielbar. Die Geschichte lautet: PicoMax erhält für das Einsammeln von Geldkisten, Pilzen oder
Fragezeichen Punkte. Aber Vorsicht! Manchmal begegnet er auch der Hinterlassenschaft eines Hundes oder wird sogar von ihm
gebissen. Dann werden ihm Punkte abgezogen oder er verliert ein Leben.
Zunächst gibt es die positiven Sachen: Geldkisten, Pilze und Fragezeichen mit einer Gutschrift von jeweils 15 Punkten. Die erscheinen
im oberen und unteren Bereich immer an unterschiedlichen Stellen und müssen durch einen Sprung nach oben berührt werden. Wenn
PicoMax von links nach rechts läuft, erreicht er die Brücke und fällt in den 'Keller'. Dort ändert sich die Laufrichtung
von rechts nach links. Am Ende öffnet sich die 'Fahrstuhltür' und PicoMax gelangt wieder nach oben. Durch einen Druck auf den
Joystickbutton kann PicoMax jederzeit angehalten werden.
Der Quellcode dafür ist im unteren Kasten enthalten. Kopieren Sie ihn zunächst ins Thonny und testen ihn. Anschließend werde
ich einige Erläuterungen geben. Wenn Ihnen das Ganze aber noch etwas zu komplex ist, oder Sie noch nicht so weit sind, müssen Sie nicht
verzagen. Es ist Weihnachten und da gibt es auch kleine Geschenke. Ihres haben Sie schon mit dem Weihnachtsgadget heruntergeladen. Alles was hier
beschrieben ist, befindet sich schon auf Ihrem PicoBoy-Color. Wenn Sie die Datei 'code.py' z.B. vom Dateiexplorer aus in 'xmas_start.py' umbenennen
und dafür die Datei 'picomax_start.py' in 'code.py', dann startet das Spiel beim Einschalten des PicoBoy-Color. Das sollte Sie aber nicht davon
abhalten, die Anleitung trotzdem bis zum Ende zu verfolgen.
Bewegte Bilder auf PicoBoy Color
technische Daten wie beim RPi Pico
Microcontroller RP2040 - 1,69 Zoll Farbdisplay mit 240 x 280 Pixeln
Projekte und Anleitung in CircuitPython 9.x.x
1 # SPDX-FileCopyrightText : 2024 Detlef Gebhardt, written for CircuitPython 9.2.0 2 # SPDX-FileCopyrightText : Copyright (c) 2024 Detlef Gebhardt 3 # SPDX-Filename : PicoMax's Abenteuer - Spiel auf PicoBoy-Color 4 # SPDX-License-Identifier: https://dgebhardt.de 5 import time 6 import gc 7 import board 8 import busio 9 import displayio 10 import terminalio 11 import digitalio 12 from adafruit_display_text import label 13 from adafruit_st7789 import ST7789 14 import keypad 15 import adafruit_imageload 16 import random 17 import microcontroller 18 19 # 1,69 Zoll 240x280 Pixel ST7789 Display 20 # SPI, in Landscape format 21 dc=board.GP8 22 reset=board.GP9 23 cs=board.GP10 24 sck=board.GP18 25 mosi=board.GP19 26 bl=board.GP26 27 # Release any resources currently in use for the displays 28 displayio.release_displays() 29 spi = busio.SPI(sck, mosi) 30 display_bus = displayio.FourWire(spi, command=dc, chip_select=cs, reset=reset) 31 display = ST7789(display_bus, rotation=90, width=280, height=240, backlight_pin=bl, rowstart=20, colstart=0) 32 display.brightness = 1 33 main = displayio.Group() 34 35 K_UP = 0x01 # GP3 dez. 1 36 K_LEFT = 0x02 # GP2 dez. 2 37 K_RIGHT = 0x04 # GP4 dez. 4 38 K_DOWN = 0x08 # GP1 dez. 8 39 K_A = 0x10 # GP27 dez. 16 40 K_B = 0x20 # GP28 dez. 32 41 K_C = 0x40 # GP0 dez. 64 42 43 class _Buttons: 44 def __init__(self): 45 self.keys = keypad.Keys((board.GP1, board.GP4, board.GP2, board.GP3, board.GP28, board.GP27, board.GP0), 46 value_when_pressed=False, interval=0.05) 47 self.last_state = 0 48 self.event = keypad.Event(0, False) 49 self.last_z_press = None 50 51 def get_pressed(self): 52 buttons = self.last_state 53 events = self.keys.events 54 while events: 55 if events.get_into(self.event): 56 bit = 1 << self.event.key_number 57 if self.event.pressed: 58 buttons |= bit 59 self.last_state |= bit 60 else: 61 self.last_state &= ~bit 62 return buttons 63 buttons = _Buttons() 64 65 # Load the backgr sprite sheet (bitmap) 66 sprite_sheet, palette = adafruit_imageload.load("/images/floor.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) 67 backgr_group = displayio.TileGrid(sprite_sheet, pixel_shader=palette, width=7, height=6, tile_width=40, tile_height=40, default_tile=7) 68 69 # Load the sprite sheet for PicoMax (bitmap) 70 sprite_sheet, palette = adafruit_imageload.load("/images/picomax.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) 71 palette.make_transparent(1) 72 good1 = displayio.TileGrid(sprite_sheet, pixel_shader=palette, width=1, height=1, tile_width=32, tile_height=32, default_tile=0) 73 good1_group = displayio.Group(scale=1) 74 good1_group.append(good1) 75 good2 = displayio.TileGrid(sprite_sheet, pixel_shader=palette, width=1, height=1, tile_width=32, tile_height=32, default_tile=0) 76 good2_group = displayio.Group(scale=1) 77 good2_group.append(good2) 78 79 picomax = displayio.TileGrid(sprite_sheet, pixel_shader=palette, width=1, height=1, tile_width=32, tile_height=32, default_tile=0) 80 picomax_group = displayio.Group(scale=1) 81 picomax_group.append(picomax) 82 ## Draw the label for the score 83 updating_score = label.Label(font=terminalio.FONT, text = " Los geht's",scale=2, color=0x0000ff, line_spacing=1) 84 updating_score.anchor_point = (0, 0) 85 updating_score.anchored_position = (40, 5) 86 87 backgr = [15, 16, 13, 13, 13, 13, 13, 88 18, 19, 20, 14, 20, 14, 20, 89 7, 7, 7, 7, 7, 7, 7, 90 7, 0, 5, 5, 5, 8, 6, 91 7, 0, 7, 7, 7, 7, 2, 92 12, 0, 11, 11, 8, 10, 11] 93 94 def floor(): 95 # show the 42 sprites 96 for x in range(0, 7): 97 for y in range(0, 6): 98 backgr_group[x, y] = backgr[y*7 +x] 99 100 def testing_things(points): 101 if abs(picomax.x - good1.x) < 5 and abs(picomax.y - good1.y) < 15 and not good1[0] == 0: 102 good1[0] = 0 103 points[0] += 15 104 updating_score.text = ("Punkte:" + str(points[0]) + " Leben:" + str(points[1])) 105 if abs(picomax.x - good2.x) < 5 and abs(picomax.y - good2.y) < 15 and not good2[0] == 0: 106 good2[0] = 0 107 points[0] += 15 108 updating_score.text = ("Punkte:" + str(points[0]) + " Leben:" + str(points[1])) 109 110 111 def set_sprites(): 112 backgr_group[5, 4] = 7 113 good1.x = random.randint(90,220) 114 good1.y = random.randint(45,70) 115 good1[0] = random.randint(12,15) 116 good2.x = random.randint(90,200) 117 good2.y = random.randint(125,140) 118 good2[0] = random.randint(12,15) 119 120 121 main.append(backgr_group) 122 main.append(good1_group) 123 main.append(good2_group) 124 125 main.append(picomax_group) 126 main.append(updating_score) 127 display.root_group = main 128 floor() 129 set_sprites() 130 picomax.x = 90 131 picomax.y = 90 132 picomax[0] = 3 133 points = [0, 5] 134 right = False 135 left = False 136 up = True 137 down = True 138 before = picomax.y 139 debounce = False 140 i = 0 141 step = time.monotonic() 142 jump = time.monotonic() 143 144 while True: 145 cur_btn_vals = buttons.get_pressed() 146 testing_things(points) 147 148 #### 149 # picomax bleibt stehen 150 #### 151 if cur_btn_vals == 0x40 and not debounce: 152 if right == True: 153 picomax[0] = 3 154 if left == True: 155 picomax[0] = 7 156 right = False 157 left = False 158 #### 159 # picomax läuft nach rechts 160 #### 161 if cur_btn_vals == 0x04: 162 right = True 163 left = False 164 m = 1 165 #### 166 # picomax läuft nach links 167 #### 168 if cur_btn_vals == 0x02: 169 right = False 170 left = True 171 m = 5 172 #### 173 # picomax springt nach oben 174 #### 175 if cur_btn_vals == 0x01: 176 if not debounce: 177 debounce = True 178 before = picomax.y 179 picomax.y -= 33 180 jump = time.monotonic() 181 182 if (time.monotonic() - jump > 0.3): 183 picomax.y = before 184 ### wenn picomax nach rechts laeuft 185 if right == True: 186 if time.monotonic() - step > 0.05: 187 picomax[0] = m 188 m += 1 189 picomax.x += 4 190 if m == 4: 191 m = 1 192 193 step = time.monotonic() 194 195 ### wenn picomax nach links laeuft 196 if left == True: 197 if time.monotonic() - step > 0.05: 198 picomax[0] = m 199 m += 1 200 picomax.x -= 4 201 if m == 8: 202 m = 5 203 204 step = time.monotonic() 205 206 ##### pruefen ob picomax rechts oder links angekommen ist 207 # 208 # von der Bruecke in den Keller 209 if picomax.x >= 240: 210 backgr_group[6, 3] = 7 211 backgr_group[1, 2] = 7 212 picomax.y = 130 213 before = picomax.y 214 right = False 215 left = True 216 m = 5 217 # zweite Stufe im Keller 218 if picomax.x < 215 and picomax.x > 210 and left: 219 backgr_group[6, 3] = 6 220 backgr_group[1, 4] = 3 221 picomax.y = 170 222 before = picomax.y 223 224 # links mit dem Fahrstuhl nach oben 225 if picomax.x <= 45: 226 picomax[0] = 0 227 backgr_group[1, 2] = 3 228 backgr_group[1, 4] = 0 229 time.sleep(0.2) 230 picomax.y = 90 231 before = picomax.y 232 picomax[0] = 1 233 set_sprites() 234 right = True 235 left = False 236 i = 0 237 m = 1 238 # wenn keine Taste gedrückt ist- debounce zurücksetzen 239 if cur_btn_vals == 0: 240 debounce = False 241 gc.collect() 242 #print(gc.mem_free())
Import der Bibliotheken
Neben den schon vorhandenen Bibliotheken werden die für den Text, die Tastenabfrage und Zufallszahlen importiert. Zusätzlich
'microcontroller' - wird später zum Neustart bei Spielende gebraucht.
Display initialisieren
Zeilen 19 bis 33 wie gehabt.
Tasten des PicoBoy-Color
Dazu wird die 'Keypad'-Bibliothek genutzt. So kann abgefragt werden, ob eine Taste gedrückt wurde und wenn ja, welche. In den Zeilen
35 bis 62 wird deshalb eine Klasse 'Buttons' definiert und in Zeile 63 an das Programm übergeben. Außerdem wird eine Variable
'debounce' (Zeile 139) definiert, mit der die Tasteneingaben entprellt werden. Solange 'debounce = True', wird keine weitere Eingabe
erfasst. Am Programmende (Zeilen 238 bis 240) wird 'debounce' zurückgesetzt. Man spart sich so die Unterbrechungen des Programmablaufs
wie z.B. 'time.sleep()' u.ä.
weitere Sprites laden
Bisher haben wir die Sprites für den Hintergrund, die Figuren und 'PicoMax' geladen. Jetzt kommen die Sprites 'good1' und 'good2', welche
die Geldkiste, den Pilz oder das Fragezeichen darstellen, sowie das Label zur Anzeige des Punktestandes dazu. Das umfasst die Zeilen 65 bis 85.
Liste für das Hintergrundbild
In den Zeilen 87 bis 92 wird die Liste mit den Nummern der Hintergrundsprites definiert. In den Zeilen 94 bis 98 wird der Hintergrund in der Funktion 'floor()'
dargestellt.
Funktionen 'testing_things() und 'set_sprites()'
In jeder Runde von PicoMax werden mit Hilfe der Funktion 'set_sprites()' die good's gesetzt (und später auch poop und dog). In der Funktion
'testing_things()' wird festgestellt, ob PicoMax den good's (und später auch poop und dog) nahe genug gekommen ist, um Punkte zu bekommen bzw.
abgezogen zu bekommen.
Variable und Programmvorbereitung
Die Zeilen 121 bis 142 stellen noch benötigte Variable bereit bzw. bereiten den Progammstart vor. Die Funktionen 'floor()' und set_sprites()
werden aufgerufen, PicoMax plaziert, eine Punkteliste 'points' mit 0 Punkten und 5 Leben
sowie Laufrichtungen festgelegt. Mit Hilfe der Variable 'step' und 'jump' werden die Laufgeschwindigkeit bzw. Sprungdauer bestimmt.
Hauptprogramm in der 'while'-Schleife
Ab Zeile 144 beginnt die Endlosschleife. Dort wird bei jedem Durchlauf geprüft, ob eine Taste gedrückt wurde und eine 'Kollision' stattfand.
Alle anderen Aktionen sind durch entsprechende Kommentare ausführlich beschrieben.
Eine letzte Bemerkung zu Zeile 241 u.242
Der Befehl 'gc.collect()' sammelt bei jedem Schleifendurchlauf den nicht mehr benötigten Arbeitsspeicher und gibt ihn frei. Bei einer solchen, für
den PicoBoy speicherextensiven Anwendung, ist das keine Kleinigkeit. Mit dem Ausdrucken des noch vorhandenen Arbeitsspeichers in Zeile 142 kann man in der
Entwicklungsphase kontrollieren, wie viel Speicher noch verfügbar ist. Danach richtet sich z.B., ob noch weitere Spites installiert werden
können.
Mit der nächsten Box erhalten Sie den kompletten Quellcode. Darin sind jetzt noch die Charaktere 'Hundekode' und 'Hund' enthalten.
Wenn PicoMax es nicht schafft über 'poop' zu springen, werden 10 Punkte abgezogen, während er bei Kollision mit 'dog' jeweils ein Leben
verliert.
Achtung: Nachdem 'dog' übersprungen wurde erscheint er im 'Fahrstuhl'. Nach dem Zufallsprinzip lässt er sich manchmal verjagen, so dass
PicoMax den Fahrstuhl nach oben nehmen kann. Ansonsten muss er sehr schnell umkehren, denn 'dog' verfolgt ihn kurz und PicoMax muss die bereitstehende
Leiter auf der rechten Seite nach oben nehmen.
# SPDX-FileCopyrightText : 2024 Detlef Gebhardt, written for CircuitPython 9.2.0 # SPDX-FileCopyrightText : Copyright (c) 2024 Detlef Gebhardt # SPDX-Filename : PicoMax's Abenteuer - Spiel auf PicoBoy-Color # SPDX-License-Identifier: https://dgebhardt.de Klicken Sie auf 'Code kopieren' und fügen ihn ins Thonny ein. Speichen Sie unter dem Namen 'code.py' und starten das Spiel. PS: Die Bibliotheken und Bilddateien aus den vorhergehenden Seiten werden als vorhanden vorausgesetzt.
Erweitern Sie die Anwendung gerne und nutzen, was der Arbeitsspeicher noch hergibt.
Viel Spass und Erfolg beim Ausprobieren.
Ein erholsames Weihnachtsfest
and don't bite the dog or step into dog poop.
Viel Spass und Erfolg beim Ausprobieren.
Ein erholsames Weihnachtsfest
and don't bite the dog or step into dog poop.