I have recently redid an earlier version of my version of Pong. However, I am having a slight issue with it. Whenever the ball hits the opposing paddle and then hits the bottom, the ball travels along the bottom until the player paddle hits it. I have tried for days to fix it but it seems I cannot on my own. Any help would be greatly appreciated.
I was going to implement vectors into but I still am not good with them so..
This is a font module, for easy changing of fonts. It is used below so I will include it here
import pygame
import random
from pygame.font import Font as Rfont
import pygame.gfxdraw
pygame.init()
def randcolor():
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
print (c1, c2, c3)
return (c1, c2, c3)
def randcoor(x, y):
co1 = random.randint(0, x)
co2 = random.randint(0, y)
return (co1, co2)
class Font(Rfont):
def __init__(self, name, size):
self.font = Rfont(name, size)
self.name_of_font = name
def get_name(self):
return self.name_of_font
def render(self, text, i, color):
return self.font.render(text, i, color).convert()
def get_height(self):
return self.font.get_height()
def get_width(self):
return self.font.get_width()
def get_size(self):
return (self.font.get_width(), self.font.get_height())
class Text(object):
def __init__(self, text, fonts=[pygame.font.get_default_font()], sizes=[20], main=(pygame.font.get_default_font(), 20),
color=(0, 0, 0)):
self.fonts = {}
for w, i in enumerate(fonts):
self.fonts[i] = {}
self.fonts[i][sizes[w]] = Font(i, sizes[w])
self.current_font = self.fonts[main[0]][main[1]]
self.text = self.current_font.render(text, 0, color)
self.color = color
self.words = text
def change_text(self, new):
self.text = self.current_font.render(new, 0, self.color)
self.words = new
def change_font(self, new, size=20):
if self.fonts.has_key(new):
if self.fonts[new].has_key(size):
self.current_font = self.fonts[new][size]
self.text = self.current_font.render(self.words, 0, self.color)
else:
self.change_size(size, new)
else:
self.add_font(new, size)
self.current_font = self.fonts[new][size]
self.text = self.current_font.render(self.words, 0, self.color)
def change_size(self, size, font=1):
if font != 1 and self.fonts.has_key(font):
self.fonts[font][size] = Font(font, size)
self.current_font = self.fonts[font][size]
self.text = self.current_font.render(self.words, 0, self.color)
elif font == 1:
self.fonts[self.current_font.get_name()][size] = Font(self.current_font.get_name(), size)
self.current_font = self.fonts[self.current_font.get_name()][size]
self.text = self.current_font.render(self.words, 0, self.color)
def change_color(self, color):
self.color = color
self.text = self.current_font.render(self.words, 0, self.color)
def add_font(self, font, size):
self.fonts[font][size] = Font(font, size)
def render(self):
return self.text
def get_width(self):
return self.text.get_width()
def get_height(self):
return self.text.get_height()
def get_size(self):
return self.text.get_size()
from __future__ import division
import random
import os
from Text import Text
import pygame
import pygame.gfxdraw as Drawing
from imputwrapper import Input
from pygame.locals import *
pygame.init()
pygame.mixer.init()
os.environ['SDL_VIDEO_CENTERED'] = '1'
### End imports ###
### System kernal info ###
__Name__ = 'Pong'
__Created__ = 'August 25, 2010'
__Version__ = 0.95 + .1
__Updated__ = 'August 31, 2010'
__ToDo__ = 'Fix bug when ball hits ball of screen'
### End System kernal ###
### Sound check ###
sound = raw_input('Sound? ') # Ask for sound
if sound.lower() not in 'yes yeah y yup' or not pygame.mixer.get_init():
print 'Sound is disabled.'
sound = False
else:
sound = True
### End sound check ###
### Class definitions ###
class MyException(Exception):
'''Exception to handle small problems'''
def __init__(self, message = None):
self.message = message
def __str__(self):
return repr(self.message)
class Music(object):
def __init__(self, list_of_tracks):
self.list_of_tracks = {}
for i in list_of_tracks:
self.list_of_tracks[i] = pygame.mixer.Sound(i)
self.current = None
def play(self, song):
if song in self.list_of_tracks:
self.list_of_tracks[song].play()
self.current = song
else:
raise MyException, 'No such music avaible'
def stop(self):
if self.current:
self.list_of_tracks[self.current].stop()
self.current = None
def set_nick(self, name, nick):
self.list_of_tracks[nick] = self.list_of_tracks[name]
del self.list_of_tracks[name]
class Pobject(object):
def revert(self):
'''Changes the image back to the original size'''
# Get the x and y value
coor = (self.position[0], self.position[1])
# Return the image to normal
self.image = pygame.transform.smoothscale(self.image, self.size)
# Get the new rect
self.rect = self.image.get_rect()
# Set the rect to same co-ordinates
self.position[0] = coor[0]
self.position[1] = coor[1]
def scale(self, scale):
'''Changes the image another size'''
# Get the x and y value
coor = (self.position[0], self.position[1])
# Change the size of the image
self.image = pygame.transform.smoothscale(self.image, scale)
# Get the new rect
self.rect = self.image.get_rect()
# Set the rect to same co-ordinates
self.position[0] = coor[0]
self.position[1] = coor[1]
def draw(self, screen):
'''Draws the object onto the screen'''
screen.blit(self.image, self.rect)
class Paddle(Pobject):
'''A class for the both the player and the opponent.'''
def __init__(self, size, place, image=None, color=(255, 255, 255)):
'''The construtor. Sets boundries, images converted, rects set.'''
if image:
# Loads the image
ima = pygame.image.load(image).convert_alpha()
self.image = pygame.transform.smoothscale(ima, size)
else:
# Creates a surface if there isn't an image
self.image = pygame.surface.Surface(size).convert()
self.image.fill(color)
# Sets the original size
self.size = size
# Set the position and the rect
self.rect = self.image.get_rect()
self.rect.topleft = place
# Set the speed
self.speed = 0
def update(self, move, disp, bottomrect):
'''Updates the paddles y value'''
# Moves the rect
self.rect.y += move
# Change speed
if move > 0 and self.speed < 1:
self.speed += move / 10
elif not move:
self.speed = 0
# Checks if movement is with-in bounds
if self.rect.colliderect(disp.rect):
self.rect.y = disp.rect.bottom
elif self.rect.colliderect(bottomrect):
self.rect.bottom = bottomrect.top
class Ball(Pobject):
'''Creates a new ball'''
def __init__(self, size, place, image=None, radius=None, color=(255, 255, 255),
screencolor=(0, 0, 0)):
'''Constructor. Sets the boundries, the rect, and the image'''
if image:
# Loads the image
ima = pygame.image.load(image).convert_alpha()
self.image = pygame.transform.smoothscale(ima, size)
else:
# Creates a surface
if not radius:
radius = (size[0]/6)*2
self.image = pygame.surface.Surface(size)
self.image.fill(screencolor)
Drawing.filled_circle(self.image, int(size[0]/3), int(size[1]/3), int(radius), color)
# Set the size
self.size = size
# Get the rect and set the place
self.rect = self.image.get_rect()
self.rect.topleft = place
# Set the angle
self.random_place()
# Set up touch
self.touch = False
# Set up speed
self.speed = 1.0
self.xspeed = 1.0
# Make table for angling
self.table = {
0:[5, 0],
5:[5, -.5],
10:[5, -1],
15:[5, -1.5],
20:[5, -2],
25:[5, -2.5],
30:[5, -3],
35:[5, -3.5],
40:[5, -4],
45:[4.5, -4.5],
50:[4, -5],
55:[3.5, -5],
60:[3, -5],
65:[2.5, -5],
70:[2, -5],
75:[1.5, -5],
80:[1, -5],
85:[.5, -5],
90:[0, -5],
360:[5, 0],
355:[5, .5],
350:[5, 1],
345:[5, 1.5],
340:[5, 2],
335:[5, 2.5],
330:[5, 3],
325:[5, 3.5],
320:[5, 4],
315:[4.5, 4.5],
310:[4, 5],
305:[3.5, 5],
300:[3, 5],
295:[2.5, 5],
290:[2, 5],
285:[1.5, 5],
280:[1, 5],
275:[.5, 5],
270:[0, 5],
180:[-5, 0],
185:[-5, .5],
190:[-5, 1],
195:[-5, 1.5],
200:[-5, 2],
205:[-5, 2.5],
210:[-5, 3],
215:[-5, 3.5],
220:[-5, 4],
225:[-4.5, 4.5],
230:[-4, 5],
235:[-3.5, 5],
240:[-3, 5],
245:[-2.5, 5],
250:[-2, 5],
255:[-1.5, 5],
260:[-1, 5],
265:[-.5, 5],
175:[-5, -.5],
170:[-5, -1],
165:[-5, -1.5],
160:[-5, -2],
155:[-5, -2.5],
150:[-5, -3],
145:[-5, -3.5],
140:[-5, -4],
135:[-4.5, -4.5],
130:[-4, -5],
125:[-3.5, -5],
120:[-3, -5],
115:[-2.5, -5],
110:[-2, -5],
105:[-1.5, -5],
100:[-1, -5],
95:[-.5, -5],
}
def random_place(self):
'''Place the ball in a random angle'''
self.angle = random.randint(1, 359)
def aup(self):
'''Checks the angle'''
if self.angle in [90, 180, 270, 360, 0]:
self.angle += random.choice([1, -1])
def tup(self, p1, p2):
'''Checks if ball isnt touching paddles'''
if self.touch and not (self.rect.colliderect(p1) or self.rect.colliderect(p2)):
self.touch = False
def speed_check(self):
'''Checks the speed of the ball and sets reduction values'''
if self.speed > 1.0:
self.speed -= .05
if self.speed < 1.0:
self.speed = 1.0
elif self.speed < 1.0:
self.speed = 1.05
if self.xspeed > 1.0:
self.xspeed -= .05
if self.xspeed < 1.0:
self.xspeed = 1.0
elif self.xspeed < 1.0:
self.xspeed = 1.05
def table_return(self):
'''Get positioning from table'''
if self.table.has_key(self.angle):
return self.table[self.angle]
else:
for i in range(5):
if self.table.has_key(self.angle+i):
return self.table[self.angle+i]
def update(self, speed, player1, player2, disp, bottomrect):
'''Updates the balls position'''
# Check the angles
self.aup()
# Check for touch
self.tup(player1, player2)
t = self.table_return()
# Moves the x value according to the direction
if self.angle <= 90 or self.angle >= 270:
self.rect.x += self.xspeed * speed #+ (t[0]/5)
else:
self.rect.x -= self.xspeed * speed# + (t[0]/5)
# Moves the y value according to the speed
if self.angle < 180:
self.rect.y -= self.speed + (t[1]/5)
else:
self.rect.y += self.speed + (t[1]/5)
# Check speed
self.speed_check()
# Check the angles
self.aup()
# Checks for collisions
return self.check(player1, player2, disp, bottomrect)
def check(self, p1, p2, disp, bottomrect):
'''Checks for collisions'''
collide = False
# If the ball is moving right
if (self.angle <= 90 or self.angle >= 270) and self.rect.colliderect(p2.rect):
# If it isn't already touching the paddle
if not self.touch:
collide = True
self.touch = True
self.angle += 180 if self.angle <= 180 else -180
# Change the speed
if self.around(p2):
self.speed += .6
self.xspeed += self.xspeed * p2.speed
elif self.around(p2, 'bottomright'):
self.speed += .6
self.xspeed += self.xspeed * p2.speed
elif self.around(p2, (p2.rect.center[0]+(p2.rect.width/2), p2.rect.center[1]), 10, True):
self.speed = 1
self.xspeed = 1
else:
self.speed += .1
self.xspeed += p2.speed
# If ball is moving left
elif (self.angle <= 270 and self.angle >= 90) and self.rect.colliderect(p1.rect):
# If it isn't already touching the paddle
if not self.touch:
collide = True
self.angle += 180 if self.angle <= 180 else -180
self.touch = True
# Change the speed
if self.around(p1):
self.speed += .6
self.xspeed += self.xspeed * p1.speed
elif self.around(p1, 'bottomright'):
self.speed += .6
self.xspeed += self.xspeed * p1.speed
elif self.around(p1, (p1.rect.center[0]+(p1.rect.width/2), p1.rect.center[1]), 10, True):
self.speed = 1
self.xspeed = 1
else:
self.speed += .1
self.xspeed += p1.speed
# If it is touching the top
if self.rect.colliderect(disp.rect):
if self.rect.y <= 90 and self.rect.y > 0:
self.angle = 360 - self.angle
elif self.rect.y >= 90 and self.rect.y <= 180:
self.angle += 90
self.speed += .05
# If it is touching the bottom
if self.rect.colliderect(bottomrect):
if self.angle <= 360 and self.angle >= 270:
self.angle = 360 - self.angle
elif self.angle >= 180 and self.angle <= 270:
self.angle -= 90
self.speed += .05
return collide
def around(self, pad, point='topright', divide=5, p=False):
'''Checks if ball is around a certain point'''
if not p:
po = eval('pad.rect.%s'%point)
else:
po = point
x = po[1] / divide
for i in range(int(po[1]-x), int(po[1]+x)):
if self.rect.collidepoint((po[0], i)):
return True
return False
class Power(Pobject):
def __init__(self, size, upperbound, lowerbound, left, right, image, target={'1.5 scale':['player']},
power=['1.5 scale'], ptime=200, stime=200):
'''The construtor. Sets boundries, images converted, rects set.'''
# Loads the image
ima = pygame.image.load(image).convert_alpha()
self.image = pygame.transform.smoothscale(ima, size)
# Sets the original size
self.size = size
# Get the rect
self.rect = self.image.get_rect()
# Set the bounds
self.upper = upperbound
self.lower = lowerbound
self.left = left
self.right = right
# Set the times
self.stime = stime
self.ptime = ptime
self.screen = True
# Set powers and targets
self.powers = power
self.targets = target
def update(self, player, opponent, ball):
if self.screen:
self.stime -= 1
self.check_ball(player, opponent, ball)
if not self.stime:
return 'delete'
else:
self.ptime -= 1
if not self.ptime:
self.stop(player, opponent, ball)
return 'delete'
return 'stay'
def draw(self, screen):
'''Draw the power up to the screen'''
if self.screen:
screen.blit(self.image, self.rect)
def place(self, screen):
'''Place the power up on the screen'''
self.rect.x = random.randint(self.upper, self.lower)
self.rect.y = random.randint(self.left, self.right)
self.draw(screen)
def check_ball(self, p1, p2, ball):
if ball.rect.colliderect(self.rect):
self.run(p1, p2, ball)
def run(self, p1, p2, ball):
for pow in self.powers:
pow1 = pow.split()
for t in self.targets[pow]:
if 'scale' == pow1[1]:
if t == 'player':
p1.scale(int(pow1[0]))
elif t == 'opponent':
p2.scale(int(pow1[0]))
elif t == 'ball':
ball.scale(int(pow1[0]))
def stop(self, p1, p2, ball):
p1.revert()
p2.revert()
ball.revert()
class Display(Pobject):
'''Class for display of points and such'''
def __init__(self, size, ssize, place, name1, name2, color1, color2, image=None, bcolor=(0, 0, 0)):
'''Constructor. Sets the names and background and scores up.'''
if image:
# Loads the image
ima = pygame.image.load(image)
self.image = pygame.transform.smoothscale(ima, size)
else:
# Create a surface for the background
self.image = pygame.surface.Surface(size)
self.image.fill(bcolor)
# Set the size
self.size = size
# Get the rect
self.rect = self.image.get_rect()
self.rect.x = place[0]
self.rect.y = place[1]
# Set name and scores
self.name1 = Text(name1, color=color1)
self.name2 = Text(name2, color=color2)
self.score = [0, 0]
self.score1 = Text('0', color=color1)
self.score2 = Text('0', color=color2)
# Set up the draw positions
self.places = {}
self.places['name1'] = place
self.places['name2'] = (ssize[0]-self.name2.get_width()-10, place[1])
self.places['score1'] = (ssize[0]/2-20, place[1])
self.places['score2'] = (ssize[0]/2+20, place[1])
def update(self, score1, score2):
'''Update the scores'''
self.score[0] += score1
self.score[1] += score2
self.score1.change_text(str(self.score[0]))
self.score2.change_text(str(self.score[1]))
def change_name(self, n1, n2):
'''Change the names of the players'''
self.name1.change_text(n1)
self.name2.change_text(n2)
def draw(self, screen):
'''Draw the Display'''
# Draw the background
screen.blit(self.image, self.rect)
# Draw the names
screen.blit(self.name1.render(), self.places['name1'])
screen.blit(self.name2.render(), self.places['name2'])
# Draw the scores
screen.blit(self.score1.render(), self.places['score1'])
screen.blit(self.score2.render(), self.places['score2'])
class AI(object):
'''Class that decides where AI paddle will move'''
def __init__(self, main='Normal', levels={'Easy':[3, 4, 5, 4, 3], 'Normal':[2, 3, 4, 3, 2], 'Hard':[3, 2, 1, 2, 3, 2, 3]}):
'''Constructor. Sets the level'''
self.levels = levels
self.main = main
self.level = levels[main]
def update(self, frame, ball, p):
'''Updates the paddle'''
if random.choice(self.level) <= 100:#frame:
if ball.angle >= 180 and ball.angle <= 360 or p.rect.y <= ball.rect.y:
# If ball is moving downward
return 1
elif ball.angle <= 180 and ball.angle >= 0 or p.rect.y >= ball.rect.y:
# If ball is moving upward
return -1
return 0
### End class definitions ###
### Global definitions ###
def draw_all(screen, background, player, ball, opp, disp, power):
'''Draws all the items onto the screen'''
screen.blit(background, (0, 0))
disp.draw(screen)
player.draw(screen)
ball.draw(screen)
opp.draw(screen)
if power:
power.draw(screen)
def main(size, limit, name, chance=10, pows=True, image=(20, 20, 50), sound=True):
'''Sets up and plays the game'''
# Creates the screen
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Pong %s'%__Version__)
icon = pygame.surface.Surface((40, 40))
icon.fill((0, 0, 0))
icon.set_alpha(255)
pygame.display.set_icon(icon)
bottomrect = pygame.rect.Rect(0, size[1], size[0], 1)
# Create/load background image
if isinstance(image, tuple):
background = pygame.surface.Surface(size).convert()
background.fill(image)
else:
background = pygame.image.load(image).convert()
# Creates the player
player = Paddle((20, 50), [10, size[1]/2])
# Creates the opponent and the AI
opp = Paddle((20, 50), [size[0]-30, size[1]/2])
ai = AI('Hard')
# Creates the ball
ball = Ball((30, 30), [300, 250], screencolor=image)
# Create the display
disp = Display((size[0], 20), size, (0, 0), name, '%s Opponent'%ai.main, (0, 0, 200), (200, 0, 0))
# Create power ups
if pows:
powers = [((40, 40), size[1]-10, disp.image.get_height(), 40, size[0]-50, 'pow1.png')]
else:
powers = ''
power = ''
pow = 'Stay'
# Create the clock for frame rate control
clock = pygame.time.Clock()
# Set up player variables
move = 0
# Set up opponent variables
omove = 0
# Set up AI variables
frame = 0
# Set up frame rate check
low = 1000
high = 0
# Check for the game to be done
run = 1
# Create the sound effects
if sound:
music = Music(['score.wav', 'collide.wav'])
music.set_nick('score.wav', 'score')
music.set_nick('collide.wav', 'collide')
# Start the loop
while run:
# Tick the clock
clock.tick(limit)
# Check the frame rate
current_fps = int(clock.get_fps())
if current_fps < low and current_fps > 10:
low = current_fps
if current_fps > high:
high = current_fps
# Update AI variable
frame += 1
# Get keys
Input.add_events(pygame.event.get())
# Check for exit
if Input.isset(pygame.QUIT) or Input.down(pygame.K_ESCAPE):
run = 0
# Check for player movement
# If up
if Input.down(pygame.K_UP):
move += -1
# If down
elif Input.down(pygame.K_DOWN):
move += 1
# Create a new power up:
if not power and powers and random.randint(0, 100) >= chance:
#p = random.choice(powers)
#power = Power(p[0], p[1], p[2], p[3], p[4], p[5])
#power.place(screen)
#del p
pass
if pow == 'Delete':
power = ''
pow = 'Stay'
# Update everything
player.update(move, disp, bottomrect)
if power:
pow = power.update(player, opp, ball)
if 30:
m = ball.update(1, player, opp, disp, bottomrect)
if sound and m:
music.play('collide')
omove = ai.update(frame, ball, opp)
if omove == 1 or omove == -1:
frame = 0
opp.update(omove, disp, bottomrect)
# Check for score
if ball.rect.x <= 0 or ball.rect.x >= size[0]:
if ball.rect.x >= size[0]:
disp.update(1, 0)
else:
disp.update(0, 1)
if sound:
music.play('score')
ball.rect.topleft = [size[0]/2, size[1]/2]
pygame.time.wait(limit*3)
ball.touch = False
ball.random_place()
# Draw everything
draw_all(screen,background, player, ball, opp, disp, power)
# Clean up
pygame.display.update()
move = 0
print 'The lowest frame rate was %s and the highest was %s.' %(low, high)
pygame.quit()
### End global definitions ###
### Start ###
if __name__ == '__main__':
n = 'Kyle'#raw_input('Name? ')
main((600, 500), 200, n, 0, sound=False)
Again, thanks for any help given