Bernd54Albrecht
Posts: 27
Joined: Tue Jun 16, 2015 6:35 pm

Pong reloaded // MagPi77 //pygamezero

Sat Feb 23, 2019 9:15 am

Pong is an excellent example for using MCP3004/3008 as well as for pygamezero. We like that "old" game from 1972.
However, there is always room for improvement. My pupils wanted to change the BALLSPEED and have a winner, when a certain score is reached. Therefore, we amended the code as attached. BALLSPEED is initially 3 (versus 5) and gets faster every 60 seconds. No problem.
And we included an if-statement, whether p1Score or p2Score has reached END (for test purposes =3, later =10). We included a print-statement that gives the correct result in the shell. However, here comes our problem: the score on the game board is not updated to the final score, although the print-out in the shell is correct. Why do the statements in line 40 an 48 do not work?

attached the modified code and a photo of our home-made paddles with 10k-potentiometers.
Pong_Paddles1024.jpg
Pong_Paddles1024.jpg (115.03 KiB) Viewed 2489 times

Code: Select all

# pong game
# source MagPi 77, pages 32 - 35
# modified by Raspberry Pi course at JFS Bad Bramstedt, Germany

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

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

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

def draw():
    global screen
    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)
    winner()       

def winner():           #new
    global screen, p1Score, p2Score, BALLSPEED, TIME
    if p2Score==END:
        print("p1 = ",p1Score,"p2 = ",p2Score)
        print("Winner is Player2")
        screen.draw.tex[attachment=0]Pong_Paddles1024.jpg[/attachment]t(str(p2Score) , center=(705, 40), color=WHITE, fontsize=60)   # ???
        BALLSPEED = 0
        sleep(RESTART)
        p1Score = p2Score = 0
        BALLSPEED = 3
    if p1Score==END:
        print("p1 = ",p1Score,"p2 = ",p2Score)
        print("inner is Player1")
        screen.draw.text(str(p1Score), center=(105, 40), color=WHITE, fontsize=60)    # ???
        BALLSPEED = 0
        sleep(RESTART)
        p1Score = p2Score = 0
        BALLSPEED = 3

def update():
    updatePaddles()
    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()


User avatar
lucyhattersley
Posts: 26
Joined: Tue Aug 04, 2015 5:05 pm

Re: Pong reloaded // MagPi77 //pygamezero

Tue Feb 26, 2019 9:34 am

Typo on line 40.

Code: Select all

screen.draw.tex[attachment=0]Pong_Paddles1024.jpg[/attachment]t(str(p2Score) , center=(705, 40), color=WHITE, fontsize=60)   # ???
Should be:

Code: Select all

screen.draw.text[attachment=0]Pong_Paddles1024.jpg[/attachment]t(str(p2Score) , center=(705, 40), color=WHITE, fontsize=60)   # ???
(Edit: There's some other stuff as well. Try to read your code line-by-line. I find it helps to read from back to front one line at a time).

Bernd54Albrecht
Posts: 27
Joined: Tue Jun 16, 2015 6:35 pm

Re: Pong reloaded // MagPi77 //pygamezero

Tue Feb 26, 2019 10:08 am

Thanks for the reply.
However, my problem is not the missing t in text. This word was divided by the first attempt to attach a photo, which was placed in the middle of the code. So, this part must be deleted.

Bernd54Albrecht
Posts: 27
Joined: Tue Jun 16, 2015 6:35 pm

Re: Pong reloaded // MagPi77 //pygamezero

Tue Feb 26, 2019 10:10 am

Correction:

Code: Select all

# pong game
# source MagPi 77, pages 32 - 35
# modified by Raspberry Pi course at JFS Bad Bramstedt, Germany

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

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

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

def draw():
    global screen
    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)
    winner()       

def winner():           #new
    global screen, p1Score, p2Score, BALLSPEED, TIME
    if p2Score==END:
        print("p1 = ",p1Score,"p2 = ",p2Score)
        print("Winner is Player2")
        screen.draw.text(str(p2Score) , center=(705, 40), color=WHITE, fontsize=60)   # ???
        BALLSPEED = 0
        sleep(RESTART)
        p1Score = p2Score = 0
        BALLSPEED = 3
    if p1Score==END:
        print("p1 = ",p1Score,"p2 = ",p2Score)
        print("inner is Player1")
        screen.draw.text(str(p1Score), center=(105, 40), color=WHITE, fontsize=60)    # ???
        BALLSPEED = 0
        sleep(RESTART)
        p1Score = p2Score = 0
        BALLSPEED = 3

def update():
    updatePaddles()
    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()

User avatar
lucyhattersley
Posts: 26
Joined: Tue Aug 04, 2015 5:05 pm

Re: Pong reloaded // MagPi77 //pygamezero

Tue Feb 26, 2019 10:50 am

Ah, it's a logic error then.

I haven't fixed it but is related to the screen.draw.text nested inside winner(). This function is not being called. It seems to be repeating the score update in the draw() function so the winner() function should return to that function() (rather than trying to update the text itself).

You are also repeating the setup variables twice inside the winner() function definition. Maybe take the setup code and place it inside a separate function definition) and call this when the player has won (and call this after the draw() function has updated the score).

Maybe open it up in Thonny and use the Debug mode and step through and see where the variables and logic end up?

Bernd54Albrecht
Posts: 27
Joined: Tue Jun 16, 2015 6:35 pm

Re: Pong reloaded // MagPi77 //pygamezero

Tue Feb 26, 2019 12:50 pm

I replaced the screen.draw.text statement with the full function draw. No joy!
I ran the debugger in Thonny -> error message, see attached screen shot.
Thonny  -  -home-pi-PyGameZero-pong_gettingFaster.py  @  132 - 1_001.png
Thonny - -home-pi-PyGameZero-pong_gettingFaster.py @ 132 - 1_001.png (117.18 KiB) Viewed 2379 times
pgzrun obviously does not support the debugger.

The missing link to the above is the update function in pygamezero. In Pygame the display is deliberately updated at the end of all computations, in pygamezero the update is presumably at the beginning of the next round of the game. The draw.text statement is therefore prepared, but not executed, I guess.

Thanks for the support, Lucy, I will leave it as is.

MarkyV
Posts: 97
Joined: Wed Sep 21, 2016 1:52 pm
Location: Buckingham, UK
Contact: Website

Re: Pong reloaded // MagPi77 //pygamezero

Wed Feb 27, 2019 11:09 am

Hi - glad you are having fun with the pong game :) - I think I know why you are not seeing what you are expecting: When you call the winner() function whilst the scores are printed out to the console (which is updated outside the Pygame Zero draw cycle) The scores that you are drawing to the screen at that point are not seen because you are calling the sleep() function. Sleep halts all program activity so the draw cycle will not complete until it is released by sleep() - after the restart delay.

What you need to do is detect the endgame state in the draw() function and do your end game draw there - you could have a countdown to restart in the update() function or you could have the user press a key like the space bar - I have some example code below (just the sections you need to change to do a restart with the spacebar):

Code: Select all

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("P2 Wins!" , center=(400, 30), color=WHITE, fontsize=60)
    if p1Score==END:
        screen.draw.text("P1 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()
        
        
Hope that helps :D

Mark
My RaspberryPi Blog: http://thepimaker.online

Bernd54Albrecht
Posts: 27
Joined: Tue Jun 16, 2015 6:35 pm

Re: Pong reloaded // MagPi77 //pygamezero

Wed Feb 27, 2019 4:21 pm

That was it! Many thanks to Mark.

Attached the revised code:

Code: Select all

# pong game
# source MagPi 77, pages 32 - 35
# modified by Raspberry Pi course at JFS Bad Bramstedt, Germany
# with the decisive contribution by MarkyV
# also thanks to Lucy Hattersley
# 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          # neu

pot1 = MCP3004(0)            # change to MCP3008, if using 8-channel ADC
pot2 = MCP3004(1)            # change to MCP3008, if using 8-channel ADC

# 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 initially 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()



Return to “The MagPi”