Spielerisch Lernen - [Teil 2]

Programe juegos usted mismo y fabrique controladores de juegos usted mismo con poco esfuerzo - Parte 2

En la primera parte le mostré la idea de hacer su propio controlador de juego e introduje la carrera de tortugas, en la que tenía que presionar su botón lo más rápido posible para que su tortuga cruzara la línea de meta primero. Hoy quiero mostrarle un juego con dispositivos de entrada analógica.

Pong es el primer videojuego que se distribuye en todo el mundo. La primera versión de 1972 fue desarrollada por Atari para salas de juegos. Con la expansión de las computadoras domésticas en la década de 1980, también hubo versiones para ellas. Este juego nunca ha desaparecido, hay nuevas ideas de implementación debido principalmente a la difusión de la Raspberry Pi y la nueva ola de entusiasmo por la programación.

El principio de juego de Pong es similar al de Tenis de mesa: La bola se mueve de izquierda a derecha y vuelve a la pantalla. Cada uno de los dos jugadores controla un club con un botón giratorio (Paddle) arriba y abajo para devolver la pelota. Si esto no tiene éxito, el oponente recibe un punto.

Hardware requerido

Para mover las raquetas necesita dos mandos de juego, para los que se requieren soluciones creativas, porque las Paddles originales ya no se pueden comprar. El mouse podría ser una solución si el segundo jugador es reemplazado por la inmejorable computadora. En este blog queremos usar Paddles de fabricación propia con potenciómetros de 10 kOhm (ver imagen), pero también se nos ocurre la idea con Sensores de distancia ultrasónicos en el Blog de la Fundación Raspberry Pi .


Seguramente ha reconocido el material básico para el dispositivo de juego. Una vez que haya comido el chocolate y eliminado la sorpresa, puede perforar los "huevos" amarillos en la parte superior e inferior e instalar los potenciómetros con tres cables cada uno.

Las señales analógicas del potenciómetro en conexión con Raspberry Pi significan que necesitamos un convertidor de analógico a digital (ADC) como el MCP3004 o MCP3008. Estos son los momentos en los que los Raspians envidiamos a la facción Arduino por las entradas analógicas. Afortunadamente, el MCP3004 es un componente fácil de usar, cuya evaluación es compatible con el módulo de Python gpiozero.

Eso sí, primero debemos activar la interfaz SPI en la configuración de Raspberry Pi. Alternativamente, con los cambios necesarios en el programa, un ADS1115 en el bus I2C. Esto se hace usando el módulo Adafruit Python ADS1x15.

Para los gráficos animados usamos el módulo pygamezero (pgzrun), una nueva variante reducida del módulo pygame muy extenso y muy poderoso. Mark Vanstone proporciona una introducción a la programación con pgzrun en The Revista MagPi, incluida en el número 77 donde vi y desarrollé su versión de pong.

No quiero ocultar el hecho de que no lo logré todo yo solo. La visualización de la puntuación en la interfaz gráfica de usuario al final del juego causó problemas, por lo que busqué ayuda en el foro de la organización Raspberry Pi. ¡Y obtenido! Debido a la moderación, el mejor foro que conozco, pero en inglés.

https://www.raspberrypi.org/forums/viewtopic.php?t=234306

La estructura

Aquí está el diagrama de circuito con Raspberry Pi, MCP3008 y dos potenciómetros. Tenga en cuenta que el IC requiere tanto una tensión de alimentación como una tensión de referencia para el ADC. En nuestro caso ambos tiempos 3.3V y GND. DOUT está conectado con MISO (pin21), DIN conectado con MOSI (pin19), CLK con CLK (pin23) y CS con CE0 (pin24). El conteo de las entradas analógicas comienza en 0.


En nuestro ejemplo de programa, utilizo el MCP3004, la variante con cuatro entradas analógicas. Junto con un Raspi-Breadboard-Cobbler, cabe en la mitad de una placa de pruebas (ver imagen de arriba).

Me limito a las explicaciones que he añadido. Para las explicaciones sobre pygamezero, me refiero al enlace de arriba. El MagPi 77.

El software

Con desde gpiozero import MCP3004 importamos la clase gpiozero.MCP3004 y luego instanciamos dos objetos pot1=MCP3004(0) y pot2=MCP3004(1). Como se mencionó anteriormente, el conteo de las entradas analógicas comienza en 0.

Además del BALLSPEED, que inicialmente fijamos más bajo que en el código original y luego lo incrementamos cada 60 segundos, definimos un final cuando el primer jugador ha anotado 10 puntos y un RESTART automático.

Aquí está el código del programa completo:

# pong game based on pygamezero
# Pong was the first video game with world-wide distribution, published in 1972Pong
# source The MagPi magazine issue 77, pages 32 - 35
# modified by Raspberry Pi course at JFS Bad Bramstedt, Germany
# with the decisive contribution by MarkyV at raspberrypi.org/forums
# also thanks to Lucy Hattersley, editor of The MagPi magazine
# BALLSPEED starts rather slow, but increases every 60 seconds
# Game over, when one player scores 10
# Restart: Press Space Bar

import pgzrun
import random
from gpiozero import MCP3004
import math
from time import time, sleep          # new

pot1 = MCP3004(0)
pot2 = MCP3004(1)

# Set up the colours
BLACK = (0  ,0  ,0  )
WHITE = (255,255,255)
p1Score = p2Score = 0
END = 10                           # new: end of game, when first player has scored END
RESTART = 15                   # restart after xx seconds                             
BALLSPEED = 3                 # changed from 5 to 3
p1Y = 300
p2Y = 300
TIME = time()


def draw():
    global screen, p1Score, p2Score
    screen.fill(BLACK)
    screen.draw.line((400,0),(400,600),"green")
    drawPaddles()
    drawBall()
    screen.draw.text(str(p1Score) , center=(105, 40), color=WHITE, fontsize=60)
    screen.draw.text(str(p2Score) , center=(705, 40), color=WHITE, fontsize=60)
    if p2Score==END:
        screen.draw.text("Player2 wins!" , center=(400, 30), color=WHITE, fontsize=60)
    if p1Score==END:
        screen.draw.text("Player1 wins!", center=(400, 30), color=WHITE, fontsize=60)

def on_key_down(key):
    global p1Score, p2Score, BALLSPEED
    if (p2Score == END or p1Score == END) and key.name == "SPACE":
        p1Score = p2Score = 0
        BALLSPEED = 3
        print("Restart")
        
def update():
    updatePaddles()
    if p2Score < END and p1Score < END:
        updateBall()

def init():
    global ballX, ballY, ballDirX, ballDirY
    ballX = 400
    ballY = 300
    a = random.randint(10, 350)
    while (a > 80 and a < 100) or (a > 260 and a < 280):
        a = random.randint(10, 350)
    ballDirX = math.cos(math.radians(a))
    ballDirY = math.sin(math.radians(a))

def drawPaddles():
    global p1Y, p2Y
    p1rect = Rect((100, p1Y-30), (10, 60))
    p2rect = Rect((700, p2Y-30), (10, 60))
    screen.draw.filled_rect(p1rect, "red")
    screen.draw.filled_rect(p2rect, "red")

def updatePaddles():
    global p1Y, p2Y
    p1Y = (pot1.value * 540) +30
    p2Y = (pot2.value * 540) +30
    
    if keyboard.up:
        if p2Y > 30:
            p2Y -= 2
    if keyboard.down:
        if p2Y < 570:
            p2Y += 2
    if keyboard.w:
        if p1Y > 30:
            p1Y -= 2
    if keyboard.s:
        if p1Y < 570:
            p1Y += 2
            
def updateBall():
    global ballX, ballY, ballDirX, ballDirY, p1Score, p2Score, BALLSPEED, TIME
    ballX += ballDirX*BALLSPEED
    ballY += ballDirY*BALLSPEED
    ballRect = Rect((ballX-4,ballY-4),(8,8))
    p1rect = Rect((100, p1Y-30), (10, 60))
    p2rect = Rect((700, p2Y-30), (10, 60))
    if  time() - TIME > 60:             	#new
        BALLSPEED += 1                  	#new
        TIME = time()                   	#new
        print("BALLSPEED is now: ", BALLSPEED)

    if checkCollide(ballRect, p1rect) or checkCollide(ballRect, p2rect):
        ballDirX *= -1
    if ballY < 4 or ballY > 596:
        ballDirY *= -1
    if ballX < 0:
        p2Score += 1
        init()
    if ballX > 800:
        p1Score += 1
        init()  

def checkCollide(r1,r2):
    return (
        r1.x < r2.x + r2.w and
        r1.y < r2.y + r2.h and
        r1.x + r1.w > r2.x and
        r1.y + r1.h > r2.y
    )

def drawBall():
    screen.draw.filled_circle((ballX, ballY), 8, "white")
    pass
    
init()
pgzrun.go()

Diviértase haciendo y jugando


Proyectos para principiantes

1 comentario

Bernd-Steffen Großmann

Bernd-Steffen Großmann

Hallo Herr Albrecht, zunächst einmal herzlichen Dank für den interessanten und unterhaltsamen Beitrag, der die Themen Mikrocontroller, Programmieren und Spielen bedient und sicher bei vielen interessierten Makern das Interesse an dem Raspi, dessen Programmierung und dem Selbstbau der nötigen Hardware weckt bzw. vertieft. Der Blog hat bestimmt einige Reichweite in der DIY-Welt. Mir ist auch bewusst, dass die Darstellung der Schaltung in dem Zusammenhang als „Freiflug“-Verdrahtung mit Steckbrett und Steckkabeln in Fritzing-Grafik üblich geworden ist. Ich finde es aber immer gut, wenn die Beiträge auch mit einem ordentlichen elektrischen Schaltbild versehen werden, wie jeder Elektroniker und Nachrichtentechnik-Student (mancher sogar in der Schule in Physik) gelernt hat. Das als kleine Kritik. Die größere muss ich an die Konsistenz des Beitrags anbringen. In der Schaltung und deren Beschreibung verwenden Sie den MCP3008, aber im Programm und dessen Erläuterung den MCP3004! Jemand, der sich mit Schaltungstechnik und Programmierung schon auskennt, wird es nicht schwer fallen, die Komponente gegen die jeweils andere zu ersetzen, aber diejenigen, die einfach nachbauen wollen, für die wird es eine Herausforderung, der sie wohl nicht immer gewachsen sind. Also: warum haben Sie sich nicht an ein und denselben AD-Wandler in Schaltung und Programmierung gehalten?

Deja un comentario

Todos los comentarios son moderados antes de ser publicados

Artículos de blog

  1. Ahora instalamos el esp32 a través de la administración.
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. Transporte Aéreo - programación de ESP mediante redes locales inalámbricas