pythonvariablesgame-developmentincrement

Variable in Python going up by more than 1 at a time


I am currently making a project for my school for fun, and I came across a problem. The project is a paddle and ball game, and every time the ball hits the paddle the score SHOULD go up by one, but instead it increments by 3, and sometimes 2. I have thought of manually incrementing with another variable and a constant check, but I think there is another better solution. Here is the code:

#----- IMPORTS --------
import time
import math

app.score = Label('0', 200, 50, size=25)

ball = Group(
Circle(200, 200, 17, fill=rgb(130, 130, 130), border='black', borderWidth=7)  
)

paddle = Group(
Circle(170, 375, 18, fill=rgb(130, 130, 130), border='black', borderWidth=10),
Circle(240, 375, 18, fill=rgb(130, 130, 130), border='black', borderWidth=10),
Line(170, 362, 240, 362, lineWidth=10),
Line(170, 388, 240, 388, lineWidth=10),
Rect(170, 366.5, 70, 17, fill=rgb(130, 130, 130))
)

app.press = False
app.sec = time.time()
app.xvel = 0
app.yvel = 0
app.paddle_xvel = 0
app.mousex = 0
app.mousey = 0
app.scoreVar = 0

app.ballx = 0
app.bally = 0
app.padx = 0
app.pady = 0

def onMouseMove(mouseX, mouseY):
app.mousex = mouseX
app.mousey = mouseY

def onMousePress(mouseX, mouseY):
app.press = True

def onMouseRelease(mouseX, mouseY):
app.press = False

def _init_():
ball.visible = False
paddle.visible = False
app.background = 'skyblue'
app.score.visible = False

_init_()

playBtn = Group(
Circle(140, 210, 30, fill=rgb(150, 225, 170), border='black', borderWidth=10),
Circle(260, 210, 30, fill=rgb(150, 225, 170), border='black', borderWidth=10),
Rect(140, 190, 120, 40, fill=rgb(150, 225, 170)),
Line(140, 185, 260, 185, lineWidth=10),
Line(140, 235, 260, 235, lineWidth=10),
Label('P l a y', 200, 210, size=30, bold=False, font='montserrat')
)

def onStep():
app.sec = time.time()
#----- Ball physics ------
ball.centerY += app.yvel
ball.centerX += app.xvel
app.yvel += 1
app.ballx = ball.centerX
app.bally = ball.centerY
app.padx = paddle.centerX
app.pady = paddle.centerY - 20

    paddle.rotateAngle = (app.paddle_xvel / 2)
    if app.mousex > paddle.centerX:
        app.paddle_xvel += 3
    if app.mousex < paddle.centerX:
        app.paddle_xvel += -3
    app.paddle_xvel = app.paddle_xvel / 1.2
    paddle.centerX += app.paddle_xvel
    
    if app.yvel < -20:
        app.yvel = -20
    if ball.centerX > 390:
        app.xvel = -5
    if ball.centerX < 10:
        app.xvel = 5
    if ball.centerY >= 400:
        ball.centerY = 200
        app.yvel = 0
        app.xvel = 0
        ball.centerX = 200
    
    #---- HIT CHECK -------
    
    for shape in paddle:
        if ball.hitsShape(shape) == True:
            app.yvel = -20
            app.xvel = app.paddle_xvel
            app.scoreVar += 1
            app.score.value = app.scoreVar
        
    
    #----- Ball physics explanation ------
    
    # First, we set the ball's y velocity (the speed that it goes down by exponentially). 
    # Then, we make it so that the Y and X values are CHANGED by, not set to, the velocities.
    # Next we do a few checks, like if the ball is touching the wall, if it is touching 
    # the ground, and we reset it. If it touches the wall we just bounce it the opposite way.
    # The ball's terminal velocity is -20, which is the max speed the ball can get to.'''
    
    #---- Play btn physics
    playBtn.rotateAngle = math.sin((((app.sec*2)+100) * 2) + 100)
    playBtn.centerX = math.sin(app.sec*2.5) * 3 + 200
    
    if playBtn.contains(app.mousex, app.mousey):
        if app.press == True:
            paddle.visible = True
            ball.visible = True
            app.background = 'white'
            playBtn.visible = False
            app.score.visible = True

lastTime = app.sec
app.sec -= lastTime

Note that this code is in CMU CS academy, so forever loops like while true loops are impossible, you can't nest loops, and you can't define the same function twice. The docs are VERY useful: https://academy.cs.cmu.edu/docs. You might have to click on the docs/colors tab to get it open. My problem is with the "app.scoreVar += 1, app.score.value = app.scoreVar" These lines of code make it so that the Label of the score changes by "1" but instead it changes by 2 or 3 based on the speed of your paddle. I can't use time.sleep() because it freezes the whole game instead of only the respective scope.


Solution

  • The culprit is here:

    for shape in paddle:
        if ball.hitsShape(shape) == True:
            app.yvel = -20
            app.xvel = app.paddle_xvel
            app.scoreVar += 1
            app.score.value = app.scoreVar
    

    Probably, if the inner if statement is True, you should just break out of the for loop.

    for shape in paddle:
        if ball.hitsShape(shape) == True:
            app.yvel = -20
            app.xvel = app.paddle_xvel
            app.scoreVar += 1
            app.score.value = app.scoreVar
            break
    

    Otherwise, if the ball hits multiple shapes, the score will go up by more than 1.