Programmer soi-même des jeux et fabriquer des contrôleurs de jeu avec peu d'efforts - Partie 2
Dans la première partie, je vous ai montré l'idée de fabriquer vos propres manettes de jeu et la course de tortues, où vous deviez appuyer sur votre bouton aussi vite que possible pour que votre tortue franchisse la ligne d'arrivée la première. Aujourd'hui, je voudrais vous montrer un jeu avec des appareils d'entrée analogiques.
Pong est le premier jeu vidéo à distribution mondiale. La première version qui date de 1972 a été développée par la société Atari pour les arcades. Avec la diffusion des ordinateurs domestiques dans les années 1980, il y a eu aussi des versions pour cela. Ce jeu n'a jamais disparu, les nouvelles idées de mise en œuvre sont principalement dues à la diffusion du Raspberry Pi et à la nouvelle vague d'enthousiasme pour la programmation.
Le principe du jeu de Pong est similaire à celui du tennis de table : la balle se déplace sur l'écran de gauche à droite et de l'autre côté. Chacun des deux joueurs contrôle une raquette avec un bouton rotatif (paddle) de haut en bas pour rejouer la balle. Si cela ne réussit pas, l'adversaire reçoit un point.
Matériel requis
Pour le déplacement des raquettes, il faut deux contrôleurs de jeu, où des solutions créatives sont nécessaires, car on ne peut plus acheter les pagaies originales. La souris pourrait être une solution si le deuxième joueur est remplacé par l'ordinateur imbattable. Dans ce blog, nous voulons utiliser des pagaies faites maison avec des potentiomètres de 10 kOhm (voir photo), mais nous évoquons également l'idée de capteurs de distance à ultrasons dans le blog de la Fondation Raspberry Pi.
Vous avez certainement reconnu le matériel de base pour les contrôleurs de jeu. Après avoir mangé le chocolat et sorti la surprise, vous pouvez percer des trous dans le haut et le bas des "œufs" jaunes et installer les potentiomètres, chacun équipé de trois câbles.
Les signaux analogiques du pot en conjonction avec Raspberry Pi signifie que nous avons besoin d'un convertisseur analogique-numérique (ADC) tel que le MCP3004 ou le MCP3008. Ce sont les moments où nous, les Raspins, envions la faction Arduino pour avoir des entrées analogiques. Heureusement, le MCP3004 est un appareil facile à utiliser dont l'évaluation est prise en charge par le module Python gpiozero.
Bien sûr, nous devons d'abord activer l'interface SPI dans la configuration Raspberry Pi. On peut aussi utiliser un ADS1115 sur le bus I2C en apportant les modifications nécessaires au programme. Pour cela, on utilise le module Python de l'ADS1x15 d'Adafruit.
Pour les graphiques animés, nous utilisons le module pygamezero (pgzrun), une nouvelle variante simplifiée du module très complet et très puissant Pygame. Une introduction à la programmation avec pgzrun est donnée par Mark Vanstone dans le magazine The MagPi, entre autres dans le dossier 77, où j'ai vu sa version du pong et l'ai développée.
Je ne veux pas cacher le fait que je n'ai pas tout géré tout seul. L'affichage du score dans l'interface graphique à la fin du jeu a posé des problèmes, j'ai donc cherché de l'aide dans le forum de l'organisation Raspberry Pi. Et je l'ai eu ! Grâce à la modération, c'est le meilleur forum que je connaît, mais en anglais.
https://www.raspberrypi.org/forums/viewtopic.php?t=234306
La structure
Voici maintenant le schéma avec Raspberry Pi, MCP3008 et deux pots. Veuillez noter que le IC a besoin d'une tension d'alimentation ainsi que d'une tension de référence pour l'ADC. Dans notre cas, les deux temps sont 3,3V et GND. DOUT est connecté à MISO (broche 21), DIN à MOSI (broche 19), CLK à CLK (broche 23) et CS à CE0 (broche 24). Le comptage des entrées analogiques commence à 0.
Dans notre exemple de programme, j'utilise le MCP3004, la variante avec quatre entrées analogiques. Il s'assemble avec un Raspi-Breadboard-Cobbler sur une demi Breadboard (voir photo ci-dessus).
Je me limite dans les explications à la partie que j'ai ajoutée. Pour les explications sur le pygamezero, je renvoie au lien ci-dessus vers Les MagPi 77.
Le logiciel
En utilisant from gpiozero import MCP3004 nous importons la classe gpiozero. MCP3004, puis l'utiliser pour instancier deux objets : pot1=MCP3004(0) et pot2=MCP3004(1). Comme mentionné ci-dessus, le comptage des entrées analogiques commence à 0.
En plus de la BALLSPEED, que nous fixons initialement plus petite que dans le code original et qui augmente ensuite toutes les 60 secondes, nous définissons une fin lorsque le premier joueur a marqué 10 points, et un RESTART automatique.
Voici maintenant le code du programme dans son ensemble :
# 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()
Amusez-vous à réaliser et à jouer.
1 commentaire
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?