[refactor] Move screen class to separate file.
This commit is contained in:
+2
-1
@@ -1,2 +1,3 @@
|
|||||||
.vscode
|
.vscode
|
||||||
.micropico
|
.micropico
|
||||||
|
breakout.code-workspace
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
# Breakout Game for Raspberry Pi Pico
|
# Breakout Game for Raspberry Pi Pico
|
||||||
|
|
||||||
This is a simple Breakout game implemented in MicroPython for the Raspberry Pi Pico. The game uses the Pico-LCD-1.14 dDisplay for graphics and input.
|
This is a simple Breakout game implemented in MicroPython for the Raspberry Pi Pico. The game uses the Pico-LCD-1.14 dDisplay for graphics and input.
|
||||||
|
|
||||||
|
|
||||||
@@ -10,23 +9,19 @@ This is a simple Breakout game implemented in MicroPython for the Raspberry Pi P
|
|||||||
- Score tracking
|
- Score tracking
|
||||||
- Splash screen and game over screens
|
- Splash screen and game over screens
|
||||||
|
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
- Raspberry Pi Pico
|
- Raspberry Pi Pico
|
||||||
- Pico-LCD-1.14 display
|
- Pico-LCD-1.14 display
|
||||||
- MicroPython firmware installed on the Pico
|
- MicroPython firmware installed on the Pico
|
||||||
|
|
||||||
|
|
||||||
## Installation and Setup
|
## Installation and Setup
|
||||||
|
|
||||||
1. Connect the Pico-LCD-1.14 display to the Raspberry Pi Pico following the wiring diagram provided in the display's documentation.
|
1. Connect the Pico-LCD-1.14 display to the Raspberry Pi Pico following the wiring diagram provided in the display's documentation.
|
||||||
|
|
||||||
2. Download the MicroPython firmware for the Raspberry Pi Pico from the official MicroPython website and install it on the Pico. You can use the Thonny IDE to upload the firmware.
|
2. Download the MicroPython firmware for the Raspberry Pi Pico from the official MicroPython website and install it on the Pico. You can use the Thonny IDE to upload the firmware.
|
||||||
|
|
||||||
3. Clone or download this repository to your local machine.
|
3. Clone or download this repository to your local machine.
|
||||||
|
|
||||||
4. Open the Thonny IDE and connect to your Raspberry Pi Pico.
|
4. Open the Thonny IDE and connect to your Raspberry Pi Pico.
|
||||||
|
|
||||||
5. Copy the contents of the repository to the Pico's file system. You can do this by dragging and dropping the files from your local machine to the Thonny file explorer.
|
5. Copy the contents of the repository to the Pico's file system. You can do this by dragging and dropping the files from your local machine to the Thonny file explorer.
|
||||||
|
6. Once the files are copied, reset the Pico to start the game.
|
||||||
|
|
||||||
6. Once the files are copied, reset the Pico to start the game.
|
## .env file
|
||||||
|
In the .env file the user can control the behaviour of the joystick B-button.
|
||||||
|
DISABLE_B = 0 | 1 # Values: 0 = pressing B quits the program, 1 = pressing B does nothing.
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"folders": [
|
|
||||||
{
|
|
||||||
"path": "."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Mpy Remote Workspace",
|
|
||||||
"uri": "pico:"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"python.languageServer": "Pylance"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+9
-73
@@ -1,38 +1,20 @@
|
|||||||
"""
|
"""
|
||||||
Threaded breakout game with frame buffer
|
Threaded breakout game with frame buffer
|
||||||
|
|
||||||
Uses a single shot function for second core SPI handler.
|
Author: Seppe De Loore
|
||||||
This cleans itself when the function exits removing the
|
|
||||||
need for a garbage collection call.
|
|
||||||
"""
|
"""
|
||||||
from gc import collect
|
|
||||||
collect()
|
|
||||||
|
|
||||||
# import libraries
|
from random import randint
|
||||||
import math
|
from utime import sleep_us
|
||||||
import array
|
from screen import Screen, RED, YELLOW, GREEN, WHITE
|
||||||
from machine import Pin, SPI
|
|
||||||
import framebuf
|
|
||||||
from random import random, seed, randint
|
|
||||||
from utime import sleep_us, ticks_cpu, ticks_us
|
|
||||||
import _thread
|
import _thread
|
||||||
import st7789 as st7789
|
|
||||||
from helpers import Joystick, color565
|
|
||||||
|
|
||||||
# ============================
|
|
||||||
# Helper Functions
|
|
||||||
# ============================
|
|
||||||
|
|
||||||
RED = color565(0, 0, 255)
|
|
||||||
GREEN = color565(0, 255, 0)
|
|
||||||
YELLOW = color565(0, 255, 255)
|
|
||||||
BLACK = color565(0, 0, 0)
|
|
||||||
WHITE = color565(255, 255, 255)
|
|
||||||
|
|
||||||
|
from joystick import Joystick
|
||||||
|
|
||||||
# ============================
|
# ============================
|
||||||
# Constants and Configuration
|
# Constants and Configuration
|
||||||
# ============================
|
# ============================
|
||||||
|
|
||||||
SCREEN_HEIGHT = 135
|
SCREEN_HEIGHT = 135
|
||||||
SCREEN_WIDTH = 240
|
SCREEN_WIDTH = 240
|
||||||
SCREEN_ROTATION = 1 # Landscape mode
|
SCREEN_ROTATION = 1 # Landscape mode
|
||||||
@@ -68,7 +50,7 @@ DEBOUNCE = 300_000
|
|||||||
# ============================
|
# ============================
|
||||||
try:
|
try:
|
||||||
DISABLE_B = 0
|
DISABLE_B = 0
|
||||||
with open("env", "r") as file:
|
with open(".env", "r") as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
key, value = line.strip().split("=")
|
key, value = line.strip().split("=")
|
||||||
if key == "DISABLE_B":
|
if key == "DISABLE_B":
|
||||||
@@ -81,51 +63,6 @@ except:
|
|||||||
# CLASSES
|
# CLASSES
|
||||||
# ============================
|
# ============================
|
||||||
|
|
||||||
class Screen:
|
|
||||||
def __init__(self, width: int, height: int, rotation: int):
|
|
||||||
self.spi: SPI = SPI(1,
|
|
||||||
baudrate=31250000,
|
|
||||||
polarity=1,
|
|
||||||
phase=1,
|
|
||||||
bits=8,
|
|
||||||
firstbit=SPI.MSB,
|
|
||||||
sck=Pin(10),
|
|
||||||
mosi=Pin(11))
|
|
||||||
self.width: int = width
|
|
||||||
self.height: int = height
|
|
||||||
self.rotation: int = rotation
|
|
||||||
self.display = st7789.ST7789(
|
|
||||||
self.spi,
|
|
||||||
self.height,
|
|
||||||
self.width,
|
|
||||||
reset=Pin(12, Pin.OUT),
|
|
||||||
cs=Pin(9, Pin.OUT),
|
|
||||||
dc=Pin(8, Pin.OUT),
|
|
||||||
backlight=Pin(13, Pin.OUT),
|
|
||||||
rotation=self.rotation)
|
|
||||||
# FrameBuffer needs 2 bytes for every RGB565 pixel
|
|
||||||
self.buffer_width = self.width
|
|
||||||
self.buffer_height = self.height + 1
|
|
||||||
self.buffer = bytearray(self.buffer_width * self.buffer_height * 2)
|
|
||||||
self.fbuf: framebuf.FrameBuffer = framebuf.FrameBuffer(self.buffer, self.buffer_width, self.buffer_height, framebuf.RGB565)
|
|
||||||
self.render_frame = False
|
|
||||||
|
|
||||||
def refresh(self):
|
|
||||||
self.display.blit_buffer(self.buffer, 0, 0, self.buffer_width, self.buffer_height)
|
|
||||||
|
|
||||||
def clear(self, refresh: bool = True):
|
|
||||||
self.fbuf.fill(BLACK)
|
|
||||||
if refresh:
|
|
||||||
self.refresh()
|
|
||||||
|
|
||||||
def render_thread(self):
|
|
||||||
"""Threaded function to handle SPI rendering on a separate core."""
|
|
||||||
self.display.blit_buffer(self.buffer, 0, 0, self.buffer_width, self.buffer_height)
|
|
||||||
self.fbuf.fill(BLACK)
|
|
||||||
self.render_frame = False
|
|
||||||
# thread will exit and self clean removing need for garbage collection
|
|
||||||
|
|
||||||
|
|
||||||
class Paddle:
|
class Paddle:
|
||||||
def __init__(self, screen: Screen):
|
def __init__(self, screen: Screen):
|
||||||
"""Initialize the paddle."""
|
"""Initialize the paddle."""
|
||||||
@@ -152,9 +89,8 @@ class Paddle:
|
|||||||
"""Draw paddle."""
|
"""Draw paddle."""
|
||||||
screen.fbuf.fill_rect(self.x, self.y, self.width, self.height, PADDLE_COLOR)
|
screen.fbuf.fill_rect(self.x, self.y, self.width, self.height, PADDLE_COLOR)
|
||||||
|
|
||||||
def update(self, screen: Screen):
|
def update(self, screen: Screen, joystick: Joystick):
|
||||||
"""Update paddle position."""
|
"""Update paddle position."""
|
||||||
global joystick
|
|
||||||
if joystick.joy_left() == 0:
|
if joystick.joy_left() == 0:
|
||||||
self.move(-1)
|
self.move(-1)
|
||||||
elif joystick.joy_right() == 0:
|
elif joystick.joy_right() == 0:
|
||||||
@@ -431,7 +367,7 @@ def main_loop(screen, joystick):
|
|||||||
sleep_us(DEBOUNCE) # Debounce delay
|
sleep_us(DEBOUNCE) # Debounce delay
|
||||||
|
|
||||||
elif game_state == PLAYING and lives > 0 and score < 28: # Game loop
|
elif game_state == PLAYING and lives > 0 and score < 28: # Game loop
|
||||||
paddle.update(screen)
|
paddle.update(screen, joystick)
|
||||||
if ball_stuck:
|
if ball_stuck:
|
||||||
# Keep the ball stuck to the paddle
|
# Keep the ball stuck to the paddle
|
||||||
ball.x = paddle.x + (paddle.width // 2)
|
ball.x = paddle.x + (paddle.width // 2)
|
||||||
|
|||||||
@@ -12,12 +12,3 @@ class Joystick:
|
|||||||
self.joy_left = Pin(16, Pin.IN, Pin.PULL_UP)
|
self.joy_left = Pin(16, Pin.IN, Pin.PULL_UP)
|
||||||
self.joy_right = Pin(20, Pin.IN, Pin.PULL_UP)
|
self.joy_right = Pin(20, Pin.IN, Pin.PULL_UP)
|
||||||
self.joy_click = Pin(3, Pin.IN, Pin.PULL_UP)
|
self.joy_click = Pin(3, Pin.IN, Pin.PULL_UP)
|
||||||
|
|
||||||
|
|
||||||
def color565(red: int, green: int, blue: int) -> int:
|
|
||||||
"""Convert RGB888 to RGB565."""
|
|
||||||
return (
|
|
||||||
(((green & 0b00011100) << 3) + ((red & 0b11111000) >> 3) << 8)
|
|
||||||
+ (blue & 0b11111000)
|
|
||||||
+ ((green & 0b11100000) >> 5)
|
|
||||||
)
|
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
from machine import Pin, SPI
|
||||||
|
import _thread
|
||||||
|
from st7789 import ST7789
|
||||||
|
from framebuf import FrameBuffer, RGB565
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def color565(red: int, green: int, blue: int) -> int:
|
||||||
|
"""Convert RGB888 to RGB565."""
|
||||||
|
return (
|
||||||
|
(((green & 0b00011100) << 3) + ((red & 0b11111000) >> 3) << 8)
|
||||||
|
+ (blue & 0b11111000)
|
||||||
|
+ ((green & 0b11100000) >> 5)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
RED = color565(0, 0, 255)
|
||||||
|
GREEN = color565(0, 255, 0)
|
||||||
|
YELLOW = color565(0, 255, 255)
|
||||||
|
BLACK = color565(0, 0, 0)
|
||||||
|
WHITE = color565(255, 255, 255)
|
||||||
|
|
||||||
|
|
||||||
|
class Screen:
|
||||||
|
"""Class to handle the ST7789 display and framebuffer."""
|
||||||
|
def __init__(self, width: int, height: int, rotation: int):
|
||||||
|
self.spi: SPI = SPI(1,
|
||||||
|
baudrate=31250000,
|
||||||
|
polarity=1,
|
||||||
|
phase=1,
|
||||||
|
bits=8,
|
||||||
|
firstbit=SPI.MSB,
|
||||||
|
sck=Pin(10),
|
||||||
|
mosi=Pin(11))
|
||||||
|
self.width: int = width
|
||||||
|
self.height: int = height
|
||||||
|
self.rotation: int = rotation
|
||||||
|
self.display = ST7789(
|
||||||
|
self.spi,
|
||||||
|
self.height,
|
||||||
|
self.width,
|
||||||
|
reset=Pin(12, Pin.OUT),
|
||||||
|
cs=Pin(9, Pin.OUT),
|
||||||
|
dc=Pin(8, Pin.OUT),
|
||||||
|
backlight=Pin(13, Pin.OUT),
|
||||||
|
rotation=self.rotation)
|
||||||
|
# FrameBuffer needs 2 bytes for every RGB565 pixel
|
||||||
|
self.buffer_width = self.width
|
||||||
|
self.buffer_height = self.height + 1
|
||||||
|
self.buffer = bytearray(self.buffer_width * self.buffer_height * 2)
|
||||||
|
self.fbuf: FrameBuffer = FrameBuffer(self.buffer, self.buffer_width, self.buffer_height, RGB565)
|
||||||
|
self.render_frame = False
|
||||||
|
|
||||||
|
def refresh(self):
|
||||||
|
self.display.blit_buffer(self.buffer, 0, 0, self.buffer_width, self.buffer_height)
|
||||||
|
|
||||||
|
def clear(self, refresh: bool = True):
|
||||||
|
self.fbuf.fill(BLACK)
|
||||||
|
if refresh:
|
||||||
|
self.refresh()
|
||||||
|
|
||||||
|
def render_thread(self):
|
||||||
|
"""Threaded function to handle SPI rendering on a separate core."""
|
||||||
|
self.display.blit_buffer(self.buffer, 0, 0, self.buffer_width, self.buffer_height)
|
||||||
|
self.fbuf.fill(BLACK)
|
||||||
|
self.render_frame = False
|
||||||
|
# thread will exit and self clean removing need for garbage collection
|
||||||
Reference in New Issue
Block a user