Game made with Python turtle graphics - python

I made a simple table wall tennis,having trouble bouncing back the ball while still allowing it to change direction after going past the paddle. https://github.com/eliud-luda/table-pong.git

Your question is a little vague. Here is a ping pong program which might help:
import turtle
wn = turtle.Screen()
wn.title("Ping pong")
wn.bgcolor("blue")
wn.setup(width=900, height=600)
wn.tracer(0)
class PaddleFirst():
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("square")
self.pen.shapesize(stretch_wid=5, stretch_len=1)
self.pen.penup()
self.pen.goto(-350, 0)
def up(self):
y = self.pen.ycor()
y += 20
self.pen.sety(y)
def down(self):
y = self.pen.ycor()
y -= 20
self.pen.sety(y)
class PaddleSecond():
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("square")
self.pen.shapesize(stretch_wid=5, stretch_len=1)
self.pen.penup()
self.pen.goto(350, 0)
def up(self):
y = self.pen.ycor()
y += 20
self.pen.sety(y)
def down(self):
y = self.pen.ycor()
y -= 20
self.pen.sety(y)
class Ball():
def __init__(self):
self.pen = turtle.Turtle()
self.pen.penup()
self.pen.speed(0)
self.pen.shape("circle")
self.pen.color("Red")
self.pen.penup()
self.pen.goto(0, 0)
self.pen.dx = 00.7
self.pen.dy = 00.7
def letsgo(self):
self.pen.setx(self.pen.xcor() + self.pen.dx)
self.pen.sety(self.pen.ycor() + self.pen.dy)
def move(self):
if self.pen.ycor() > 290:
self.pen.sety(290)
self.pen.dy *= -1
if self.pen.ycor() < -290:
self.pen.sety(-290)
self.pen.dy *= -1
if self.pen.xcor() > 390:
self.pen.goto(0, 0)
self.pen.dx *= -1
if self.pen.xcor() < -390:
self.pen.goto(0, 0)
self.pen.dx *= -1
class Wall():
def moving(self):
if ball.pen.xcor() > 340 and (ball.pen.ycor() < paddle2.pen.ycor() + 40 and ball.pen.ycor() > paddle2.pen.ycor() - 40):
ball.pen.dx *= -1
if ball.pen.xcor() < -340 and (ball.pen.ycor() < paddle1.pen.ycor() + 40 and ball.pen.ycor() > paddle1.pen.ycor() - 40):
ball.pen.dx *= -1
paddle1 = PaddleFirst()
print(paddle1)
paddle2 = PaddleSecond()
print(paddle2)
ball = Ball()
print(ball)
wall = Wall()
wn.listen()
wn.onkeypress(paddle1.up, "w")
wn.onkeypress(paddle1.down, "s")
wn.onkeypress(paddle2.up, "Up")
wn.onkeypress(paddle2.down, "Down")
while True:
wn.update()
ball.letsgo()
ball.move()
wall.moving()

Related

How to display the inscription and pause the game in Ping Pong with pgzrun in Python

My code
`
import pgzero.music
import pgzrun
import pygame
import time
from pgzero.actor import Actor
WIDTH = 600
HEIGHT = 700
RED = 200, 0, 0
Darkviolet = 104, 34, 139
COLOR1 = 71,60,139
WHITE = (255, 255, 255)
BOX = Rect((20, 100), (100,10))
RADIUS = 13
ball_speed_x = -3
ball_speed_y = 3
hearts = [Actor("heart", (20, 20)), Actor("heart", (55, 20)), Actor("heart", (90, 20))]
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add(self, other):
return Vector(self.x + other.x, 0)
def __sub__(self, other):
return Vector(self.x - other.x, 0)
class Paddle:
def __init__(self, l, h, s1, s2):
self.position = [l, h]
self.size = s1, s2
def draw(self):
screen.draw.filled_rect(Rect(self.position, self.size), RED)
my_paddle = Paddle(200, 600, 100, 20)
class Rectangle:
def __init__(self,x, y, w, h):
self.x = x
self.y = y
self.h = h
self.w = w
def draw(self):
rect = Rect(self.x, self.y, self.h, self.w)
screen.draw.filled_rect(rect, "blue")
rectangles = []
rectan_count = 0
x = 30
y = 50
while rectan_count < 18:
rectangles.append(Rectangle(x, y, 20, 50))
rectan_count += 1
x += 80
if rectan_count == 7:
y += 30
x = 70
elif rectan_count == 13:
y += 30
x = 110
class Ball:
def __init__(self, x, y):
self.position = Vector(x, y)
def draw(self):
screen.draw.filled_circle((self.position.x, self.position.y), RADIUS, "darkviolet")
def update(self):
pass
ball = Ball(300, 300)
def draw():
global ball_speed_x, ball_speed_y
screen.clear()
my_paddle.draw()
ball.draw()
if hearts:
for heart in hearts:
heart.draw()
for rectangle in rectangles:
if (rectangle.x <= ball.position.x <= (rectangle.x + rectangle.w)) and (rectangle.y <= ball.position.y <= (rectangle.y + rectangle.h)):
ball_speed_y *= -1
rectangles.remove(rectangle)
rectangle.draw()
else:
screen.draw.text("Sorry, you lose!!", (150, 200), color="blue", fontsize=50)
quit()
def on_mouse_move(pos):
x = pos[0]
my_paddle.position[0] = x
def update_ball(dt, paddle_x, paddle_y):
global ball_speed_x, ball_speed_y
ball.position.x -= ball_speed_x
ball.position.y -= ball_speed_y
if (ball.position.x >= WIDTH) or (ball.position.x <= 0):
ball_speed_x *= -1
if (ball.position.y >= HEIGHT) or (ball.position.y <= 0):
ball_speed_y *= -1
if ((paddle_x + 100) >= ball.position.x >= paddle_x) and (paddle_y <= ball.position.y):
ball_speed_y *= -1
if ball.position.y >= HEIGHT:
ball.position.x = WIDTH // 2
ball.position.y = HEIGHT // 2
if hearts:
hearts.pop()
ball_speed_y += 1
def update(dt):
update_ball(dt, my_paddle.position[0], my_paddle.position[1])
pgzrun.go()`
I'm doing ping pong on pgzrun and I don't understand exactly how to make lose and win labels and have the game pause and the ball stop and then restart it again. And I still don't understand how to make rectangular barriers that my ball can bounce off. Many thanks in advance for your help!!

Slow python turtle program

I was trying to make this snake game (no food yet) by using turtle. At length of 1 it still fast but as it goes longer it runs slower and slower.
from turtle import Turtle, Screen
SIZE = 500
GRID_NUM = 20
GRID_SIZE = SIZE // GRID_NUM
screen = Screen()
screen.setup(SIZE, SIZE)
screen.bgcolor('black')
screen.setworldcoordinates(10, 8, SIZE + 2, SIZE)
class Snake:
def __init__(self):
self.head = init_turtle()
self.head.setpos((GRID_SIZE // 2 + GRID_SIZE * 9, GRID_SIZE // 2 + GRID_SIZE * 10))
self.body = []
self.direction = 0 # 0 = left, 1 = up, 2 = right, 3 = down
self.speed = 100 * len(self.body) if len(self.body) > 0 else 100
def levelup(self):
if len(self.body) == 0:
self.body.append(self.head.clone())
else:
self.body.append(self.body[len(self.body) - 1].clone())
def update(self):
for i in range(len(self.body) - 1, -1 , -1):
if i == 0:
self.body[i].setpos(self.head.pos())
else:
self.body[i].setpos(self.body[i - 1].pos())
def init_turtle():
turtle = Turtle()
turtle.shape('square')
turtle.shapesize(1.25)
turtle.color('red')
turtle.pencolor('#404040')
turtle.speed('fastest')
turtle.up()
return turtle
def init_border():
def border():
turtle = init_turtle()
for _ in range(4):
turtle.down()
turtle.forward(SIZE)
turtle.left(90)
yield(0)
turtle.penup()
turtle.hideturtle()
def horizontal():
turtle = init_turtle()
for x in range(GRID_SIZE, SIZE, GRID_SIZE):
turtle.goto(x, 0)
turtle.pendown()
turtle.goto(x, SIZE)
turtle.penup()
yield(0)
turtle.hideturtle()
def vertical():
turtle = init_turtle()
for y in range(GRID_SIZE, SIZE, GRID_SIZE):
turtle.goto(0, y)
turtle.pendown()
turtle.goto(SIZE, y)
turtle.penup()
yield(0)
turtle.hideturtle()
generator1 = border()
generator2 = horizontal()
generator3 = vertical()
while(next(generator1, 1) + next(generator2, 1) + next(generator3, 1) < 3):
pass
def start_game():
snake = Snake()
def pop():
snake.body.pop()
def right():
snake.direction = 0
def up():
snake.direction = 1
def left():
snake.direction = 2
def down():
snake.direction = 3
def exit():
screen.bye()
screen.onkey(pop, 'q')
screen.onkey(left, 'Left')
screen.onkey(up, 'Up')
screen.onkey(right, 'Right')
screen.onkey(down, 'Down')
screen.onkey(exit, 'Escape')
screen.onkey(snake.levelup, 'Return')
screen.listen()
while True:
snake.update()
snake.head.setheading(snake.direction * 90)
snake.head.forward(GRID_SIZE)
print('snake', snake.head.pos())
init_border()
start_game()
screen.mainloop()
At first i think the cause of the problem was defines a lot of function but i don't know. Also i am new to python so i don't know any kind of optimizing methods.
Any ideas to optimize this program?
We can speed up long snakes by doing the drawing off screen and sending explicit updates. Below is a rework of your code that does just that and includes a temporary patch to make the snake move in a square so you can just hit to see how much the snake is affected by additional body segments:
from turtle import Turtle, Screen
SIZE = 525
GRID_NUM = 20
GRID_SIZE = SIZE // GRID_NUM
RIGHT, UP, LEFT, DOWN = range(4)
class Snake:
def __init__(self):
self.head = init_turtle()
self.head.setpos(GRID_NUM//2, GRID_NUM//2)
self.direction = LEFT
self.body = []
def levelup(self):
if self.body:
self.body.append(self.body[-1].clone())
else:
self.body.append(self.head.clone())
def update(self):
for i in range(len(self.body) - 1, -1, -1):
if i == 0:
self.body[i].setposition(self.head.position())
else:
self.body[i].setposition(self.body[i - 1].position())
def init_turtle():
turtle = Turtle()
turtle.shape('square')
print(GRID_SIZE)
turtle.shapesize((GRID_SIZE - 1) / 20)
turtle.color('#404040', 'red')
turtle.speed('fastest')
turtle.penup()
return turtle
def init_border():
def border():
turtle = init_turtle()
turtle.goto(-0.5, -0.5)
for _ in range(4):
turtle.pendown()
turtle.forward(GRID_NUM)
turtle.left(90)
turtle.penup()
turtle.hideturtle()
def vertical():
turtle = init_turtle()
for x in range(GRID_NUM):
turtle.goto(x - 0.5, -0.5)
turtle.pendown()
turtle.goto(x - 0.5, GRID_NUM - 0.5)
turtle.penup()
yield 0
turtle.hideturtle()
def horizontal():
turtle = init_turtle()
for y in range(GRID_NUM):
turtle.goto(-0.5, y + 0.5)
turtle.pendown()
turtle.goto(GRID_NUM - 0.5, y + 0.5)
turtle.penup()
yield 0
turtle.hideturtle()
border()
generator1 = horizontal()
generator2 = vertical()
while next(generator1, 1) + next(generator2, 1) < 2:
pass
def start_game():
snake = Snake()
def right():
snake.direction = RIGHT
def up():
snake.direction = UP
def left():
snake.direction = LEFT
def down():
snake.direction = DOWN
screen.onkey(snake.body.pop, 'q')
screen.onkey(left, 'Left')
screen.onkey(up, 'Up')
screen.onkey(right, 'Right')
screen.onkey(down, 'Down')
screen.onkey(screen.bye, 'Escape')
screen.onkey(snake.levelup, 'Return')
screen.listen()
while True:
snake.update()
snake.head.setheading(snake.direction * 90)
snake.head.forward(1)
# Run snake around in a square for testing purposes
x, y = snake.head.position()
if round(x) == 1 and snake.direction == LEFT:
up()
elif round(y) == GRID_NUM - 2 and snake.direction == UP:
right()
elif round(x) == GRID_NUM - 2 and snake.direction == RIGHT:
down()
elif round(y) == 1 and snake.direction == DOWN:
left()
screen.update()
screen = Screen()
screen.setup(SIZE, SIZE)
screen.bgcolor('black')
screen.setworldcoordinates(-0.75, -0.75, GRID_NUM + 0.25, GRID_NUM + 0.25)
init_border()
screen.tracer(False)
start_game()
screen.mainloop() # never reached!
I'd recommend both approaches as the main loop will only get more complicated (slower) as you add food and border detection.
I changed your coordinate system to make it snake centric. That is, forward(1) moves one square on the grid rather than having to do the math. If you're going to mess with the coordinates anyway, why not tweak them to your best advantage.

How to limit the amount of times a button is pressed

I am trying to make a game where you can shoot bullets to kill emojis. However, i can't manage to figure out how to stop spamming the space key to shoot bullets. If you keep on spamming, the game would be too easy. I am not exactly sure if what command I should use. Please help! thanks!
Here is my code:
# import everything from turtle
from turtle import *
import random
import math
#create a link to the object (creates the environment)
screen = Screen()
speed1 = 1.3
ht()
amountOfEmojis = 11
#set a boundary for screen, if touches end, goes to the other side
screenMinX = -screen.window_width()/2
screenMinY = -screen.window_height()/2
screenMaxX = screen.window_width()/2
screenMaxY = screen.window_height()/2
#establish important data for screen environment
screen.setworldcoordinates(screenMinX,screenMinY,screenMaxX,screenMaxY)
screen.bgcolor("black")
#turtle setup
penup()
ht()
speed(0)
goto(0, screenMaxY - 50)
color('white')
write("Welcome to Emoji Run!", align="center", font=("Courier New",26))
goto(0, screenMaxY - 70)
write("Use the arrow keys to move and space to fire. The point of the game is to kill the emojis", align="center")
goto(0, 0)
color("red")
emojis = ["Poop_Emoji_7b204f05-eec6-4496-91b1-351acc03d2c7_grande.png", "1200px-Noto_Emoji_KitKat_263a.svg.png",
"annoyningface.png", "Emoji_Icon_-_Sunglasses_cool_emoji_large.png"]
class Bullet(Turtle):
#constructor, object for a class, pass in information
def __init__(self,screen,x,y,heading):
#create a bullet
Turtle.__init__(self)#clones bullet
self.speed(0)
self.penup()
self.goto(x,y)
self.seth(heading)#pointing to itself
self.screen = screen
self.color('yellow')
self.max_distance = 500
self.distance = 0
self.delta = 20
self.shape("bullet")
#logic to move bullet
def move(self):
self.distance = self.distance + self.delta#how fast it's going to move
self.forward(self.delta)
if self.done():
self.reset()
def getRadius(self):
return 4#collision detection helper function
def blowUp(self):
self.goto(-300,0)#function that makes something go off the screen
def done(self):
return self.distance >= self.max_distance # append to list
class Asteroid(Turtle):
def __init__(self,screen,dx,dy,x,y,size,emoji):#spawn asteroid randomly
Turtle.__init__(self)#clone itself
self.speed(0)
self.penup()
self.goto(x,y)
self.color('lightgrey')
self.size = size
self.screen = screen
self.dx = dx
self.dy = dy
r = random.randint(0, len(emoji) - 1)
screen.addshape(emojis[r])
self.shape(emojis[r])
#self.shape("rock" + str(size)) #sets size and shape for asteroid
def getSize(self):#part of collision detection
return self.size
#getter and setter functions
def getDX(self):
return self.dx
def getDY(self):
return self.dy
def setDX(self,dx):
self.dx = dx
def setDY(self,dy):
self.dy = dy
def move(self):
x = self.xcor()
y = self.ycor()
#if on edge of screen. go to opposite side
x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY
self.goto(x,y)
def blowUp(self):
self.goto(-300,0)#function that makes something go off the screen
def getRadius(self):
return self.size * 10 - 5
class SpaceShip(Turtle):
def __init__(self,screen,dx,dy,x,y):
Turtle.__init__(self)
self.speed(0)
self.penup()
self.color("white")
self.goto(x,y)
self.dx = dx
self.dy = dy
self.screen = screen
self.bullets = []
self.shape("turtle")
def move(self):
x = self.xcor()
y = self.ycor()
x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY
self.goto(x,y)
#logic for collision
def powPow(self, asteroids):
dasBullets = []
for bullet in self.bullets:
bullet.move()
hit = False
for asteroid in asteroids:
if intersect(asteroid, bullet):#counts every asteroid to see if it hits
asteroids.remove(asteroid)
asteroid.blowUp()
bullet.blowUp()
hit = True
if (not bullet.done() and not hit):
dasBullets.append(bullet)
self.bullets = dasBullets
def fireBullet(self):
self.bullets.append(Bullet(self.screen, self.xcor(), self.ycor(), self.heading()))
def fireEngine(self):#how turtle moves
angle = self.heading()
x = math.cos(math.radians(angle))
y = math.sin(math.radians(angle))
self.dx = self.dx + x#how it rotates
self.dy = self.dy + y
self.dx = self.dx / speed1
self.dy = self.dy / speed1
#extra function
def turnTowards(self,x,y):
if x < self.xcor():
self.left(7)
if x > self.xcor():
self.right(7)
def getRadius(self):
return 10
def getDX(self):
return self.dx
def getDY(self):
return self.dy
#collision detection
def intersect(object1,object2):
dist = math.sqrt((object1.xcor() - object2.xcor())**2 + (object1.ycor() - object2.ycor())**2)
radius1 = object1.getRadius()
radius2 = object2.getRadius()
# The following if statement could be written as
# return dist <= radius1+radius2
if dist <= radius1+radius2:
return True
else:
return False
#adds object to screen
screen.register_shape("rock3",((-20, -16),(-21, 0), (-20,18),(0,27),(17,15),(25,0),(16,-15),(0,-21)))
screen.register_shape("rock2",((-15, -10),(-16, 0), (-13,12),(0,19),(12,10),(20,0),(12,-10),(0,-13)))
screen.register_shape("rock1",((-10,-5),(-12,0),(-8,8),(0,13),(8,6),(14,0),(12,0),(8,-6),(0,-7)))
screen.register_shape("ship",((-10,-10),(0,-5),(10,-10),(0,10)))
screen.register_shape("bullet",((-2,-4),(-2,4),(2,4),(2,-4)))
#ship spawn exactly the middle everytime
ship = SpaceShip(screen,0,0,(screenMaxX-screenMinX)/2+screenMinX,(screenMaxY-screenMinY)/2 + screenMinY)
#randomize where they spawn
asteroids = []
for k in range(amountOfEmojis):
dx = random.random() * 6 - 3
dy = random.random() * 6 - 3
x = random.randrange(10) * (screenMaxX - screenMinX) + screenMinX
y = random.random() * (screenMaxY - screenMinY) + screenMinY
asteroid = Asteroid(screen,dx,dy,x,y,random.randint(1,3), emojis)
asteroids.append(asteroid)
def play():
# Tell all the elements of the game to move
ship.move()
gameover = False
for asteroid in asteroids:
r = random.randint(0, 1)
if r == 1:
asteroid.right(50)
else:
asteroid.left(20)
asteroid.move()
if intersect(ship,asteroid):
write("You Got Killed :(",font=("Verdana",25),align="center")
gameover = True
ship.powPow(asteroids)
screen.update()
if not asteroids:
color('green')
write("You Killed the Emojis!!",font=("Arial",30),align="center")
ht()
if not gameover:
screen.ontimer(play, 30)
bullets = []
#controls
def turnLeft():
ship.left(7)
def turnRight():
ship.right(7)
def go():
ship.fireEngine()
def fire():
ship.fireBullet()
ht()
screen.tracer(0);
screen.onkey(turnLeft, 'left')
screen.onkey(turnRight, 'right')
screen.onkey(go, 'up')
screen.onkey(fire, 'space')
screen.listen()
play()
You can use a threaded timer to prevent the method to be called everytime you click the button, and just two attributes in your SpaceShip class.
Everytime the method fireBullet is called, a check is made on the variable can_shoot. If it's true, the bullet is spawned like you did and then a timer runs (with a thread, for not blocking the main flow) that just put can_shoot to False, sleep for any amount of ms you want, and then put can_shoot to True and the method is callable again.
import time
import threading
def __init__(self):
# your stuff
self.wait_between_fire = 300 / 1000 # amount of ms / 1000 to convert in seconds
self.can_shoot = True
class TimerThread(threading.Thread):
def __init__(self, ref):
threading.Thread.__init__(self)
self.ref = ref
def run():
self.ref.can_shoot = False
time.sleep(ref.wait_between_fire)
self.ref.can_shoot = True
def set_timer(self):
TimerThread(self).start()
def fireBullet(self):
if self.can_shoot:
self.bullets.append(Bullet(self.screen, self.xcor(), self.ycor(), self.heading()))
self.set_timer()
We don't need to introduce time nor threading to solve this. We can use turtle's own timer events to control the rate of fire:
def fire():
screen.onkey(None, 'space')
ship.fireBullet()
screen.ontimer(lambda: screen.onkey(fire, 'space'), 250)
Here I've limited the rate of fire to 4 rounds per second. (250 / 1000 milliseconds.) Adjust as you see fit. Below is a rework of your program with this modification as well as other fixes and style tweaks:
from turtle import Screen, Turtle
from random import random, randint, randrange, choice
from math import radians, sin as sine, cos as cosine
class Bullet(Turtle):
MAX_DISTANCE = 500
DELTA = 20
RADIUS = 4
def __init__(self, position, heading):
super().__init__(shape="bullet")
self.hideturtle()
self.penup()
self.goto(position)
self.setheading(heading)
self.color('yellow')
self.showturtle()
self.distance = 0
def move(self):
self.distance += self.DELTA
self.forward(self.DELTA)
if self.done():
self.reset()
def getRadius(self):
''' collision detection helper method '''
return self.RADIUS
def blowUp(self):
''' method that makes something go off the screen '''
self.hideturtle()
def done(self):
return self.distance >= self.MAX_DISTANCE
class Asteroid(Turtle):
def __init__(self, dx, dy, position, size, emoji):
super().__init__()
self.hideturtle()
self.penup()
self.goto(position)
self.color('lightgrey')
emoji = choice(emojis)
# screen.addshape(emoji) # for StackOverflow debugging
self.shape(emoji)
self.showturtle()
self.size = size
self.dx = dx
self.dy = dy
def move(self):
x, y = self.position()
# if on edge of screen. go to opposite side
x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY
self.goto(x, y)
def blowUp(self):
''' method that makes something go off the screen '''
self.hideturtle()
def getRadius(self):
return self.size * 10 - 5
class SpaceShip(Turtle):
RADIUS = 10
def __init__(self, screen, dx, dy, x, y):
super().__init__(shape='turtle')
self.hideturtle()
self.penup()
self.color("white")
self.goto(x, y)
self.showturtle()
self.dx = dx
self.dy = dy
self.screen = screen
self.bullets = []
def move(self):
x, y = self.position()
x = (self.dx + x - screenMinX) % (screenMaxX - screenMinX) + screenMinX
y = (self.dy + y - screenMinY) % (screenMaxY - screenMinY) + screenMinY
self.goto(x, y)
def powPow(self, asteroids):
''' logic for collision '''
dasBullets = []
for bullet in self.bullets:
bullet.move()
hit = False
for asteroid in asteroids:
if intersect(asteroid, bullet): # counts every asteroid to see if it hits
asteroids.remove(asteroid)
asteroid.blowUp()
hit = True
if not bullet.done() and not hit:
dasBullets.append(bullet)
else:
bullet.blowUp()
self.bullets = dasBullets
def fireBullet(self):
bullet = Bullet(self.position(), self.heading())
self.bullets.append(bullet)
def fireEngine(self):
angle = self.heading() # how turtle moves
x = cosine(radians(angle))
y = sine(radians(angle))
self.dx = self.dx + x # how it rotates
self.dy = self.dy + y
self.dx = self.dx / speed1
self.dy = self.dy / speed1
def getRadius(self):
return self.RADIUS
def turnLeft(self):
self.left(7)
def turnRight(self):
self.right(7)
def intersect(object1, object2):
''' collision detection '''
return object1.distance(object2) <= object1.getRadius() + object2.getRadius()
def play():
# Tell all the elements of the game to move
ship.move()
gameover = False
for asteroid in asteroids:
r = randint(0, 1)
if r == 1:
asteroid.right(50)
else:
asteroid.left(20)
asteroid.move()
if intersect(ship, asteroid):
turtle.write("You Got Killed :(", font=("Verdana", 25), align="center")
gameover = True
ship.powPow(asteroids)
screen.update()
if not asteroids:
turtle.color('green')
turtle.write("You Killed the Emojis!!", font=("Arial", 30), align="center")
if not gameover:
screen.ontimer(play, 30)
# controls
def fire():
screen.onkey(None, 'space')
ship.fireBullet()
screen.ontimer(lambda: screen.onkey(fire, 'space'), 250)
# create a link to the object (creates the environment)
speed1 = 1.3
amountOfEmojis = 11
# establish important data for screen environment
screen = Screen()
screen.bgcolor("black")
# set a boundary for screen, if touches end, goes to the other side
screenMinX = -screen.window_width()/2
screenMinY = -screen.window_height()/2
screenMaxX = screen.window_width()/2
screenMaxY = screen.window_height()/2
screen.setworldcoordinates(screenMinX, screenMinY, screenMaxX, screenMaxY)
# adds object to screen
screen.register_shape("rock3", ((-20, -16), (-21, 0), (-20, 18), (0, 27), (17, 15), (25, 0), (16, -15), (0, -21)))
screen.register_shape("rock2", ((-15, -10), (-16, 0), (-13, 12), (0, 19), (12, 10), (20, 0), (12, -10), (0, -13)))
screen.register_shape("rock1", ((-10, -5), (-12, 0), (-8, 8), (0, 13), (8, 6), (14, 0), (12, 0), (8, -6), (0, -7)))
screen.register_shape("ship", ((-10, -10), (0, -5), (10, -10), (0, 10)))
screen.register_shape("bullet", ((-2, -4), (-2, 4), (2, 4), (2, -4)))
screen.tracer(0)
# turtle setup
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
turtle.goto(0, screenMaxY - 50)
turtle.color('white')
turtle.write("Welcome to Emoji Run!", align="center", font=("Courier New", 26))
turtle.goto(0, screenMaxY - 70)
turtle.write("Use the arrow keys to move, and space to fire. The point of the game is to kill the emojis.", align="center", font=("Courier New", 13))
turtle.goto(0, 0)
turtle.color("red")
emojis = [
"Poop_Emoji_7b204f05-eec6-4496-91b1-351acc03d2c7_grande.png",
"1200px-Noto_Emoji_KitKat_263a.svg.png",
"annoyningface.png",
"Emoji_Icon_-_Sunglasses_cool_emoji_large.png"
]
emojis = ['rock1', 'rock2', 'rock3'] # for StackOverflow debugging purposes
# ship spawn exactly the middle everytime
ship = SpaceShip(screen, 0, 0, (screenMaxX - screenMinX)/2 + screenMinX, (screenMaxY - screenMinY)/2 + screenMinY)
# randomize where they spawn
asteroids = []
for k in range(amountOfEmojis):
dx, dy = random() * 6 - 3, random() * 6 - 3
x = randrange(10) * (screenMaxX - screenMinX) + screenMinX
y = random() * (screenMaxY - screenMinY) + screenMinY
asteroid = Asteroid(dx, dy, (x, y), randint(1, 3), emojis)
asteroids.append(asteroid)
screen.onkey(ship.turnLeft, 'Left')
screen.onkey(ship.turnRight, 'Right')
screen.onkey(ship.fireEngine, 'Up')
screen.onkey(fire, 'space')
screen.listen()
screen.update()
play()
screen.mainloop()
Something to consider is that turtles are global entities that don't get garbage collected. So, you might want to collect your spent bullets in a list to reuse, only creating new ones when you need them.

Ball bounce in pong

I have written some code but can't get the ball to bounce on the floor or the ceiling naturally. Please help!
I've already tried getting the ball heading with ball_heading = ball.heading, but that didn't work
#Python 3.6.3
from turtle import *
import math
import random
#Screen Setup
bgcolor("black")
wn = Screen()
wn.title("Pong")
#Drawing Border
bd = Turtle()
bd.pencolor("white")
bd.pensize(3)
bd.hideturtle()
bd.penup()
bd.setposition(-400, -300)
bd.pendown()
bd.speed(0)
bd.pendown()
for line in range(2):
bd.forward(800)
bd.left(90)
bd.forward(600)
bd.left(90)
bd.penup()
bd.setposition(0, 300)
bd.setheading(270)
bd.pendown()
for dash in range(30):
bd.forward(10)
bd.penup()
bd.forward(10)
bd.pendown()
#Creating Paddles
#Paddle 1
player1 = Turtle()
player1.color("white")
player1.shape("square")
player1.shapesize(stretch_wid=5, stretch_len=1)
player1.penup()
player1.setposition(-370, 0)
#Paddle 2
player2 = Turtle()
player2.color("white")
player2.shape("square")
player2.shapesize(stretch_wid=5, stretch_len=1)
player2.penup()
player2.setposition(370, 0)
#Creating the ball
ball = Turtle()
ball.color("white")
ball.shape("square")
ball.speed(0)
ball.penup()
ball.setposition(0, 0)
ball.setheading(random.randint(0, 360))
#Moving the player
playerspeed = 15
#p1
def move_up():
y = player1.ycor()
y += playerspeed
#Setting the boundries
if y > 245:
y = 245
player1.sety(y)
def move_down():
y = player1.ycor()
y -= playerspeed
#Setting the boundries
if y < -245:
y = -245
player1.sety(y)
#p2
def move_up2():
y = player2.ycor()
y += playerspeed
#Setting the boundries
if y > 245:
y = 245
player2.sety(y)
def move_down2():
y = player2.ycor()
y -= playerspeed
#Setting the boundries
if y < -245:
y = -245
player2.sety(y)
#Ball movement
def ball_fd():
ball.forward(3)
#Ball ceiling / floor bounce
def ball_bounce():
by = ball.ycor()
if by > 279:
by = 279
ball.sety(by)
bx = ball.ycor()
if bx < -279:
bx = -279
ball.setx(bx)
#binding
listen()
onkey(move_up, "Up")
onkey(move_down, "Down")
onkey(move_up2, "w")
onkey(move_down2, "s")
#Making the ball move / main game loop
while True:
ball_fd()
ball_bounce()
Sorry the code is kind of long, but feel free to copy + paste it into IDLE or whatever.
Thank you
You didn't turn the ball when it hit the floor or ceiling.
while True:
ball.fd(3)
by = ball.ycor()
if abs(by) > 279:
ball.setheading(-ball.heading())

Trying to make a ball object bounce off a paddle

I'm new to python and am working on a final project for my intro to python class. I have the majority of a paddle ball game done, but can't figure out how to make the ball object bounce off of my paddle object.
I've looked on Stackoverflow for a while and have spent a few hours trying to figure it out on my own without any success. If anyone has any ideas I could really use the help.
If there's anything I need to explain better in order for you to get a better understanding please just comment.
GUI FILE:
Import tkinter, random, particle, and helpers
from tkinter import *
from ball import *
from paddle import *
from time import *
class PaddleBall:
def __init__(self, window):
''' Construct the paddle ball GUI '''
self.window = window
self.window.protocol('WM_DELETE_WINDOW', self.safe_exit)
self.width = 700
self.height = 900
self.canvas = Canvas(self.window, bg='black', width=self.width, height=self.height, highlightthickness=0)
self.canvas.bind_all("<KeyPress-Left>", self.move_left)
self.canvas.bind_all("<KeyPress-Right>", self.move_right)
self.canvas.pack()
# Create a label to indicate instructions
instructions = Label(window, text="Controls: Left & Right Arrow Keys")
instructions.pack(side=BOTTOM, expand=YES)
# Create a button to clear Ball
restart_button = Button(window, text="Play", command=self.reset)
restart_button.pack(side=BOTTOM, expand=YES)
self.ball = Ball(350, 350)
self.paddle = Paddle(300, 850, 400, 860, 0, 0)
self.terminated = False
self.render()
def ballobject(self):
self.ball = Ball(350, 350)
self.paddle = Paddle(300, 850, 400, 860, 0, 0)
self.render()
def reset(self):
self.terminated = True
def safe_exit(self):
''' Turn off the event loop before closing the GUI '''
self.terminated = True
self.window.destroy()
# Render everything
def render(self):
# While program is not terminated
if not self.terminated:
# Erase Canvas
self.canvas.delete(ALL)
# Move ball
self.ball.move(self.canvas, self.paddle)
# Render ball
self.ball.render(self.canvas)
# Render paddle
self.paddle.render(self.canvas)
# use distance() to detect collision between ball and paddle.
'''Ball.bounce(self)'''
# Animate the particles movement
self.canvas.after(10, self.render)
else:
# Erase Canvas
self.canvas.delete(ALL)
self.terminated = False
self.canvas.after(50, self.ballobject)
def move_left(self, event):
self.paddle.move_left(event)
def move_right(self, event):
self.paddle.move_right(event)
if __name__ == '__main__':
root = Tk()
root.option_add('*font', ('Verdana', 12, 'bold italic')) # Found at http://effbot.org/tkinterbook/tkinter-widget-styling.htm
root.resizable(0,0) # Found at https://mail.python.org/pipermail/tutor/2001-September/008504.html
root.title('Paddle Ball')
root.wm_attributes("-topmost", -1)
app = PaddleBall(root)
root.mainloop()
BALL CLASS FILE:
class Ball:
'''
Ball models a single ball that may be rendered to a canvas
'''
def __init__(self, x, y, radius = 15,):
'''
Constructor
'''
self._x = x
self._y = y
self._velX = randint(-10,10)
self._velY = randint(-10,-5)
self._radius = radius
self._color = 'white'
self._tx = 350
self._ty = 400
self._t = ""
self._tfill = "red"
self._tfont = ("Arial", 35, "bold italic")
# This method renders the ball
def render(self, canvas):
canvas.create_oval(self._x - self._radius, self._y - self._radius, self._x + self._radius, self._y + self._radius, fill = self._color)
canvas.create_text(self._tx, self._ty, text = self._t, fill = self._tfill, font = self._tfont)
# This method moves the ball
def move(self, canvas, Paddle):
# Update Position
self._x += self._velX
self._y += self._velY
# If the ball hits any of the wall negate the velocity
if (self._x + self._radius > canvas.winfo_reqwidth() and self._velX > 0) or (self._x - self._radius < 0 and self._velX < 0):
self._velX = -self._velX
if (self._y + self._radius < 0 and self._velY < 0):
self._velY = -self._velY
if (self._y + self._radius > canvas.winfo_reqheight() and self._velY > 0):
self._velY = 0
self._velX = 0
self._t = " GAME OVER! \n Click the play button to play again."
#*****THIS IS WHAT I'M HAVING TROUBLE WITH******
# Determine if the ball hits the paddle
if ((self._x + self._radius > Paddle._x(self) and self._velX > 0) or (self._x + self._radius < Paddle._x2(self))) and (self._y < Paddle._y(self)):
self._velX = -self._velX
PADDLE CLASS FILE:
# Import math and helpers
from tkinter import *
import math
from gui import *
class Paddle:
def __init__(self, x, y, x2, y2, velX, velY):
'''
Constructor
'''
self._x = x
self._y = y
self._x2 = x2
self._y2 = y2
self._velX = velX
self._velY = velY
self._color = 'white'
def getpadx(self):
return self._x
def getpady(self):
return self._y
def getpadx1(self):
return self._x2
def getpady2(self):
return self._y2
# This method renders the paddle
def render(self, canvas):
canvas.create_rectangle(self._x, self._y, self._x2, self._y2, fill = self._color)
# This method moves the paddle
def move(self, canvas):
# Update Position
# If the paddle hits any of the wall negate the velocity
if (self._x + self._radius > canvas.winfo_reqwidth() and self._velX > 0) or (self._x - self._radius < 0 and self._velX < 0):
self._velX = -self._velX
def move_left(self, event):
self._x -= 35
self._x2 -= 35
def move_right(self, event):
self._x += 35
self._x2 += 35
I figured it out with the help of a friend. All I had to do was change this code:
From this:
if ((self._x + self._radius > Paddle._x(self) and self._velX > 0) or (self._x + self._radius < Paddle._x2(self))) and (self._y < Paddle._y(self)):
self._velX = -self._velX
To this:
`if (self._x > Paddle._x) and (self._x < Paddle._x2):
if (self._y + self._radius > Paddle._y):
self._velY = -self._velY
self._velX = self._velX + randint(-2,2)`

Categories