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.
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.