Skip to content

Commit 8d0ef9d

Browse files
authored
Merge branch 'main' into patch-2
2 parents b490831 + c9b7193 commit 8d0ef9d

File tree

15 files changed

+1745
-3
lines changed

15 files changed

+1745
-3
lines changed
+251
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries
2+
# SPDX-License-Identifier: MIT
3+
"""
4+
This example demonstrates basic autosave and resume functionality. There are two buttons
5+
that can be clicked to increment respective counters. The number of clicks is stored
6+
in a game_state dictionary and saved to a data file on the SDCard. When the code first
7+
launches it will read the data file and load the game_state from it.
8+
"""
9+
import array
10+
from io import BytesIO
11+
import os
12+
13+
import board
14+
import busio
15+
import digitalio
16+
import displayio
17+
import msgpack
18+
import storage
19+
import supervisor
20+
import terminalio
21+
import usb
22+
23+
import adafruit_sdcard
24+
from adafruit_display_text.bitmap_label import Label
25+
from adafruit_button import Button
26+
27+
# use the default built-in display
28+
display = supervisor.runtime.display
29+
30+
# button configuration
31+
BUTTON_WIDTH = 100
32+
BUTTON_HEIGHT = 30
33+
BUTTON_STYLE = Button.ROUNDRECT
34+
35+
# game state object will get loaded from SDCard
36+
# or a new one initialized as a dictionary
37+
game_state = None
38+
39+
save_to = None
40+
41+
# boolean variables for possible SDCard states
42+
sd_pins_in_use = False
43+
44+
# The SD_CS pin is the chip select line.
45+
SD_CS = board.SD_CS
46+
47+
# try to Connect to the sdcard card and mount the filesystem.
48+
try:
49+
# initialze CS pin
50+
cs = digitalio.DigitalInOut(SD_CS)
51+
except ValueError:
52+
# likely the SDCard was auto-initialized by the core
53+
sd_pins_in_use = True
54+
55+
try:
56+
# if sd CS pin was not in use
57+
if not sd_pins_in_use:
58+
# try to initialize and mount the SDCard
59+
sdcard = adafruit_sdcard.SDCard(
60+
busio.SPI(board.SD_SCK, board.SD_MOSI, board.SD_MISO), cs
61+
)
62+
vfs = storage.VfsFat(sdcard)
63+
storage.mount(vfs, "/sd")
64+
65+
# check for the autosave data file
66+
if "autosave_demo.dat" in os.listdir("/sd/"):
67+
# if the file is found read data from it into a BytesIO buffer
68+
buffer = BytesIO()
69+
with open("/sd/autosave_demo.dat", "rb") as f:
70+
buffer.write(f.read())
71+
buffer.seek(0)
72+
73+
# unpack the game_state object from the read data in the buffer
74+
game_state = msgpack.unpack(buffer)
75+
print(game_state)
76+
77+
# if placeholder.txt file does not exist
78+
if "placeholder.txt" not in os.listdir("/sd/"):
79+
# if we made it to here then /sd/ exists and has a card
80+
# so use it for save data
81+
save_to = "/sd/autosave_demo.dat"
82+
except OSError as e:
83+
# sdcard init or mounting failed
84+
raise OSError(
85+
"This demo requires an SDCard. Please power off the device " +
86+
"insert an SDCard and then plug it back in."
87+
) from e
88+
89+
# if no saved game_state was loaded
90+
if game_state is None:
91+
# create a new game state dictionary
92+
game_state = {"pink_count": 0, "blue_count": 0}
93+
94+
# Make the display context
95+
main_group = displayio.Group()
96+
display.root_group = main_group
97+
98+
# make buttons
99+
blue_button = Button(
100+
x=30,
101+
y=40,
102+
width=BUTTON_WIDTH,
103+
height=BUTTON_HEIGHT,
104+
style=BUTTON_STYLE,
105+
fill_color=0x0000FF,
106+
outline_color=0xFFFFFF,
107+
label="BLUE",
108+
label_font=terminalio.FONT,
109+
label_color=0xFFFFFF,
110+
)
111+
112+
pink_button = Button(
113+
x=30,
114+
y=80,
115+
width=BUTTON_WIDTH,
116+
height=BUTTON_HEIGHT,
117+
style=BUTTON_STYLE,
118+
fill_color=0xFF00FF,
119+
outline_color=0xFFFFFF,
120+
label="PINK",
121+
label_font=terminalio.FONT,
122+
label_color=0x000000,
123+
)
124+
125+
# add them to a list for easy iteration
126+
all_buttons = [blue_button, pink_button]
127+
128+
# Add buttons to the display context
129+
main_group.append(blue_button)
130+
main_group.append(pink_button)
131+
132+
# make labels for each button
133+
blue_lbl = Label(
134+
terminalio.FONT, text=f"Blue: {game_state['blue_count']}", color=0x3F3FFF
135+
)
136+
blue_lbl.anchor_point = (0, 0)
137+
blue_lbl.anchored_position = (4, 4)
138+
pink_lbl = Label(
139+
terminalio.FONT, text=f"Pink: {game_state['pink_count']}", color=0xFF00FF
140+
)
141+
pink_lbl.anchor_point = (0, 0)
142+
pink_lbl.anchored_position = (4, 4 + 14)
143+
main_group.append(blue_lbl)
144+
main_group.append(pink_lbl)
145+
146+
# load the mouse cursor bitmap
147+
mouse_bmp = displayio.OnDiskBitmap("mouse_cursor.bmp")
148+
149+
# make the background pink pixels transparent
150+
mouse_bmp.pixel_shader.make_transparent(0)
151+
152+
# create a TileGrid for the mouse, using its bitmap and pixel_shader
153+
mouse_tg = displayio.TileGrid(mouse_bmp, pixel_shader=mouse_bmp.pixel_shader)
154+
155+
# move it to the center of the display
156+
mouse_tg.x = display.width // 2
157+
mouse_tg.y = display.height // 2
158+
159+
# add the mouse tilegrid to main_group
160+
main_group.append(mouse_tg)
161+
162+
# scan for connected USB device and loop over any found
163+
for device in usb.core.find(find_all=True):
164+
# print device info
165+
print(f"{device.idVendor:04x}:{device.idProduct:04x}")
166+
print(device.manufacturer, device.product)
167+
print(device.serial_number)
168+
# assume the device is the mouse
169+
mouse = device
170+
171+
# detach the kernel driver if needed
172+
if mouse.is_kernel_driver_active(0):
173+
mouse.detach_kernel_driver(0)
174+
175+
# set configuration on the mouse so we can use it
176+
mouse.set_configuration()
177+
178+
# buffer to hold mouse data
179+
# Boot mice have 4 byte reports
180+
buf = array.array("b", [0] * 4)
181+
182+
183+
def save_game_state():
184+
"""
185+
msgpack the game_state and save it to the autosave data file
186+
:return:
187+
"""
188+
b = BytesIO()
189+
msgpack.pack(game_state, b)
190+
b.seek(0)
191+
with open(save_to, "wb") as savefile:
192+
savefile.write(b.read())
193+
194+
195+
# main loop
196+
while True:
197+
try:
198+
# attempt to read data from the mouse
199+
# 10ms timeout, so we don't block long if there
200+
# is no data
201+
count = mouse.read(0x81, buf, timeout=10)
202+
except usb.core.USBTimeoutError:
203+
# skip the rest of the loop if there is no data
204+
continue
205+
206+
# update the mouse tilegrid x and y coordinates
207+
# based on the delta values read from the mouse
208+
mouse_tg.x = max(0, min(display.width - 1, mouse_tg.x + buf[1]))
209+
mouse_tg.y = max(0, min(display.height - 1, mouse_tg.y + buf[2]))
210+
211+
# if left click is pressed
212+
if buf[0] & (1 << 0) != 0:
213+
# get the current cursor coordinates
214+
coords = (mouse_tg.x, mouse_tg.y, 0)
215+
216+
# loop over the buttons
217+
for button in all_buttons:
218+
# if the current button contains the mouse coords
219+
if button.contains(coords):
220+
# if the button isn't already in the selected state
221+
if not button.selected:
222+
# enter selected state
223+
button.selected = True
224+
225+
# if it is the pink button
226+
if button == pink_button:
227+
# increment pink count
228+
game_state["pink_count"] += 1
229+
# update the label
230+
pink_lbl.text = f"Pink: {game_state['pink_count']}"
231+
232+
# if it is the blue button
233+
elif button == blue_button:
234+
# increment blue count
235+
game_state["blue_count"] += 1
236+
# update the label
237+
blue_lbl.text = f"Blue: {game_state['blue_count']}"
238+
239+
# save the new game state
240+
save_game_state()
241+
242+
# if the click is not on the current button
243+
else:
244+
# set this button as not selected
245+
button.selected = False
246+
247+
# left click is not pressed
248+
else:
249+
# set all buttons as not selected
250+
for button in all_buttons:
251+
button.selected = False
198 Bytes
Binary file not shown.

Diff for: Metro/Metro_RP2350_Match3/match3_game/btn_exit.bmp

922 Bytes
Binary file not shown.

Diff for: Metro/Metro_RP2350_Match3/match3_game/btn_no_set.bmp

922 Bytes
Binary file not shown.
922 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)