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.
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. Da 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 dieser 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
speicherextensiven Anwendung ist das keine Kleinigkeit. Mit dem Ausdruck 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.
Viel Spass und Erfolg beim Ausprobieren.