Clarification on Collision Detection and Updating Labels - python

I am trying to work on a paddle ball game that entails keeping a ball bouncing away from the bottom for as long as possible. In this game, there are five lives, which can get depleted when the ball hits the bottom of the screen, and resets itself once it has reached 0 lives. However, the ball does not bounce off of the paddle as it should, nor does the label for the score update as it ought to. The code for how I am trying to achieve the collision currently is tied to the vertical placement of the ball, the relative section of which is as follows:
if vertical_direction == "south":
top_y += dy
if top_y >= (self.canvas_height - ball_diameter) - 20:
if self.top_paddle <= top_y and self.top_paddle + 80 >= top_y:
top_y = self.canvas_height - ball_diameter
vertical_direction = "north"
elif top_y >= self.canvas_height - ball_diameter:
lives -= 1
if (lives >= 0):
top_x = 2
top_y = 2
self.canvas.delete("ball")
ball = self.canvas.create_oval(top_x, top_y, top_x + ball_diameter,
top_y + ball_diameter, fill = "blue", tags = "ball")
var.set("Lives: " +lives_Label)
else:
lives= 5
top_x = 2
top_y = 2
self.canvas.delete(ball)
ball = self.canvas.create_oval(top_x, top_y, top_x + ball_diameter,
top_y + ball_diameter, fill = "blue", tags = "ball")
I have looked at a bit of code which I found to be most similar to mine, and tried to implement its methods for detecting collision as displayed above. My only guess is there is some obvious logical inconsistency I failed to notice that is obvious to a more experienced coder, and that is the cause of both of my problems.
For reference, here is the complete code thus far:
from tkinter import *
import tkinter.font
class BallBounce (Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Bouncing Ball")
self.grid()
lives = 5
lives_Label = str(lives)
var = StringVar()
font = tkinter.font.Font(family = "Verdana", size = 20)
self._label = Label(self, font = font, textvariable = var)
var.set("Lives: "+lives_Label)
self._label.grid(row = 0, column = 0)
self.canvas_width = 800
self.canvas_height = 400
self.canvas = Canvas(self, width = self.canvas_width, height = self.canvas_height,
bg = "white")
self.canvas.grid(row = 1, column = 0)
frame = Frame(self)
frame.grid(row = 1, column = 0)
top_x = 0
top_y = 0
ball_diameter = 20
self.canvas.create_oval(top_x, top_y, ball_diameter, ball_diameter, fill = "blue", tags = "ball")
horizontal_direction = "east"
vertical_direction = "south"
self.canvas.create_rectangle (self.canvas_width / 2, self.canvas_height - 20, self.canvas_width / 2 + 80,
self.canvas_height, fill = "black", tags = "paddle")
self.top_paddle = self.canvas_width/2
self.canvas.bind("<Left>", lambda event: self.canvas.move("paddle", -5, 0))
self.canvas.bind("<Right>", lambda event: self.canvas.move("paddle", 5, 0))
self.canvas.focus_set()
dx = 2
dy = 2
while True:
if horizontal_direction == "east":
top_x += dx # dx is 2 because the ball moves 2 pixels horizontally every 15 milliseconds
if top_x >= self.canvas_width - ball_diameter: # ball has hit east wall
top_x = self.canvas_width - ball_diameter
horizontal_direction = "west" # change direction
self.canvas.move("ball", dx, 0) # move ball horizontally dx pixels to the right/east
else: # i.e., horizontal_direction is "west"
top_x -= dx
if top_x <= 0: # ball has hit west wall
top_x = 0 # you may need to adjust this a little
horizontal_direction = "east" # change direction
self.canvas.move("ball", -dx, 0) # move ball horizontally dx pixels to the left/west
if vertical_direction == "south":
top_y += dy
if top_y >= (self.canvas_height - ball_diameter) - 20:
if self.top_paddle <= top_y and self.top_paddle + 80 >= top_y:
top_y = self.canvas_height - ball_diameter
vertical_direction = "north"
elif top_y >= self.canvas_height - ball_diameter:
lives -= 1
if (lives >= 0):
top_x = 2
top_y = 2
self.canvas.delete("ball")
ball = self.canvas.create_oval(top_x, top_y, top_x + ball_diameter,
top_y + ball_diameter, fill = "blue", tags = "ball")
var.set("Lives: " +lives_Label)
else:
lives= 5
top_x = 2
top_y = 2
self.canvas.delete(ball)
ball = self.canvas.create_oval(top_x, top_y, top_x + ball_diameter,
top_y + ball_diameter, fill = "blue", tags = "ball")
self.canvas.move("ball", 0, dy)
else:
top_y -= dy
if top_y <= 0:
top_y = 0
vertical_direction = "south"
self.canvas.move("ball", 0, -dy)
self.canvas.after(15)
self.canvas.update()
def main():
BallBounce().mainloop()
main()

Related

Processing speed changes turtle animation speed

I was learning python turtle module.
And I was trying to make a simple pong game.
Here is the code:
import turtle
import win32api
wind = turtle.Screen()
wind.title("Pong game")
wind.bgcolor("black")
wind.setup(width=800, height=500)
wind.tracer(0) # stops window from updating automaticly
# racket1
racket1 = turtle.Turtle()
racket1.speed(0)
racket1.penup()
racket1.color("blue")
racket1.shape("square")
racket1.goto(-370, 0)
racket1.shapesize(stretch_wid=5, stretch_len=1)
# racket2
racket2 = turtle.Turtle()
racket2.speed(0)
racket2.penup()
racket2.color("red")
racket2.shape("square")
racket2.goto(370, 0)
racket2.shapesize(stretch_wid=5, stretch_len=1)
# ball
ball = turtle.Turtle()
ball.speed(0)
ball.penup()
ball.color("white")
ball.shape("circle")
ball.goto(0, 0)
ball.dx = 0.2
ball.dy = 0.2
# score writer
scw = turtle.Turtle()
scw.penup()
scw.speed(0)
scw.hideturtle()
scw.goto(0, 210)
scw.color("white")
scw.write("Blue: 0 Red: 0", font=("Arial", 24, "bold"), align="center")
# racket 1 functions
def racket1_up():
y = racket1.ycor()
if y < 200:
y += 0.3
racket1.sety(y)
def racket1_down():
y = racket1.ycor()
if y > -200:
y -= 0.3
racket1.sety(y)
# racket 2 functions
def racket2_up():
y = racket2.ycor()
if y < 200:
y += 0.3
racket2.sety(y)
def racket2_down():
y = racket2.ycor()
if y > -200:
y -= 0.3
racket2.sety(y)
# scores
p1 = 0
p2 = 0
while True:
wind.update()
# ball move
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
# border check
if ball.ycor() > 239: #240
ball.dy *= -1
if ball.ycor() < -239: #-240
ball.dy *= -1
if ball.xcor() > 389: #390
ball.goto(0, 0)
p1 += 1
ball.dx *= -1
scw.clear()
scw.write(f"Blue: {p1} Red: {p2}", font=("Arial", 24, "bold"), align="center")
if ball.xcor() < -389: #-390
ball.goto(0, 0)
p2 += 1
ball.dx *= -1
scw.clear()
scw.write(f"Blue: {p1} Red: {p2}", font=("Arial", 24, "bold"), align="center")
# ball and madareb collision
if ball.xcor() > 350 and ball.ycor() < racket2.ycor()+60 and ball.ycor() > racket2.ycor()-60:
ball.dx *= -1
if ball.xcor() < -350 and ball.ycor() < racket1.ycor()+60 and ball.ycor() > racket1.ycor()-60:
ball.dx *= -1
# racket 1 movement
w = win32api.GetKeyState(0x57)
s = win32api.GetKeyState(0x53)
if w < 0:
racket1_up()
if s < 0:
racket1_down()
# racket 2 movement
u = win32api.GetKeyState(0x26)
d = win32api.GetKeyState(0x28)
if u < 0:
racket2_up()
if d < 0:
racket2_down()
The game worked properly but the ball speed changes, I think that this is due to the change of the processing speed changes.
So is it possible to make the speed not change with the changing of the processing speed?

How to prevent Python Turtle from going through lines it has drawn?

I'm making a game using Turtle in Python 3.
My main problem is that the turtle can move through the "drawn" lines in the game. It's basically a randomized "flappy-bird" game, different each time you run the program.
Is it possible to prevent the Turtle from going through lines it has drawn?
The program creates both walls and holes the player should be able to get through, like flappy bird where it's a pipe-hole-pipe with different lengths on the pipes.
And if I run print(hole) at the end of the program it returns None. Why is this?
Here is my program:
import turtle
import random
GameOver=False
import math
import time
board = turtle.Screen()
board.screensize(50.50)
board.bgcolor("black")
board.title("Labyrinten")
Hast_på_ritande_av_bana= 0
TURTLE_SIZE = 20
playerspeed = 50
n=1 #variabeler som gör att den hoppar ett steg åt höger när den gör raderna t.ex. ((930/8)*n)
b=2 #
global player
#SÄTTER UPP SKÄRM
border = turtle.Turtle()
border.speed(Hast_på_ritande_av_bana)
border.hideturtle()
border.color("white")
border.shape("triangle")
border.penup()
border.goto(TURTLE_SIZE/2 - board.window_width()/2, board.window_height()/2 - TURTLE_SIZE/2)
border.pendown()
border.showturtle()
border.rt(90)
border.fd(780)
border.penup()
#ritar banan
for rader in range(4): #creating the maze
border.lt(90)
border.fd(930/8)
border.pendown()
border.lt(90)
wall_ett = border.fd(random.randint(50,630)) #lower wall on row 1
border.penup()
hole=border.fd(random.randint(30,70)) #hole on row 1
border.pendown()
wall_ett_ett = border.goto (TURTLE_SIZE/2 - board.window_width()/2 + (930/8*n), board.window_height()/2 - TURTLE_SIZE/2) #higher wall on row 1
border.rt(90)
border.fd(930/8)
border.rt(90)
wall_två_ett = border.fd(random.randint(50, 630)) #lower wall on row 2
border.penup()
hole2 = border.fd(random.randint(30, 70)) #hole on row 2
border.pendown()
wall_två_två = border.goto(TURTLE_SIZE/2 - board.window_width()/2 + (930/8*b), + TURTLE_SIZE/2 - board.window_height()/2 ) # higher wall on row 2
n = n + 2
b = b + 2
border.goto(TURTLE_SIZE/2 - board.window_width()/2 , TURTLE_SIZE/2 - board.window_height()/2 )
border.goto(TURTLE_SIZE/2 - board.window_width()/2, board.window_height()/2 - TURTLE_SIZE/2)
border.penup()
border.lt(90)
border.fd(930/8)
border.pendown()
border.goto(-TURTLE_SIZE + board.window_width()/2, board.window_height()/2 - TURTLE_SIZE/2)
border.hideturtle()
player=turtle.Turtle()
player.color("green")
player.shape("turtle")
player.hideturtle()
player.penup()
player.goto(TURTLE_SIZE/2 - board.window_width()/2, board.window_height()/2 - TURTLE_SIZE/2)
player.rt(90)
player.fd(30)
player.lt(90)
player.fd((930/8)/2)
player.rt(90)
player.showturtle()
coordinates = player.pos()
#Skapa spelaren (som går igenom banan)
def spawna_spelare():
spawn = turtle.Turtle()
spawn.color("green")
spawn.shape("turtle")
spawn.hideturtle()
spawn.penup()
spawn.goto(TURTLE_SIZE/2 - board.window_width()/2, board.window_height()/2 - TURTLE_SIZE/2)
spawn.rt(90)
spawn.fd(30)
spawn.lt(90)
spawn.fd((930/8)*(random.randint(1,8)))
spawn.rt(90)
spawn.showturtle()
#Gå med spelaren
def move_left():
x = player.xcor()
x -= playerspeed
if x < -460:
x = -460
player.setx(x)
def move_right():
x = player.xcor()
x += playerspeed
if x > 450:
x = 450
player.setx(x)
if x.distance(wall_ett) >20: #or wall_ett_ett or wall_två_ett or wall_två_två) == 1: #
player.shape("triangle")
def move_down():
y = player.ycor()
y -= playerspeed
if y < -375:
y = -375
player.sety(y)
def move_up():
y = player.ycor()
y += playerspeed
if y > 380:
y = 380
player.sety(y)
turtle.listen()
turtle.onkey(spawna_spelare, "space")
turtle.onkey(move_left, "Left")
turtle.onkey(move_right, "Right")
turtle.onkey(move_down, "Down")
turtle.onkey(move_up, "Up")
wall_ett = border.xcor()
wall_två_ett=border.xcor()
print(wall_ett)
print(wall_ett)
print(hole)
board.mainloop()
So you need to draw the walls in a way you can check afterwards if the move the player requested is crossing any wall (or border).
here is a suggestion:
SCREEN_WIDTH = 800
HOLE_HEIGHT = 50
SCREEN_HEIGHT = 600
NUM_WALLS = 8
board = turtle.Screen()
board.setup(SCREEN_WIDTH+10, SCREEN_HEIGHT+10)
board.screensize(SCREEN_WIDTH, SCREEN_HEIGHT)
board.setworldcoordinates(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
border = turtle.Turtle()
border.speed(10) # draw walls as fast as possible
border.color('white')
border.hideturtle()
# list of the drawn walls, each wall is represented by a tuple:
# (wall_x, wall_hole_lower_y, wall_hole_upper_y)
walls = []
for wall_ix in range(NUM_WALLS):
# compute coordinates of wall and store them
wall_x = int((1+wall_ix) * SCREEN_WIDTH / (1+NUM_WALLS))
wall_ybottom = random.randint(0, SCREEN_HEIGHT - HOLE_HEIGHT)
wall_ytop = wall_ybottom + HOLE_HEIGHT
walls.append((wall_x, wall_ytop, wall_ybottom))
# draw wall
border.penup()
border.goto(wall_x, 0)
border.pendown()
border.goto(wall_x, wall_ybottom)
border.penup()
border.goto(wall_x, wall_ytop)
border.pendown()
border.goto(wall_x, SCREEN_HEIGHT)
def move_right():
old_x = player.xcor()
new_x = old_x + playerspeed
y = player.ycor()
for wall_x, wall_ytop, wall_ybottom in walls:
if old_x <= wall_x <= new_x:
# player is possibly moving across the wall, check that y is valid
if wall_ybottom < y < wall_ytop:
# OK ! player moves through the hole
player.setx(new_x)
else:
# invalid, player is crossing a wall line
# resetting to old position, but you might want to stop the game
player.setx(old_x)

Collision detection for player

My code works like pong except I tried to make it 4 players. Collision between the ball and the player sort of works but it only goes towards one direction. I want to make it so that if the ball hits the top edge of the player the ball goes up and if it hit's the side of the player, the ball goes flying to that direction. Right now the ball only goes in a diagonal direction.
import turtle
import math
wn = turtle.Screen()
wn.title("PMH HANDBALL")
wn.bgcolor("Black")
wn.setup(width=800, height=600)
wn.tracer(0)
def isCollision(t1, t2):
distance = math.sqrt(math.pow(t1.xcor()-
t2.xcor(),2)+math.pow(t1.ycor()-t2.ycor(),2))
if distance < 50:
return True
else:
return False
#Handball court top right
court = turtle.Turtle()
court.speed(0)
court.color("white")
court.hideturtle()
court.goto(400, 0)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
#handball court top left
court.speed(0)
court.color("white")
court.hideturtle()
court.goto(-400, 0)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
#Handball court bottom left
court.speed(0)
court.color("white")
court.hideturtle()
court.goto(-400, -400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
#handball court bottom right
court.speed(0)
court.color("white")
court.hideturtle()
court.goto(0, -400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
court.left(90)
court.forward(400)
#handball
ball = turtle.Turtle()
ball.speed(0)
ball.shape("square")
ball.color("white")
ball.penup()
ball.goto(50, 50)
ball.dx = 2
ball.dy = -2
#player 1
player1 = turtle.Turtle()
player1.speed(0)
player1.shape("square")
player1.color("red")
player1.shapesize(stretch_wid=4, stretch_len=4)
player1.penup()
player1.goto(100, 200)
#player 2
player2 = turtle.Turtle()
player2.speed(0)
player2.shape("square")
player2.color("yellow")
player2.shapesize(stretch_wid=4, stretch_len=4)
player2.penup()
player2.goto(100, -200)
#player 3
player3 = turtle.Turtle()
player3.speed(0)
player3.shape("square")
player3.color("green")
player3.shapesize(stretch_wid=4, stretch_len=4)
player3.penup()
player3.goto(-100, 200)
#player 4
player4 = turtle.Turtle()
player4.speed(0)
player4.shape("square")
player4.color("blue")
player4.shapesize(stretch_wid=4, stretch_len=4)
player4.penup()
player4.goto(-100, -200)
#function
def player1_up():
y = player1.ycor()
y += 20
player1.sety(y)
x = player1.xcor()
x += 20
def player1_down():
y = player1.ycor()
y -= 20
player1.sety(y)
def player1_right():
x = player1.xcor()
x += 20
player1.setx(x)
def player1_left():
x = player1.xcor()
x -= 20
player1.setx(x)
def player2_up():
y = player2.ycor()
y += 20
player2.sety(y)
def player2_down():
y = player2.ycor()
y -= 20
player2.sety(y)
def player2_right():
x = player2.xcor()
x += 20
player2.setx(x)
def player2_left():
x = player2.xcor()
x += -20
player2.setx(x)
def player3_up():
y = player3.ycor()
y += 20
player3.sety(y)
x = player1.xcor()
x += 20
def player3_down():
y = player3.ycor()
y -= 20
player3.sety(y)
def player3_right():
x = player3.xcor()
x += 20
player3.setx(x)
def player3_left():
x = player3.xcor()
x -= 20
player3.setx(x)
def player4_up():
y = player4.ycor()
y += 20
player4.sety(y)
x = player4.xcor()
x += 20
def player4_down():
y = player4.ycor()
y -= 20
player4.sety(y)
def player4_right():
x = player4.xcor()
x += 20
player4.setx(x)
def player4_left():
x = player4.xcor()
x -= 20
player4.setx(x)
#keyboard bind
wn.listen()
wn.onkeypress(player1_up, "i")
wn.onkeypress(player1_down, "k")
wn.onkeypress(player1_right, "l")
wn.onkeypress(player1_left, "j")
wn.onkeypress(player2_up, "Up")
wn.onkeypress(player2_down, "Down")
wn.onkeypress(player2_right, "Right")
wn.onkeypress(player2_left, "Left")
wn.onkeypress(player3_up, "w")
wn.onkeypress(player3_down, "s")
wn.onkeypress(player3_right, "d")
wn.onkeypress(player3_left, "a")
wn.onkeypress(player4_up, "t")
wn.onkeypress(player4_down, "g")
wn.onkeypress(player4_right, "h")
wn.onkeypress(player4_left, "f")
#main loop that keeps window running
while True:
wn.update()
#boundary checking topright
if player1.xcor() > 360:
player1.goto(360, player1.ycor())
if player1.xcor() < 25:
player1.goto(40, player1.ycor())
if player1.ycor() > 360:
player1.goto(player1.xcor(), 360)
if player1.ycor() < 35:
player1.goto(player1.xcor(), 40)
#Boundary checking bottomright
if player2.xcor() > 360:
player2.goto(360, player2.ycor())
if player2.xcor() < 25:
player2.goto(40, player2.ycor())
if player2.ycor() > -40:
player2.goto(player2.xcor(), -40)
if player2.ycor() < -360:
player2.goto(player2.xcor(), -360)
#boundary checking topleft
if player3.xcor() > -40:
player3.goto(-40, player3.ycor())
if player3.xcor() < -360:
player3.goto(-360, player3.ycor())
if player3.ycor() > 360:
player3.goto(player3.xcor(), 360)
if player3.ycor() < 35:
player3.goto(player3.xcor(), 40)
#boundary checking bottomleft
if player4.xcor() > -40:
player4.goto(-40, player4.ycor())
if player4.xcor() < -360:
player4.goto(-360, player4.ycor())
if player4.ycor() > -40:
player4.goto(player4.xcor(), -40)
if player4.ycor() < -360:
player4.goto(player4.xcor(), -360)
#ball movement
ball.setx(ball.xcor() + ball.dx)
ball.sety(ball.ycor() + ball.dy)
#border checking for ball
if ball.ycor() > 420:
ball.goto(50,50)
ball.dy *= -1
if ball.ycor() < -420:
ball.goto(50,50)
ball.dy *= 1
if ball.xcor() > 420:
ball.goto(50, 50)
ball.dx *= -1
if ball.xcor() < -420:
ball.goto(50, 50)
ball.dx *= -1
#player and ball collisons
if isCollision(ball, player4):
ball.dy *= -1
ball.dx *= -1
if isCollision(ball, player3):
ball.dy *= -1
ball.dx *= -1
if isCollision(ball, player2):
ball.dy *= -1
ball.dx *= -1
if isCollision(ball, player1):
ball.dy *= -1
ball.dx *= -1
I've reworked the ball with player collision logic in your code to provide a simple, but playable bounce motion:
Far from perfect, this should give you a starting point from which to experiment. I've also rewritten your code to simplify extending it -- it's about half the size and paramerterized to the size of the screen and players:
from turtle import Screen, Turtle
from functools import partial
from random import choice
WIDTH, HEIGHT = 800, 600
CURSOR_SIZE = 20
PLAYER_SIZE = 80
def isCollision(t1, t2):
return t1.distance(t2) < (PLAYER_SIZE + CURSOR_SIZE) / 2
# Event handlers
def player_up(player):
player.sety(player.ycor() + 20)
def player_down(player):
player.sety(player.ycor() - 20)
def player_right(player):
player.setx(player.xcor() + 20)
def player_left(player):
player.setx(player.xcor() - 20)
screen = Screen()
screen.title("PMH HANDBALL")
screen.setup(WIDTH, HEIGHT)
screen.bgcolor('black')
screen.tracer(0)
# Handball court
court = Turtle()
court.hideturtle()
court.color('white')
court.width(4)
for x, y in ((0, -HEIGHT/2), (-WIDTH/2, -HEIGHT/2), (-WIDTH/2, 0), (0, 0)):
court.goto(x, y)
for _ in range(2):
court.forward(WIDTH/2)
court.left(90)
court.forward(HEIGHT/2)
court.left(90)
# Handball
ball = Turtle()
ball.shape('circle')
ball.color('white')
ball.penup()
ball.dx = 2
ball.dy = 2
ball.dx *= choice([-1, 1])
ball.dy *= choice([-1, 1])
# Player 1
player1 = Turtle()
player1.shape('square')
player1.color('red')
player1.shapesize(PLAYER_SIZE / CURSOR_SIZE)
player1.penup()
player1.goto(WIDTH/4, HEIGHT/4)
# Player 2
player2 = player1.clone()
player2.color('yellow')
player2.goto(WIDTH/4, -HEIGHT/4)
# Player 3
player3 = player1.clone()
player3.color('green')
player3.goto(-WIDTH/4, HEIGHT/4)
# Player 4
player4 = player1.clone()
player4.color('blue')
player4.goto(-WIDTH/4, -HEIGHT/4)
# Keyboard bindings
screen.onkeypress(partial(player_up, player1), 'i')
screen.onkeypress(partial(player_down, player1), 'k')
screen.onkeypress(partial(player_right, player1), 'l')
screen.onkeypress(partial(player_left, player1), 'j')
screen.onkeypress(partial(player_up, player2), 'Up')
screen.onkeypress(partial(player_down, player2), 'Down')
screen.onkeypress(partial(player_right, player2), 'Right')
screen.onkeypress(partial(player_left, player2), 'Left')
screen.onkeypress(partial(player_up, player3), 'w')
screen.onkeypress(partial(player_down, player3), 's')
screen.onkeypress(partial(player_right, player3), 'd')
screen.onkeypress(partial(player_left, player3), 'a')
screen.onkeypress(partial(player_up, player4), 't')
screen.onkeypress(partial(player_down, player4), 'g')
screen.onkeypress(partial(player_right, player4), 'h')
screen.onkeypress(partial(player_left, player4), 'f')
screen.listen()
# Main loop that keeps window running
while True:
# boundary checking top right
if player1.xcor() > WIDTH/2 - PLAYER_SIZE/2:
player1.setx(WIDTH/2 - PLAYER_SIZE/2)
elif player1.xcor() < PLAYER_SIZE/2:
player1.setx(PLAYER_SIZE/2)
if player1.ycor() > HEIGHT/2 - PLAYER_SIZE/2:
player1.sety(HEIGHT/2 - PLAYER_SIZE/2)
elif player1.ycor() < PLAYER_SIZE/2:
player1.sety(PLAYER_SIZE/2)
# boundary checking bottom right
if player2.xcor() > WIDTH/2 - PLAYER_SIZE/2:
player2.setx(WIDTH/2 - PLAYER_SIZE/2)
elif player2.xcor() < PLAYER_SIZE/2:
player2.setx(PLAYER_SIZE/2)
if player2.ycor() > -PLAYER_SIZE/2:
player2.sety(-PLAYER_SIZE/2)
elif player2.ycor() < PLAYER_SIZE/2 - HEIGHT/2:
player2.sety(PLAYER_SIZE/2 - HEIGHT/2)
# boundary checking top left
if player3.xcor() > -PLAYER_SIZE/2:
player3.setx(-PLAYER_SIZE/2)
elif player3.xcor() < PLAYER_SIZE/2 - WIDTH/2:
player3.setx(PLAYER_SIZE/2 - WIDTH/2)
if player3.ycor() > HEIGHT/2 - PLAYER_SIZE/2:
player3.sety(HEIGHT/2 - PLAYER_SIZE/2)
elif player3.ycor() < PLAYER_SIZE/2:
player3.sety(PLAYER_SIZE/2)
# boundary checking bottom left
if player4.xcor() > -PLAYER_SIZE/2:
player4.setx(-PLAYER_SIZE/2)
elif player4.xcor() < PLAYER_SIZE/2 - WIDTH/2:
player4.setx(PLAYER_SIZE/2 - WIDTH/2)
if player4.ycor() > -PLAYER_SIZE/2:
player4.sety(-PLAYER_SIZE/2)
elif player4.ycor() < PLAYER_SIZE/2 - HEIGHT/2:
player4.sety(PLAYER_SIZE/2 - HEIGHT/2)
# Ball movement
x, y = ball.position()
x += ball.dx
y += ball.dy
# Border checking for ball
if not - (WIDTH/2 + CURSOR_SIZE/2) < x < WIDTH/2 + CURSOR_SIZE/2:
ball.home()
ball.dx *= choice([-1, 1])
ball.dy *= choice([-1, 1])
continue
elif not - (HEIGHT/2 + CURSOR_SIZE/2) < y < HEIGHT/2 + CURSOR_SIZE/2:
ball.home()
ball.dx *= choice([-1, 1])
ball.dy *= choice([-1, 1])
continue
ball.setposition(x, y)
# Player and ball collisions
# Simplistic player and ball collision logic
for player in [player1, player2, player3, player4]:
if isCollision(ball, player):
p_x, p_y = player.position()
if abs(p_x - x) > abs(p_y - y):
ball.dx *= -1
else:
ball.dy *= -1
break
screen.update()

Adding obstacle generation and detection to pong game

This project is being done without pygame or other libraries that aren't built into Python 3. I have already made a pong game with a paddle and a ball moving around the screen. When the ball hits the paddle it bounces off like it normally does in any game like this. I want to generate a grid of rectangle shapes in the top middle part of the frame with the paddle and ball, and make it so when the ball hits a rectangle, the rectangle disappears. What is an effective way to do this and what would it look like, roughly speaking? Here is what I am working with currently:
from tkinter import *
import tkinter.font
import time
class Display(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Animation")
self.grid()
horizontal_direction = "east"
vertical_direction = "south"
self.canvas_width = 800
self.canvas_height = 400
self.paddle_x = 20
self.paddle_y = 80
self.left_rect_side = 360 #forposition
self.canvas = Canvas(self, width=self.canvas_width, height=self.canvas_height, bg = "white")
self.canvas.grid(row = 1, column = 0)
self.master.bind('<Left>', lambda event: self.leftKey(self))
self.master.bind('<Right>', lambda event: self.rightKey(self))
self.x = 5
self.y = 5
diameter = 20
self.canvas.create_oval(self.x, self.y, self.x + diameter, self.y + diameter, outline="#000000"
, fill="red", tags="circle")
self.canvas.create_rectangle(self.canvas_width/2 - self.paddle_y/2, self.canvas_height - self.paddle_x,
self.canvas_width/2 + self.paddle_y/2, self.canvas_height,
fill="black", tags="paddle")
fontx = tkinter.font.Font(family = "Verdana", size = 20)
self.lives = 5
self.lifedisplay = Label(self, width = -800, height = -20,
font = fontx, text = "Lives left: " + str(self.lives))
self.lifedisplay.grid(row = 0, column = 0)
mvt = 2
while True:
if self.y + diameter > self.canvas_height:
self.lives -= 1
self.lifedisplay.configure(text = "Lives left: " + str(self.lives))
if self.lives <= 0:
self.canvas.move("circle", -self.x, -self.y)
break
if self.y + diameter >= self.canvas_height - self.paddle_x:
if self.x + diameter > self.left_rect_side and self.x < self.left_rect_side + self.paddle_y:
vertical_direction = "north"
if horizontal_direction == "east":
if self.x + diameter >= self.canvas_width:
horizontal_direction = "west"
else:
self.canvas.move("circle", mvt, 0)
self.x += mvt
else:
if self.x + diameter <= diameter:
horizontal_direction = "east"
else:
self.canvas.move("circle", -mvt, 0)
self.x -= mvt
if vertical_direction == "south":
if self.y + diameter >= self.canvas_height:
vertical_direction = "north"
self.canvas.move("circle", 0, -mvt)
self.y -= mvt
else:
self.canvas.move("circle", 0, mvt)
self.y += mvt
else:
if self.y + diameter <= diameter:
vertical_direction = "south"
else:
self.canvas.move("circle", 0, -mvt)
self.y -= mvt
self.canvas.update()
self.canvas.after(15)
#staticmethod
def leftKey(self):
if self.left_rect_side >= 10:
self.canvas.move("paddle", -5, 0)
self.left_rect_side -= 5
self.canvas.update()
#staticmethod
def rightKey(self):
if self.left_rect_side <= self.canvas_width - self.paddle_y - 5:
self.canvas.move("paddle", 5, 0)
self.left_rect_side += 5
self.canvas.update()
def main():
Display().mainloop()
main()
To do this, you should make a list of a bunch of rectangle objects that have 4 attributes:
x coordinate
y coordinate
width
height
Additionally, you will have to figure out the x/y coordinate for the center of your circle. Then, each frame, have a method that checks for a collision between the circle and each rectangle. Remove the rectangle from this list of rectangles if it is hit by the circle, then only draw the rectangles from the list onto the screen.
Checking for the collision is the hardest part. I would recommend checking out this StackOverflow answer:
Circle-Rectangle collision detection (intersection)
This next article might be a little harder to understand, but check this out too:
https://yal.cc/rectangle-circle-intersection-test/
I'm not going to write the code for you (that's not what SO is for), but I hope this helped. Let me know if you need help understanding.

Tkinter GUI not opening when compiled

My python program I created doesn't seem to be opening when I click compile. The reason I am confused is because I have a .mainloop() attached to the class. Through my own testing I have deduced that it has something to do with the while loop in my code. Additionally, not sure if this helps, but when I abort the program the following appears in the console:
File "C:\Users\zach\Anaconda3\lib\tkinter\__init__.py", line 2585, in move
self.tk.call((self._w, 'move') + args)
KeyboardInterrupt
here is my completed code for:
from tkinter import *
class GUI(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Lab 8")
self.grid()
canvas_width = 800
canvas_height = 400
self.canvas = Canvas(self, width = canvas_width, height =
canvas_height, bg = "white")
self.canvas.grid()
ball_diameter = 20
top_x = 2
top_y = 2
self.canvas.create_oval(top_x, top_y, top_x + ball_diameter,
top_y + ball_diameter, fill = "black", tags = "ball")
horizontal_direction = "east"
vertical_direction = "south"
dx = 2
dy = 2
while True:
if horizontal_direction == "east":
self.canvas.move("ball", dx, 0) # move ball horizontally dx pixels to the right/east
top_x += dx # dx is 2 because the ball moves 2 pixels horizontally every 15 milliseconds
if top_x >= canvas_width - ball_diameter: # ball has hit east wall
horizontal_direction = "west" # change direction
else: # i.e., horizontal_direction is "west"
self.canvas.move("ball", -dx, 0) # move ball horizontally dx pixels to the left/west
top_x -= dx
if top_x <= 0: # ball has hit west wall
horizontal_direction = "east" # change direction
if vertical_direction == "south":
self.canvas.move("ball", 0, dy)
top_y += dy
if top_y >= canvas_height - ball_diameter:
vertical_direction = "north"
else:
self.canvas.move("ball", 0, -dy)
top_y -= dy
if top_y <= 0 :
vertical_direction = "south"
def main():
GUI().mainloop()
main()
I figured it out it was because I forgot to add the update and after methods to wait for the ball and update its position.
Your issue is that you run an infinite loop in your __init__ function. It will never reach your main loop to run the GUI. You need to let __init__ end and to call your update code, not in a tight loop but at a set time interval.
Break out the code to move the shape into a separate function, minus the infinite loop and call that function at intervals using the after method of tk widgets.
from tkinter import *
class GUI(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("Lab 8")
self.grid()
self.canvas_width = 800
self.canvas_height = 400
self.canvas = Canvas(self,
width=self.canvas_width,
height=self.canvas_height,
bg="white")
self.canvas.grid()
self.ball_diameter = 20
self.top_x = 2
self.top_y = 2
self.canvas.create_oval(self.top_x,
self.top_y,
self.top_x + self.ball_diameter,
self.top_y + self.ball_diameter,
fill = "black", tags = "ball")
self.horizontal_direction = "east"
self.vertical_direction = "south"
self.dx = 2
self.dy = 2
self.after(10, self.move)
def move(self):
if self.horizontal_direction == "east":
self.canvas.move("ball", self.dx, 0) # move ball horizontally dx pixels to the right/east
self.top_x += self.dx # dx is 2 because the ball moves 2 pixels horizontally every 15 milliseconds
if self.top_x >= self.canvas_width - self.ball_diameter: # ball has hit east wall
self.horizontal_direction = "west" # change direction
else: # i.e., horizontal_direction is "west"
self.canvas.move("ball", -self.dx, 0) # move ball horizontally dx pixels to the left/west
self.top_x -= self.dx
if self.top_x <= 0: # ball has hit west wall
self.horizontal_direction = "east" # change direction
if self.vertical_direction == "south":
self.canvas.move("ball", 0, self.dy)
self.top_y += self.dy
if self.top_y >= self.canvas_height - self.ball_diameter:
self.vertical_direction = "north"
else:
self.canvas.move("ball", 0, -self.dy)
self.top_y -= self.dy
if self.top_y <= 0 :
self.vertical_direction = "south"
self.after(10, self.move)
def main():
GUI().mainloop()
main()
Note that the number of self variables has exploded and become pretty unmanageable IMHO, which might indicate you need to break out some of those values into other classes.
But fundamentally this runs. It ain't pretty, but you can work on that next.

Categories