Compare commits
5 Commits
main
...
examples/i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c0b40e220 | ||
|
|
228ecb1fc6 | ||
|
|
c0b95c2316 | ||
|
|
25930b58af | ||
|
|
c51c430cdf |
39
micropython/examples/interstate_75_w/cover-art.py
Normal file
39
micropython/examples/interstate_75_w/cover-art.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
"""
|
||||||
|
|
||||||
|
Simple example to display cover art.
|
||||||
|
|
||||||
|
Album art should be saved in 128 x 128 resolution PNG format
|
||||||
|
and placed in a folder called 'covers' in the root.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
from interstate75 import Interstate75, DISPLAY_INTERSTATE75_128X128
|
||||||
|
import pngdec
|
||||||
|
import os
|
||||||
|
from random import choice
|
||||||
|
|
||||||
|
# Time between covers
|
||||||
|
INTERVAL = 10
|
||||||
|
|
||||||
|
# Setup for the display
|
||||||
|
i75 = Interstate75(display=DISPLAY_INTERSTATE75_128X128, stb_invert=False, panel_type=Interstate75.PANEL_GENERIC)
|
||||||
|
display = i75.display
|
||||||
|
WIDTH, HEIGHT = display.get_bounds()
|
||||||
|
|
||||||
|
p = pngdec.PNG(display)
|
||||||
|
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
# Select a PNG image from our 'covers' folder at random
|
||||||
|
file = choice(os.listdir("covers"))
|
||||||
|
img = f"covers/{file}"
|
||||||
|
|
||||||
|
p.open_file(img)
|
||||||
|
|
||||||
|
# Decode our PNG file and set the X and Y
|
||||||
|
p.decode(0, 0)
|
||||||
|
|
||||||
|
i75.update()
|
||||||
|
time.sleep(INTERVAL)
|
||||||
156
micropython/examples/interstate_75_w/cubes.py
Normal file
156
micropython/examples/interstate_75_w/cubes.py
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
import time
|
||||||
|
import math
|
||||||
|
from random import randint, randrange
|
||||||
|
from interstate75 import Interstate75, DISPLAY_INTERSTATE75_128X128
|
||||||
|
|
||||||
|
# Setup for the display
|
||||||
|
i75 = Interstate75(
|
||||||
|
display=DISPLAY_INTERSTATE75_128X128, stb_invert=False, panel_type=Interstate75.PANEL_GENERIC)
|
||||||
|
display = i75.display
|
||||||
|
WIDTH, HEIGHT = display.get_bounds()
|
||||||
|
|
||||||
|
BLACK = display.create_pen(0, 0, 0)
|
||||||
|
WHITE = display.create_pen(255, 255, 255)
|
||||||
|
|
||||||
|
|
||||||
|
class Cube(object):
|
||||||
|
# The corners of the cube
|
||||||
|
vertices = [[-1, -1, 1],
|
||||||
|
[1, -1, 1],
|
||||||
|
[1, -1, -1],
|
||||||
|
[-1, -1, -1],
|
||||||
|
[-1, 1, 1],
|
||||||
|
[1, 1, 1],
|
||||||
|
[1, 1, -1],
|
||||||
|
[-1, 1, -1]]
|
||||||
|
|
||||||
|
# The corners that will be connected together to make a cube :)
|
||||||
|
edges = [(0, 1), (1, 2), (2, 3), (3, 0),
|
||||||
|
(4, 5), (5, 6), (6, 7), (7, 4),
|
||||||
|
(0, 4), (1, 5), (2, 6), (3, 7)]
|
||||||
|
|
||||||
|
def __init__(self, fov, distance, x, y, speed):
|
||||||
|
self.tick = time.ticks_ms() / 1000.0
|
||||||
|
self.cos = math.cos(self.tick)
|
||||||
|
self.sin = math.sin(self.tick)
|
||||||
|
self.fov = fov
|
||||||
|
self.distance = distance
|
||||||
|
self.pos_x = x
|
||||||
|
self.pos_y = y
|
||||||
|
self.speed = speed
|
||||||
|
|
||||||
|
self.cube_points = []
|
||||||
|
|
||||||
|
# Project our points
|
||||||
|
def to_2d(self, x, y, z, pos_x, pos_y, fov, distance):
|
||||||
|
factor = fov / (distance + z)
|
||||||
|
x = x * factor + pos_x
|
||||||
|
y = -y * factor + pos_y
|
||||||
|
|
||||||
|
return int(x), int(y)
|
||||||
|
|
||||||
|
def return_tick(self):
|
||||||
|
return self.tick
|
||||||
|
|
||||||
|
# Clear our points and recalculate the sin and cos values
|
||||||
|
def _update(self):
|
||||||
|
|
||||||
|
self.cube_points = []
|
||||||
|
|
||||||
|
self.tick = time.ticks_ms() / (self.speed * 1000)
|
||||||
|
self.cos = math.cos(self.tick)
|
||||||
|
self.sin = math.sin(self.tick)
|
||||||
|
|
||||||
|
def set_fov(self, fov):
|
||||||
|
self.fov = fov
|
||||||
|
|
||||||
|
def set_distance(self, distance):
|
||||||
|
self.distance = distance
|
||||||
|
|
||||||
|
def set_speed(self, speed):
|
||||||
|
self.speed = speed
|
||||||
|
|
||||||
|
def set_x(self, x):
|
||||||
|
self.pos_x = x
|
||||||
|
|
||||||
|
def set_y(self, y):
|
||||||
|
self.pos_y = y
|
||||||
|
|
||||||
|
def get_fov(self):
|
||||||
|
return self.fov
|
||||||
|
|
||||||
|
# Rotate on XYZ and save the new points in our list
|
||||||
|
def rotate(self):
|
||||||
|
|
||||||
|
for v in self.vertices:
|
||||||
|
|
||||||
|
start_x, start_y, start_z = v
|
||||||
|
|
||||||
|
# X
|
||||||
|
y = start_y * self.cos - start_z * self.sin
|
||||||
|
z = start_y * self.sin + start_z * self.cos
|
||||||
|
|
||||||
|
# Y
|
||||||
|
x = start_x * self.cos - z * self.sin
|
||||||
|
z = start_x * self.sin + z * self.cos
|
||||||
|
|
||||||
|
# Z
|
||||||
|
n_y = x * self.sin + y * self.cos
|
||||||
|
n_x = x * self.cos - y * self.sin
|
||||||
|
|
||||||
|
y = n_y
|
||||||
|
x = n_x
|
||||||
|
|
||||||
|
point = self.to_2d(x, y, z, self.pos_x, self.pos_y, self.fov, self.distance)
|
||||||
|
self.cube_points.append(point)
|
||||||
|
|
||||||
|
# Draw the edges of the cube so we can see it on screen!
|
||||||
|
def draw(self):
|
||||||
|
|
||||||
|
for edge in self.edges:
|
||||||
|
display.line(self.cube_points[edge[0]][0], self.cube_points[edge[0]][1], self.cube_points[edge[1]][0], self.cube_points[edge[1]][1])
|
||||||
|
|
||||||
|
self._update()
|
||||||
|
|
||||||
|
|
||||||
|
# Setup the first 3 cubes.
|
||||||
|
cubes = [Cube(16, 8, WIDTH / 2, HEIGHT / 2, 1.0), Cube(32, 8, 100, 100, 0.9), Cube(32, 8, 100, 100, 0.5)]
|
||||||
|
|
||||||
|
# Set our initial pen colour
|
||||||
|
pen = display.create_pen_hsv(1.0, 1.0, 1.0)
|
||||||
|
|
||||||
|
while 1:
|
||||||
|
|
||||||
|
# We'll use this for cycling through the rainbow
|
||||||
|
t = time.ticks_ms() / 1000
|
||||||
|
|
||||||
|
# Set the layer we're going to be drawing to.
|
||||||
|
display.set_layer(0)
|
||||||
|
|
||||||
|
# Clear the screen and set the pen colour for the cubes
|
||||||
|
display.set_pen(BLACK)
|
||||||
|
display.clear()
|
||||||
|
display.set_pen(WHITE)
|
||||||
|
display.text("Flying Cubes!", 33, 55, WIDTH, 1)
|
||||||
|
display.reset_pen(pen)
|
||||||
|
pen = display.create_pen_hsv(t, 1.0, 1.0)
|
||||||
|
display.set_pen(pen)
|
||||||
|
|
||||||
|
# Now we go through each Cube object we have in 'cubes'
|
||||||
|
# and increase the FOV angle so it appears closer to the screen.
|
||||||
|
# We'll also rotate the cube during this loop too.
|
||||||
|
for i, cube in enumerate(cubes):
|
||||||
|
fov = cube.get_fov()
|
||||||
|
fov += 3
|
||||||
|
cube.set_fov(fov)
|
||||||
|
cube.rotate()
|
||||||
|
cube.draw()
|
||||||
|
|
||||||
|
# We want the cubes to disappear randomly as they appear close to the screen, so we'll decide when this happens based on the current FOV
|
||||||
|
# We'll replace that cube with a new one and start the process from the beginning!
|
||||||
|
if fov > randint(250, 600):
|
||||||
|
cubes[i] = Cube(8, 8, randint(10, WIDTH), randint(10, HEIGHT), randrange(4, 9) / 10)
|
||||||
|
|
||||||
|
# Finally we update the display with our changes :)
|
||||||
|
i75.update()
|
||||||
|
time.sleep(0.03)
|
||||||
377
micropython/examples/interstate_75_w/random_maze.py
Normal file
377
micropython/examples/interstate_75_w/random_maze.py
Normal file
@ -0,0 +1,377 @@
|
|||||||
|
import gc
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from interstate75 import DISPLAY_INTERSTATE75_128X128, Interstate75
|
||||||
|
from machine import I2C
|
||||||
|
from qwstpad import ADDRESSES, QwSTPad
|
||||||
|
|
||||||
|
"""
|
||||||
|
A single player game demo. Navigate a set of mazes from the start (red) to the goal (green).
|
||||||
|
Mazes get bigger / harder with each increase in level.
|
||||||
|
Makes use of 1 QwSTPad and a 128x128 LED matrix + i75W.
|
||||||
|
|
||||||
|
Controls:
|
||||||
|
* U = Move Forward
|
||||||
|
* D = Move Backward
|
||||||
|
* R = Move Right
|
||||||
|
* L = Move left
|
||||||
|
* + = Continue (once the current level is complete)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# General Constants
|
||||||
|
I2C_PINS = {"id": 0, "sda": 20, "scl": 21} # The I2C pins the QwSTPad is connected to
|
||||||
|
I2C_ADDRESS = ADDRESSES[0] # The I2C address of the connected QwSTPad
|
||||||
|
BRIGHTNESS = 1.0 # The brightness of the LCD backlight (from 0.0 to 1.0)
|
||||||
|
|
||||||
|
# Gameplay Constants
|
||||||
|
Position = namedtuple("Position", ("x", "y"))
|
||||||
|
MIN_MAZE_WIDTH = 2
|
||||||
|
MAX_MAZE_WIDTH = 5
|
||||||
|
MIN_MAZE_HEIGHT = 2
|
||||||
|
MAX_MAZE_HEIGHT = 5
|
||||||
|
WALL_SHADOW = 1
|
||||||
|
WALL_GAP = 1
|
||||||
|
TEXT_SHADOW = 1
|
||||||
|
MOVEMENT_SLEEP = 0.1
|
||||||
|
DIFFICULT_SCALE = 0.5
|
||||||
|
|
||||||
|
# Setup for the display
|
||||||
|
i75 = Interstate75(
|
||||||
|
display=DISPLAY_INTERSTATE75_128X128, stb_invert=False, panel_type=Interstate75.PANEL_GENERIC)
|
||||||
|
display = i75.display
|
||||||
|
|
||||||
|
# Colour Constants
|
||||||
|
WHITE = display.create_pen(255, 255, 255)
|
||||||
|
BLACK = display.create_pen(0, 0, 0)
|
||||||
|
RED = display.create_pen(255, 0, 0)
|
||||||
|
GREEN = display.create_pen(0, 255, 0)
|
||||||
|
PLAYER = display.create_pen(227, 231, 110)
|
||||||
|
WALL = display.create_pen(127, 125, 244)
|
||||||
|
BACKGROUND = display.create_pen(60, 57, 169)
|
||||||
|
PATH = display.create_pen((227 + 60) // 2, (231 + 57) // 2, (110 + 169) // 2)
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
i2c = I2C(**I2C_PINS) # The I2C instance to pass to the QwSTPad
|
||||||
|
complete = False # Has the game been completed?
|
||||||
|
level = 0 # The current "level" the player is on (affects difficulty)
|
||||||
|
|
||||||
|
# Get the width and height from the display
|
||||||
|
WIDTH, HEIGHT = display.get_bounds()
|
||||||
|
|
||||||
|
|
||||||
|
# Classes
|
||||||
|
class Cell:
|
||||||
|
def __init__(self, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.bottom = True
|
||||||
|
self.right = True
|
||||||
|
self.visited = False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remove_walls(current, next):
|
||||||
|
dx, dy = current.x - next.x, current.y - next.y
|
||||||
|
if dx == 1:
|
||||||
|
next.right = False
|
||||||
|
if dx == -1:
|
||||||
|
current.right = False
|
||||||
|
if dy == 1:
|
||||||
|
next.bottom = False
|
||||||
|
if dy == -1:
|
||||||
|
current.bottom = False
|
||||||
|
|
||||||
|
|
||||||
|
class MazeBuilder:
|
||||||
|
def __init__(self):
|
||||||
|
self.width = 0
|
||||||
|
self.height = 0
|
||||||
|
self.cell_grid = []
|
||||||
|
self.maze = []
|
||||||
|
|
||||||
|
def build(self, width, height):
|
||||||
|
if width <= 0:
|
||||||
|
raise ValueError("width out of range. Expected greater than 0")
|
||||||
|
|
||||||
|
if height <= 0:
|
||||||
|
raise ValueError("height out of range. Expected greater than 0")
|
||||||
|
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
|
||||||
|
# Set the starting cell to the centre
|
||||||
|
cx = (self.width - 1) // 2
|
||||||
|
cy = (self.height - 1) // 2
|
||||||
|
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
# Create a grid of cells for building a maze
|
||||||
|
self.cell_grid = [[Cell(x, y) for y in range(self.height)] for x in range(self.width)]
|
||||||
|
cell_stack = []
|
||||||
|
|
||||||
|
# Retrieve the starting cell and mark it as visited
|
||||||
|
current = self.cell_grid[cx][cy]
|
||||||
|
current.visited = True
|
||||||
|
|
||||||
|
# Loop until every cell has been visited
|
||||||
|
while True:
|
||||||
|
next = self.choose_neighbour(current)
|
||||||
|
# Was a valid neighbour found?
|
||||||
|
if next is not None:
|
||||||
|
# Move to the next cell, removing walls in the process
|
||||||
|
next.visited = True
|
||||||
|
cell_stack.append(current)
|
||||||
|
Cell.remove_walls(current, next)
|
||||||
|
current = next
|
||||||
|
|
||||||
|
# No valid neighbour. Backtrack to a previous cell
|
||||||
|
elif len(cell_stack) > 0:
|
||||||
|
current = cell_stack.pop()
|
||||||
|
|
||||||
|
# No previous cells, so exit
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
# Use the cell grid to create a maze grid of 0's and 1s
|
||||||
|
self.maze = []
|
||||||
|
|
||||||
|
row = [1]
|
||||||
|
for x in range(0, self.width):
|
||||||
|
row.append(1)
|
||||||
|
row.append(1)
|
||||||
|
self.maze.append(row)
|
||||||
|
|
||||||
|
for y in range(0, self.height):
|
||||||
|
row = [1]
|
||||||
|
for x in range(0, self.width):
|
||||||
|
row.append(0)
|
||||||
|
row.append(1 if self.cell_grid[x][y].right else 0)
|
||||||
|
self.maze.append(row)
|
||||||
|
|
||||||
|
row = [1]
|
||||||
|
for x in range(0, self.width):
|
||||||
|
row.append(1 if self.cell_grid[x][y].bottom else 0)
|
||||||
|
row.append(1)
|
||||||
|
self.maze.append(row)
|
||||||
|
|
||||||
|
self.cell_grid.clear()
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
self.grid_columns = (self.width * 2 + 1)
|
||||||
|
self.grid_rows = (self.height * 2 + 1)
|
||||||
|
|
||||||
|
def choose_neighbour(self, current):
|
||||||
|
unvisited = []
|
||||||
|
for dx in range(-1, 2, 2):
|
||||||
|
x = current.x + dx
|
||||||
|
if x >= 0 and x < self.width and not self.cell_grid[x][current.y].visited:
|
||||||
|
unvisited.append((x, current.y))
|
||||||
|
|
||||||
|
for dy in range(-1, 2, 2):
|
||||||
|
y = current.y + dy
|
||||||
|
if y >= 0 and y < self.height and not self.cell_grid[current.x][y].visited:
|
||||||
|
unvisited.append((current.x, y))
|
||||||
|
|
||||||
|
if len(unvisited) > 0:
|
||||||
|
x, y = random.choice(unvisited)
|
||||||
|
return self.cell_grid[x][y]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def maze_width(self):
|
||||||
|
return (self.width * 2) + 1
|
||||||
|
|
||||||
|
def maze_height(self):
|
||||||
|
return (self.height * 2) + 1
|
||||||
|
|
||||||
|
def draw(self, display):
|
||||||
|
# Draw the maze we have built. Each '1' in the array represents a wall
|
||||||
|
for row in range(self.grid_rows):
|
||||||
|
for col in range(self.grid_columns):
|
||||||
|
# Calculate the screen coordinates
|
||||||
|
x = (col * wall_separation) + offset_x
|
||||||
|
y = (row * wall_separation) + offset_y
|
||||||
|
|
||||||
|
if self.maze[row][col] == 1:
|
||||||
|
# Draw a wall shadow
|
||||||
|
display.set_pen(BLACK)
|
||||||
|
display.rectangle(x + WALL_SHADOW, y + WALL_SHADOW, wall_size, wall_size)
|
||||||
|
|
||||||
|
# Draw a wall top
|
||||||
|
display.set_pen(WALL)
|
||||||
|
display.rectangle(x, y, wall_size, wall_size)
|
||||||
|
|
||||||
|
if self.maze[row][col] == 2:
|
||||||
|
# Draw the player path
|
||||||
|
display.set_pen(PATH)
|
||||||
|
display.rectangle(x, y, wall_size, wall_size)
|
||||||
|
|
||||||
|
|
||||||
|
class Player(object):
|
||||||
|
def __init__(self, x, y, colour, pad):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.colour = colour
|
||||||
|
self.pad = pad
|
||||||
|
|
||||||
|
def position(self, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
|
||||||
|
def update(self, maze):
|
||||||
|
# Read the player's gamepad
|
||||||
|
button = self.pad.read_buttons()
|
||||||
|
|
||||||
|
if button['L'] and maze[self.y][self.x - 1] != 1:
|
||||||
|
self.x -= 1
|
||||||
|
time.sleep(MOVEMENT_SLEEP)
|
||||||
|
|
||||||
|
elif button['R'] and maze[self.y][self.x + 1] != 1:
|
||||||
|
self.x += 1
|
||||||
|
time.sleep(MOVEMENT_SLEEP)
|
||||||
|
|
||||||
|
elif button['U'] and maze[self.y - 1][self.x] != 1:
|
||||||
|
self.y -= 1
|
||||||
|
time.sleep(MOVEMENT_SLEEP)
|
||||||
|
|
||||||
|
elif button['D'] and maze[self.y + 1][self.x] != 1:
|
||||||
|
self.y += 1
|
||||||
|
time.sleep(MOVEMENT_SLEEP)
|
||||||
|
|
||||||
|
maze[self.y][self.x] = 2
|
||||||
|
|
||||||
|
def draw(self, display):
|
||||||
|
display.set_pen(self.colour)
|
||||||
|
display.rectangle(self.x * wall_separation + offset_x,
|
||||||
|
self.y * wall_separation + offset_y,
|
||||||
|
wall_size, wall_size)
|
||||||
|
|
||||||
|
|
||||||
|
def build_maze():
|
||||||
|
global wall_separation
|
||||||
|
global wall_size
|
||||||
|
global offset_x
|
||||||
|
global offset_y
|
||||||
|
global start
|
||||||
|
global goal
|
||||||
|
|
||||||
|
difficulty = int(level * DIFFICULT_SCALE)
|
||||||
|
width = random.randrange(MIN_MAZE_WIDTH, MAX_MAZE_WIDTH)
|
||||||
|
height = random.randrange(MIN_MAZE_HEIGHT, MAX_MAZE_HEIGHT)
|
||||||
|
builder.build(width + difficulty, height + difficulty)
|
||||||
|
|
||||||
|
wall_separation = min(HEIGHT // builder.grid_rows,
|
||||||
|
WIDTH // builder.grid_columns)
|
||||||
|
wall_size = wall_separation - WALL_GAP
|
||||||
|
|
||||||
|
offset_x = (WIDTH - (builder.grid_columns * wall_separation) + WALL_GAP) // 2
|
||||||
|
offset_y = (HEIGHT - (builder.grid_rows * wall_separation) + WALL_GAP) // 2
|
||||||
|
|
||||||
|
start = Position(1, builder.grid_rows - 2)
|
||||||
|
goal = Position(builder.grid_columns - 2, 1)
|
||||||
|
|
||||||
|
|
||||||
|
# Create the maze builder and build the first maze and put
|
||||||
|
builder = MazeBuilder()
|
||||||
|
build_maze()
|
||||||
|
|
||||||
|
# Create the player object if a QwSTPad is connected
|
||||||
|
try:
|
||||||
|
player = Player(*start, PLAYER, QwSTPad(i2c, I2C_ADDRESS))
|
||||||
|
except OSError:
|
||||||
|
print("QwSTPad: Not Connected ... Exiting")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
print("QwSTPad: Connected ... Starting")
|
||||||
|
|
||||||
|
# Store text strings and calculate centre location
|
||||||
|
text_1_string = "Maze Complete!"
|
||||||
|
text_1_size = display.measure_text(text_1_string, 1)
|
||||||
|
|
||||||
|
text_2_string = "Press + to continue"
|
||||||
|
text_2_size = display.measure_text(text_2_string, 1)
|
||||||
|
|
||||||
|
text_1_location = ((WIDTH // 2) - (text_1_size // 2), 55)
|
||||||
|
text_2_location = ((WIDTH // 2) - (text_2_size // 2), 65)
|
||||||
|
|
||||||
|
# Wrap the code in a try block, to catch any exceptions (including KeyboardInterrupt)
|
||||||
|
try:
|
||||||
|
# Loop forever
|
||||||
|
while True:
|
||||||
|
if not complete:
|
||||||
|
# Update the player's position in the maze
|
||||||
|
player.update(builder.maze)
|
||||||
|
|
||||||
|
# Check if any player has reached the goal position
|
||||||
|
if player.x == goal.x and player.y == goal.y:
|
||||||
|
complete = True
|
||||||
|
else:
|
||||||
|
# Check for the player wanting to continue
|
||||||
|
if player.pad.read_buttons()['+']:
|
||||||
|
complete = False
|
||||||
|
level += 1
|
||||||
|
build_maze()
|
||||||
|
player.position(*start)
|
||||||
|
|
||||||
|
# Clear the screen to the background colour
|
||||||
|
display.set_pen(BACKGROUND)
|
||||||
|
display.clear()
|
||||||
|
|
||||||
|
# Draw the maze walls
|
||||||
|
builder.draw(display)
|
||||||
|
|
||||||
|
# Draw the start location square
|
||||||
|
display.set_pen(RED)
|
||||||
|
display.rectangle(start.x * wall_separation + offset_x,
|
||||||
|
start.y * wall_separation + offset_y,
|
||||||
|
wall_size, wall_size)
|
||||||
|
|
||||||
|
# Draw the goal location square
|
||||||
|
display.set_pen(GREEN)
|
||||||
|
display.rectangle(goal.x * wall_separation + offset_x,
|
||||||
|
goal.y * wall_separation + offset_y,
|
||||||
|
wall_size, wall_size)
|
||||||
|
|
||||||
|
# Draw the player
|
||||||
|
player.draw(display)
|
||||||
|
|
||||||
|
# Display the level
|
||||||
|
display.set_pen(BLACK)
|
||||||
|
display.text(f"Lvl: {level}", 2 + TEXT_SHADOW, 2 + TEXT_SHADOW, WIDTH, 1)
|
||||||
|
display.set_pen(WHITE)
|
||||||
|
display.text(f"Lvl: {level}", 2, 2, WIDTH, 1)
|
||||||
|
|
||||||
|
if complete:
|
||||||
|
# Draw banner shadow
|
||||||
|
display.set_pen(BLACK)
|
||||||
|
display.rectangle(4, 44, WIDTH, 50)
|
||||||
|
# Draw banner
|
||||||
|
display.set_pen(PLAYER)
|
||||||
|
display.rectangle(0, 40, WIDTH, 50)
|
||||||
|
|
||||||
|
# Draw text shadow
|
||||||
|
display.set_pen(BLACK)
|
||||||
|
display.text(f"{text_1_string}", text_1_location[0] + TEXT_SHADOW, text_1_location[1] + TEXT_SHADOW, WIDTH, 1)
|
||||||
|
display.text(f"{text_2_string}", text_2_location[0] + TEXT_SHADOW, text_2_location[1] + TEXT_SHADOW, WIDTH, 1)
|
||||||
|
|
||||||
|
# Draw text
|
||||||
|
display.set_pen(WHITE)
|
||||||
|
display.text(f"{text_1_string}", text_1_location[0], text_1_location[1], WIDTH, 1)
|
||||||
|
display.text(f"{text_2_string}", text_2_location[0], text_2_location[1], WIDTH, 1)
|
||||||
|
|
||||||
|
# Finally we update the display with our changes :)
|
||||||
|
i75.update()
|
||||||
|
|
||||||
|
# Handle the QwSTPad being disconnected unexpectedly
|
||||||
|
except OSError:
|
||||||
|
print("QwSTPad: Disconnected .. Exiting")
|
||||||
|
|
||||||
|
# Turn off the LEDs of the connected QwSTPad
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
player.pad.clear_leds()
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
118
micropython/examples/interstate_75_w/today.py
Normal file
118
micropython/examples/interstate_75_w/today.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
import machine
|
||||||
|
import network
|
||||||
|
import ntptime
|
||||||
|
from interstate75 import DISPLAY_INTERSTATE75_128X128, Interstate75
|
||||||
|
|
||||||
|
SHADOW_OFFSET = 1
|
||||||
|
|
||||||
|
# Check and import the Network SSID and Password from secrets.py
|
||||||
|
try:
|
||||||
|
from secrets import WIFI_PASSWORD, WIFI_SSID
|
||||||
|
if WIFI_SSID == "":
|
||||||
|
raise ValueError("WIFI_SSID in 'secrets.py' is empty!")
|
||||||
|
if WIFI_PASSWORD == "":
|
||||||
|
raise ValueError("WIFI_PASSWORD in 'secrets.py' is empty!")
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError("'secrets.py' is missing from your Plasma 2350 W!")
|
||||||
|
except ValueError as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
rtc = machine.RTC()
|
||||||
|
|
||||||
|
DAYS = ["Mon", "Tue", "Wed", "Thur", "Fri", "Sat", "Sun"]
|
||||||
|
|
||||||
|
# Enable the Wireless
|
||||||
|
wlan = network.WLAN(network.STA_IF)
|
||||||
|
wlan.active(True)
|
||||||
|
|
||||||
|
|
||||||
|
def network_connect(SSID, PSK):
|
||||||
|
|
||||||
|
# Number of attempts to make before timeout
|
||||||
|
max_wait = 5
|
||||||
|
|
||||||
|
# Sets the Wireless LED pulsing and attempts to connect to your local network.
|
||||||
|
print("connecting...")
|
||||||
|
wlan.config(pm=0xa11140) # Turn WiFi power saving off for some slow APs
|
||||||
|
wlan.connect(SSID, PSK)
|
||||||
|
|
||||||
|
while max_wait > 0:
|
||||||
|
if wlan.status() < 0 or wlan.status() >= 3:
|
||||||
|
break
|
||||||
|
max_wait -= 1
|
||||||
|
print('waiting for connection...')
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# Handle connection error. Switches the Warn LED on.
|
||||||
|
if wlan.status() != 3:
|
||||||
|
print("Unable to connect. Attempting connection again")
|
||||||
|
|
||||||
|
|
||||||
|
# Function to sync the Pico RTC using NTP
|
||||||
|
def sync_time():
|
||||||
|
|
||||||
|
try:
|
||||||
|
network_connect(WIFI_SSID, WIFI_PASSWORD)
|
||||||
|
except NameError:
|
||||||
|
print("Create secrets.py with your WiFi credentials")
|
||||||
|
|
||||||
|
if wlan.status() < 0 or wlan.status() >= 3:
|
||||||
|
try:
|
||||||
|
ntptime.settime()
|
||||||
|
except OSError:
|
||||||
|
print("Unable to sync with NTP server. Check network and try again.")
|
||||||
|
|
||||||
|
|
||||||
|
# Setup for the display
|
||||||
|
i75 = Interstate75(
|
||||||
|
display=DISPLAY_INTERSTATE75_128X128, stb_invert=False, panel_type=Interstate75.PANEL_GENERIC)
|
||||||
|
display = i75.display
|
||||||
|
|
||||||
|
WIDTH, HEIGHT = display.get_bounds()
|
||||||
|
|
||||||
|
# Pens
|
||||||
|
RED = display.create_pen(120, 0, 0)
|
||||||
|
WHITE = display.create_pen(255, 255, 255)
|
||||||
|
BLACK = display.create_pen(0, 0, 0)
|
||||||
|
|
||||||
|
sync_time()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
current_t = rtc.datetime()
|
||||||
|
|
||||||
|
# Set the pen to Red and clear the screen.
|
||||||
|
display.set_pen(WHITE)
|
||||||
|
display.clear()
|
||||||
|
|
||||||
|
# Measures the length of the text to help us with centring later.
|
||||||
|
day_length = display.measure_text(DAYS[current_t[3]], 4)
|
||||||
|
date_length = display.measure_text(str(current_t[2]), 7)
|
||||||
|
|
||||||
|
# Red banner
|
||||||
|
display.set_pen(RED)
|
||||||
|
display.rectangle(0, 0, WIDTH, 30)
|
||||||
|
|
||||||
|
# Drop Shadow
|
||||||
|
display.set_font("bitmap6")
|
||||||
|
display.set_pen(BLACK)
|
||||||
|
|
||||||
|
display.text(DAYS[current_t[3]], (WIDTH // 2) - (day_length // 2) + SHADOW_OFFSET, 2 + SHADOW_OFFSET, WIDTH, 4)
|
||||||
|
|
||||||
|
display.set_font("bitmap8")
|
||||||
|
display.text(str(current_t[2]), (WIDTH // 2) - (date_length // 2) + SHADOW_OFFSET + 4, 55 + SHADOW_OFFSET, WIDTH, 7)
|
||||||
|
|
||||||
|
# Main Text
|
||||||
|
display.set_font("bitmap6")
|
||||||
|
display.set_pen(WHITE)
|
||||||
|
display.text(DAYS[current_t[3]], (WIDTH // 2) - (day_length // 2), 2, WIDTH, 4)
|
||||||
|
|
||||||
|
display.set_pen(RED)
|
||||||
|
display.set_font("bitmap8")
|
||||||
|
display.text(str(current_t[2]), (WIDTH // 2) - (date_length // 2) + 4, 55, WIDTH, 7)
|
||||||
|
|
||||||
|
display.set_pen(display.create_pen(0, 0, 0))
|
||||||
|
|
||||||
|
i75.update()
|
||||||
Loading…
Reference in New Issue
Block a user