Martin Collins
Published © GPL3+

Ping pong game in super tiny RP2040

Hand gesture ultrasonic game using super tiny RP2040

BeginnerProtip1 hour799
Ping pong game in super tiny RP2040

Things used in this project

Hardware components

Super Tiny RP2040/ESP32 Display Development Board
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1

Software apps and online services

thonny

Story

Read more

Code

main.py

Python
game code
from machine import Pin, I2C, PWM, SPI
from time import sleep, ticks_us, ticks_diff
import array
import rp2
import utime
import st7789
import vga1_8x16 as font1
import vga1_16x32 as font
import vga1_16x16 as font2
import random

# Initialize display
spi = SPI(1, baudrate=40000000, sck=Pin(10), mosi=Pin(11))
tft = st7789.ST7789(spi, 128, 128, reset=Pin(6, Pin.OUT), cs=Pin(13, Pin.OUT), dc=Pin(12, Pin.OUT), backlight=Pin(14, Pin.OUT), rotation=3)
tft.init()
utime.sleep(0.2)

# Initialize ultrasound sensor
trigger = Pin(27, Pin.OUT)
echos = Pin(28, Pin.IN)

# Game variables
ball_x, ball_y = 64, 64  # Ball starts at the center
ball_speed_x, ball_speed_y = 2, 2  # Ball speed
paddle1_y, paddle2_y = 50, 50  # Initial paddle positions
paddle_width, paddle_height = 4, 20
score1, score2 = 0, 0
game_over = False

# Function to measure distance using ultrasound sensor
def measure_distance():
    trigger.value(0)
    sleep(0.002)
    trigger.value(1)
    sleep(0.00001)
    trigger.value(0)
    while echos.value() == 0:
        pass
    start = ticks_us()
    while echos.value() == 1:
        pass
    end = ticks_us()
    duration = ticks_diff(end, start)
    distance = (duration * 0.0343) / 2
    return distance

# Function to draw paddles and ball
def draw_game():
    tft.fill(st7789.BLACK)  # Clear screen
    # Draw paddles
    tft.fill_rect(0, int(paddle1_y), paddle_width, paddle_height, st7789.WHITE)  # Player paddle
    tft.fill_rect(124, int(paddle2_y), paddle_width, paddle_height, st7789.WHITE)  # AI paddle
    # Draw ball
    tft.fill_rect(int(ball_x), int(ball_y), 4, 4, st7789.WHITE)
    # Draw scores
    tft.text(font, str(score1), 30, 5, st7789.WHITE)
    tft.text(font, str(score2), 90, 5, st7789.WHITE)

# Main game loop
while not game_over:
    # Measure distance and update player paddle position
    distance = measure_distance()
    paddle1_y = max(0, min(128 - paddle_height, distance * 2))  # Map distance to paddle position

    # Update ball position
    ball_x += ball_speed_x
    ball_y += ball_speed_y

    # Ball collision with top and bottom walls
    if ball_y <= 0 or ball_y >= 124:
        ball_speed_y *= -1
        ball_speed_x += random.choice([-1, 1])  # Randomly increase or decrease X direction for a "jumping" effect

    # Ball collision with paddles
    if ball_x <= paddle_width and paddle1_y <= ball_y <= paddle1_y + paddle_height:
        ball_speed_x *= -1  # Reverse ball direction
        ball_speed_y += random.choice([-1, 1])  # Increase randomness after hitting player paddle
    if ball_x >= 124 - paddle_width and paddle2_y <= ball_y <= paddle2_y + paddle_height:
        ball_speed_x *= -1  # Reverse ball direction
        ball_speed_y += random.choice([-1, 1])  # Increase randomness after hitting AI paddle

    # Ball out of bounds (score)
    if ball_x <= 0:
        score2 += 1  # AI scores
        ball_x, ball_y = 64, 64  # Reset ball position
        ball_speed_x, ball_speed_y = random.choice([-2, 2]), random.choice([-2, 2])  # Random direction
    if ball_x >= 128:
        score1 += 1  # Player scores
        ball_x, ball_y = 64, 64  # Reset ball position
        ball_speed_x, ball_speed_y = random.choice([-2, 2]), random.choice([-2, 2])  # Random direction

    # AI paddle movement (increased sensitivity)
    if paddle2_y + paddle_height / 2 < ball_y:
        paddle2_y += 2  # Increase AI paddle movement speed
    elif paddle2_y + paddle_height / 2 > ball_y:
        paddle2_y -= 2  # Increase AI paddle movement speed

    # Draw game
    draw_game()

    # Check for game over
    if score1 >= 10 or score2 >= 10:
        game_over = True
        tft.text(font, "Game Over!", 20, 50, st7789.WHITE)
        if score1 >= 10:
            tft.text(font, "You Win!", 30, 80, st7789.WHITE)
        else:
            tft.text(font, "AI Wins!", 30, 80, st7789.WHITE)

    # Delay for smooth gameplay
    sleep(0.02)

Credits

Martin Collins
2 projects • 2 followers
Maker, Educator, Researcher
Contact
Thanks to Majeed Mohsin.

Comments

Please log in or sign up to comment.