Trouble with classes in pygame - python

I've been working on a game using pygame. So far I have got the shooting to work.
Here is the code:
def game_loop():
global x
global y
x=0
y=0
second_x=0
second_y=0
change_x=0
change_y=0
xlist=[]
ylist=[]
# paused=True
while True:
game_display.blit(background, (0, 0))
mouseclk=pygame.mouse.get_pressed()
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
quit()
x, y = pygame.mouse.get_pos()
xlist.append(x)
ylist.append(y)
if x>=display_width-40:
x=display_width-40
if y>=display_height-48:
y=display_height-48
if event.type == pygame.MOUSEBUTTONUP :
if event.button==1:
bullets.append([x+16,y])
shoot.play()
for bullet in bullets:
game_display.blit(bulletpic, (bullet[0], bullet[1]+10))
for b in range(len(bullets)):
bullets[b][-1] -= 10
for bullet in bullets:
if bullet[1]>display_height:
bullets.remove(bullet)
mainship=Ship(spaceship, x, y, pygame.mouse.get_focused())
mainship.MakeShip()
if pygame.mouse.get_focused()==0:
pause()
pygame.display.update()
clock.tick(60)
The shooting works fine but i really want to use classes in my game. I tried making a class like this:
class Bullet:
def __init__(self, xpos, ypos, sprite, speed, llist):
self.xpos=xpos
self.ypos=ypos
self.sprite=sprite
self.speed=speed
self.list=llist
self.list.append([self.xpos+16,self.ypos])
for bullet in self.list:
game_display.blit(self.sprite, (bullet[0], bullet[1]+10))
for b in range(len(self.list)):
self.list[b][-1] -= self.speed
for bullet in self.list:
if bullet[1]>display_height:
self.list.remove(bullet)
Now, even though this looks like it would work, it just makes the bullets glitchy and slow and sometimes the bullets won't even spawn properly.
Is there any way i can make this work? I'm a noob programmer and new to classes in general so any help will be appreciated.

I think your Bullet does far too much. You could model bullets like so:
class Bullet:
"""This is a bullet. It knows about its position, direction and speed.
It can move. It knows when it crosses the classvariables bounds."""
# bounds as class variable for _all_ bullets - set it to dimensions of your game field
bounds = (0,0,10,10) # if position is lower or higher that these it is out of bounds
# if you got only 1 spite for all bullets (no acid-, fire-, waterbullets) you could
# set it here. I would not, I would leave bullets simply to do the movement and tell
# me if they get out of bounds
def __init__(self, xpos, ypos, xdir, ydir, speed):
# where does the bullet start (f.e. muzzle position)
self.xpos=xpos
self.ypos=ypos
# direction that the bullet flies
self.xdir=xdir
self.ydir=ydir
# initial speed of the bullet
self.speed=speed
def moveBullet(self):
self.xpos += int(self.xdir * self.speed) # speed may be 0.8 or so
self.ypos += int(self.ydir * self.speed)
def outOfBounds(self):
minX,minY,maxX,maxY = Bullet.bounds
return self.xpos < minX or self.ypos < minY or self.xpos > maxX or self.ypos > maxY
def __repr__(self):
"""Pretty print stuff"""
return "({},{}){}".format(self.xpos,self.ypos,"" if
not self.outOfBounds()
else " : Out Of Bounds {}".format(Bullet.bounds))
Your game then sets the bounds of all bullets and keeps track of a list of bullets. If you need a new bullet, simply place it into the list
Bullet.bounds = (0,0,90,90)
bullets = [ Bullet(10,10,12,0,3), Bullet(10,10,11,9,3), Bullet(10,10,0,5,1)]
while bullets:
# you should move this into some kind of `def moveBullets(bulletlist): ...`
# that you then call inside your game loop
for b in bullets:
b.moveBullet()
print(b) # instead draw a spirte at b.xpos, b.ypos
print("")
# return from moveBullets(..)
# remove all out of bounds bullets from list
bullets = filter(lambda b: not b.outOfBounds(),bullets)
Output:
(46,10)
(43,37)
(10,15)
(82,10)
(76,64)
(10,20)
(118,10) : Out Of Bounds (0, 0, 90, 90)
(109,91) : Out Of Bounds (0, 0, 90, 90)
(10,25)
(10,30)
(10,35)
(10,40)
(10,45)
(10,50)
(10,55)
(10,60)
(10,65)
(10,70)
(10,75)
(10,80)
(10,85)
(10,90)
(10,95) : Out Of Bounds (0, 0, 90, 90)

Related

Implementing a collision detect feature between a Rect object and a ball in pygame [duplicate]

This question already has an answer here:
Sometimes the ball doesn't bounce off the paddle in pong game
(1 answer)
Closed 2 years ago.
import pygame, random, time
# main function where we call all other functions, start the game loop, quit pygame and clean up the window. Inside we create a game object, display surface, and start the game loop by calling the play method on the game object. There is also a set caption with the title of the game.
def main():
pygame.init()
size =(500,400)
surface=pygame.display.set_mode(size)
pygame.display.set_caption('Pong v2')
game = Game(surface)
game.play()
pygame.quit()
# This is where we define the class game
class Game():
# an object in this class represents a complete game
# here we initialize a game. self is the game that is initialized surface is the display window surface object we also set default values for continuing the game and closing the window. we also define what fps we are running the game at, and define the velocity color position and radius of the ball
def __init__(self,surface):
# defining surface, fps, background color
self.surface=surface
self.FPS=120
self.bg_color=pygame.Color('black')
screen_width = surface.get_width()
screen_height = surface.get_height()
# defining ball attributes
ball_radius=10
ball_pos = [random.randint(ball_radius, screen_width-ball_radius),
random.randint(ball_radius, screen_height-ball_radius)]
ball_color=pygame.Color('white')
ball_velocity=[2,1]
self.ball=Ball(ball_pos,ball_radius,ball_color,ball_velocity,surface)
# defining paddle attributes
rect_left=[50,450]
rect_top=225
rect_height=60
rect_width=10
self.Paddle1=Rect(rect_left[0],rect_top,rect_width,rect_height,surface)
self.Paddle2=Rect(rect_left[1],rect_top,rect_width,rect_height,surface)
self.game_Clock=pygame.time.Clock()
self.close_clicked=False
self.continue_game=True
self.score1=0
self.score2=0
self.frame_counter=0
def play(self):
# game is played until player clicks close
while not self.close_clicked:
self.handle_events()
self.draw()
# if nothing sets this to false the game will continue to update
if self.continue_game:
self.update()
self.game_Clock.tick(self.FPS)
# score is drawn onto the screen (unimportant this is just playing with a feature for the next version), we define color font background etc of the score message and update score upon points being scored
def draw_score(self):
font_color = pygame.Color("white")
font_bg = pygame.Color("black")
font = pygame.font.SysFont("arial", 18)
text_img = font.render("Score for Player 1: " + str(self.score1) + ' Score for Player 2: ' + str(self.score2), True, font_color, font_bg)
text_pos = (0,0)
self.surface.blit(text_img, text_pos)
# ball, surface, score, and two paddles are drawn, pygame also updates this drawing once per frame
def draw(self):
self.surface.fill(self.bg_color)
self.draw_score()
#pygame.draw.rect(self.surface,pygame.Color('blue'),(50,225,10,50))
#pygame.draw.rect(self.surface,pygame.Color('red'),(450,225,10,50))
self.Paddle1.draw()
self.Paddle2.draw()
self.ball.draw()
pygame.display.update()
# score value set to default of 0 we tell ball to move and add 1 to frame counter upon each update. update game object for the next frame
def update(self):
self.ball.move()
self.score=0
self.frame_counter+=self.frame_counter+1
# here we setup an event loop and figure out if the action to end the game has been done
def handle_events(self):
events=pygame.event.get()
for event in events:
if event.type== pygame.QUIT:
self.close_clicked=True
# user defined class ball
class Ball:
# self is the ball to intialize. color/center/radius are defined for the ball that is initialized
def __init__(self,center,radius,color,velocity,surface):
self.center=center
self.radius=radius
self.color=color
self.velocity=velocity
self.surface=surface
# screen size is determined and edge of ball is checked that it is not touching the edge. if it is touching the edge it bounces and reverses velocity
def move(self):
screen_width=self.surface.get_width()
screen_height=self.surface.get_height()
screen_size=(screen_width,screen_height)
for i in range(0,len(self.center)):
self.center[i]+=self.velocity[i]
if (self.center[i]<=0 + self.radius or self.center[i]>=screen_size[i] - self.radius):
self.velocity[i]=-self.velocity[i]
# ball is drawn
def draw(self):
pygame.draw.circle(self.surface,self.color,self.center,self.radius)
class Rect:
def __init__(self,left,top,width,height,surface):
#self.left=left
#self.top=top
#self.width=width
#self.height=height
self.surface=surface
self.rect=pygame.Rect(left,top,width,height)
def draw(self):
pygame.draw.rect(self.surface,pygame.Color('red'),self.rect)
def collide(self):
if pygame.Rect.collide(x,y) == True:
return True
else:
return False
main()
Above is my work so far basically its supposed to be the retro arcade game pong where the ball bounces off of the edges of the paddles and if it doesn't the opposite side scores a point upon it hitting the edge of the window. So specifically this part of the project requires me to make the ball bounce off of the front of the paddles and I'm confused as to how to do this. My idea originally was to use the collidepoint method inside of the class Rect that if it returns true would reverse the balls velocity. However, I don't have access to the centre coordinates of the ball inside of the class or inside of the method play in the class game where I intended to make this work on the specific instances of ball and paddle1,paddle2 so I don't know how to do this.
Evaluate if the ball hits the left paddle at the right, respectively the right paddle at the left in Game.update.
If the ball hits the paddle the the score can be incremented:
class Game():
# [...]
def update(self):
self.ball.move()
# evaluate if Ball hits the left paddle (Paddle1) at the right
if self.ball.velocity[0] < 0 and self.Paddle1.rect.top <= self.ball.center[1] <= self.Paddle1.rect.bottom:
if self.Paddle1.rect.right <= self.ball.center[0] <= self.Paddle1.rect.right + self.ball.radius:
self.ball.velocity[0] = -self.ball.velocity[0]
self.ball.center[0] = self.Paddle1.rect.right + self.ball.radius
self.score1 += 1
# evaluate if Ball hits the right paddle (Paddle2) at the left
if self.ball.velocity[0] > 0 and self.Paddle2.rect.top <= self.ball.center[1] <= self.Paddle2.rect.bottom:
if self.Paddle2.rect.left >= self.ball.center[0] >= self.Paddle2.rect.left - self.ball.radius:
self.ball.velocity[0] = -self.ball.velocity[0]
self.ball.center[0] = self.Paddle2.rect.left - self.ball.radius
self.score2 += 1
Get the state of the keys by pygame.key.get_pressed() and change the position of the paddles is Game.handle_events.
e.g. Move the left paddle by w / s and the right paddle by UP / DOWN:
class Game():
# [...]
def handle_events(self):
events=pygame.event.get()
for event in events:
if event.type== pygame.QUIT:
self.close_clicked=True
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.Paddle1.rect.top = max(0, self.Paddle1.rect.top - 3)
if keys[pygame.K_s]:
self.Paddle1.rect.bottom = min(self.surface.get_height(), self.Paddle1.rect.bottom + 3)
if keys[pygame.K_UP]:
self.Paddle2.rect.top = max(0, self.Paddle2.rect.top - 3)
if keys[pygame.K_DOWN]:
self.Paddle2.rect.bottom = min(self.surface.get_height(), self.Paddle2.rect.bottom + 3)

Shooting bullets in pygame

I'm making my own space invaders game and so far I've been able to move my ship around using the mouse. However, I still can't shoot. Here's my game loop.
def game_loop():
x=0
y=0
xlist=[]
ylist=[]
while True:
mouseclk=pygame.mouse.get_pressed()
game_display.fill(white)
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
quit()
x, y = pygame.mouse.get_pos()
xlist.append(x)
ylist.append(y)
if x>=display_width-40:
x=display_width-40
if y>=display_height-48:
y=display_height-48
if pygame.mouse.get_focused()==0:
game_display.blit(spaceship, (x, y))
elif pygame.mouse.get_focused()==1:
game_display.blit(spaceshipflames, (x, y))
pygame.display.update()
if pygame.mouse.get_focused()==0:
pause()
clock.tick(500)
I've tried using the following code inside my game loop:
if mouseclk[0]==1:
shoot.play()
while True:
pygame.draw.circle(game_display, white, (x+20, y-2), 5)
pygame.draw.circle(game_display, red, (x+20, y-7), 5)
y-=5
if y<=0:
break
pygame.display.update()
clock.tick(400)
But the end result is very glitchy and doesn't allow me to shoot multiple bullets without making the game choppy.
Is there a way to run both loops at the same time, or a completely different way to implement shooting?
I'd recommend making use of classes (especially for games) and splitting up your code into smaller functions.
When making a game, each class should represent some type of object in the game, for example a ship or a bullet here. Using classes should help with this problem of multiple bullets causes glitches.
Breaking into smaller functions will make your code much easier to read and update as it grows. Try to stick to the Single Responsibility Principle as much as possible.
How you might implement shooting with these things in mind:
bullets = []
class Bullet:
def __init__(self, position, speed):
self.position = position
self.speed = speed
def move(self):
self.position[1] += self.speed
class Ship:
def __init__(self, position, bullet_speed):
self.position = position
self.bullet_speed = bullet_speed
def shoot(self):
new_bullet = Bullet(self.position, self.bullet_speed)
bullets.append(new_bullet)
Where the position variables have the form [x,y]. Then to move your bullets forward, put this line somewhere in your main game loop:
for bullet in bullets:
bullet.move()
And loop over all the bullets and draw each to the screen to render them.
This isn't the most detailed example, but hopefully it's enough to get you going in the right direction.

Making a pacman game and not sure how to remove pac pellets after colliding with

I'm currently making a pacman game and am struggling to figure out how to remove a pelllet from the screen after colliding with it. I tried changing the colour to black, but I couldn't make it work. I next tried to del the element index, but that also didn't work.
import pygame
import os
import sys
#initialise the game
pygame.init()
screen = pygame.display.set_mode((448, 576))
done = False
y = 416
x = 232
#sets up clock and loads pacman image
clock = pygame.time.Clock()
PACMANSPRITE = pygame.image.load("pacman.png").convert_alpha()
PACMAN_MAP = pygame.image.load("pacman_map.png").convert_alpha()
#gets pacman intro music, sets music to lower volume then plays it
pygame.mixer.music.load('pacman_beginning.WAV')
pygame.mixer.music.set_volume(0.01)
pygame.mixer.music.play(0)
#box class, used for boxes to border pacmans map
class boxcollisions(pygame.sprite.Sprite):
def __init__(self, x, y):
self.y = y
self.x = x
self.rect = pygame.Rect(self.x, self.y, 12, 12)
self.colour = (0, 128, 255)
def draw(self, screen):
pygame.draw.rect(screen, self.color, self.rect)
class pointclass(pygame.sprite.Sprite):
def __init__(self, x, y):
self.y = y
self.x = x
self.rect = pygame.Rect(self.x, self.y, 12, 12)
self.colour = (255, 204, 153)
self.score=0
def draw(self, screen):
pygame.draw.rect(screen, self.colour, self.rect)
def addpoint(self):
self.score+=1
print(self.score)
self.colour= (0,0,0)
print('why isnt it working')
#pacmans class
class pacman(pygame.sprite.Sprite):
def __init__(self, image, x, y):
self.image = image
self.y=416
self.x=216
self.currentx=self.x
self.currenty=self.y
self.rect = self.image.get_rect()
self.rect.left = self.x
self.rect.top = self.y
self.rect.width=16
self.rect.height=16
# move pacman
def movement(self):
pressed= pygame.key.get_pressed()
if pressed[pygame.K_UP]:
self.y -= 2
if pressed[pygame.K_DOWN]:
self.y += 2
if pressed[pygame.K_LEFT]:
self.x -= 2
if pressed[pygame.K_RIGHT]:
self.x += 2
self.rect.left = self.x
self.rect.top = self.y
def draw(self, surface):
# blit yourself at your current position
surface.blit(self.image, (self.x, self.y))
self.currentx=self.x
self.currenty=self.y
def outofbounds(self):
self.y=self.currenty
self.x=self.currentx
self.rect.left = self.x
self.rect.top = self.y
#instances the pacman class
sprite = pacman(PACMANSPRITE, x ,y)
#main game loop
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
sys.exit()
screen.fill((0,0,0))
screen.blit(PACMAN_MAP, (0, 0))
#co-ordinates for boxes to set up map boundaries
boxboundaries=[
[],
[],
[],
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],
[1,14,15,28], #5
[1,3,4,5,6,8,9,10,11,12,14,15,17,18,19,20,21,23,24,25,26,28],
[1,3,4,5,6,8,9,10,11,12,14,15,17,18,19,20,21,23,24,25,26,28],
[1,3,4,5,6,8,9,10,11,12,14,15,17,18,19,20,21,23,24,25,26,28],
[1,28],
[1,3,4,5,6,8,9,11,12,13,14,15,16,17,18,20,21,23,24,25,26,28], #10
[1,3,4,5,6,8,9,11,12,13,14,15,16,17,18,20,21,23,24,25,26,28],
[1,8,9,14,15,20,21,28],
[1,2,3,4,5,6,8,9,10,11,12,14,15,17,18,19,20,21,23,24,25,26,27,28],
[1,2,3,4,5,6,8,9,10,11,12,14,15,17,18,19,20,21,23,24,25,26,27,28],
[6,8,9,20,21,23], #15
[6,8,9,11,12,13,14,15,16,17,18,20,21,23],
[1,2,3,4,5,6,8,9,11,12,13,14,15,16,17,18,20,21,23,24,25,26,27,28],
[1,11,12,13,14,15,16,17,18,28],
[1,2,3,4,5,6,8,9,11,12,13,14,15,16,17,18,20,21,23,24,25,26,27,28],
[6,8,9,11,12,13,14,15,16,17,18,20,21,23,24,25,26,27,28], #20
[6,8,9,20,21,23],
[6,8,9,11,12,13,14,15,16,17,18,20,21,23],
[1,2,3,4,5,6,8,9,11,12,13,14,15,16,17,18,20,21,23,24,25,26,27,28],
[1,14,15,28],
[1,3,4,5,6,8,9,10,11,12,14,15,17,18,19,20,21,23,24,25,26,28], #25
[1,3,4,5,6,8,9,10,11,12,14,15,17,18,19,20,21,23,24,25,26,28],
[1,5,6,23,24,28],
[1,2,3,5,6,8,9,11,12,13,14,15,16,17,18,20,21,23,24,26,27,28],
[1,2,3,5,6,8,9,11,12,13,14,15,16,17,18,20,21,23,24,26,27,28],
[1,8,9,14,15,20,21,28], # 30
[1,3,4,5,6,7,8,9,10,11,12,14,15,17,18,19,20,21,22,23,24,25,26,28],
[1,3,4,5,6,7,8,9,10,11,12,14,15,17,18,19,20,21,22,23,24,25,26,28],
[1,28],
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28],
]
#point spawn locations
pointspawns=[
[],
[],
[],
[],
[2,3,4,5,6,7,8,9,10,11,12,13,16,17,18,19,20,21,22,23,24,25,26,27], #5
[2,7,13,16,22,27],
[2,7,13,16,22,27],
[2,7,13,16,22,27],
[2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27],
[2,7,10,19,22,27], #10
[2,7,10,19,22,27],
[2,3,4,5,6,7,10,11,12,13,16,17,18,19,22,23,24,25,26,27],
[7,22],
[7,22],
[7,22], #15
[7,22],
[7,22],
[7,22],
[7,22],
[7,22], #20
[7,22],
[7,22],
[7,22],
[2,3,4,5,6,7,8,9,10,11,12,13,16,17,18,19,20,21,22,23,24,25,26,27],
[2,7,13,16,22,27], #25
[2,7,13,16,22,27],
[2,3,4,7,8,9,10,11,12,13,16,17,18,19,20,21,22,25,26,27],
[4,7,10,19,22,25],
[4,7,10,19,22,25],
[2,3,4,5,6,7,10,11,12,13,16,17,18,19,22,23,24,25,26,27],
[2,13,16,27], # 30
[2,13,16,27],
[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27],
]
#moves pacman
sprite.movement()
px=0
py=-16
for row in pointspawns:
#y co ordinate
py=py+16
for n in row:
#x co ordinate
n=n-1
px=n*16
point=(pointclass(px, py))
#used to draw points
point.draw(screen)
if pygame.sprite.collide_rect(sprite, point):
point.addpoint()
#builds the boxes
bx=0
by=-16
for row in boxboundaries:
#y co ordinate
by=by+16
for n in row:
#x co ordinate
n=n-1
bx=n*16
box=(boxcollisions(bx, by))
#used to draw boxes for visual repsentation
#box.draw(screen)
if pygame.sprite.collide_rect(sprite, box):
sprite.outofbounds()
#draws pacman
sprite.draw(screen)
pygame.display.flip()
clock.tick(60)
The easiest way I know (and I don't know a lot) is using pygame.sprite.Group() and pygame.sprite.spritecollide.
The basic logic here would be, create a sprite group for the pellets, create every pellet as a sprite and add it to the group. On every iteration of the game loop, draw the sprite group to the screen and validate if there was collision between the player character and any of the pellets in the pellets group with spritecollide.
spritecollide has a paramenter to eliminate the pellet when there is collision, so you want to set that to true, in order to avoid drawing it in the next loop.
#Basic logic as example.
pellets = pygame.sprite.Group()
#CREATE PELLETS AND ADD THEM TO THE pellets sprite group.
player = Sprite()
...
#IN THE GAME LOOP
#Validate if there was a collision.
pellets_hit = pygame.sprite.spritecollide(player, pellets, True) #True indicates that, if there were any hit, remove the pellet from the group.
if len(pellet_hit):
#Increment score or something.
...
#Updating the display
player.draw(screen)
pellets.draw(screen) #If there were any hit, the pellet won't be in this group and won't be drawn
This is a project example that uses sprites and sprites groups:
Snake game
i figured it out after a lot of work
#spawn pellets function
def spawnpellets(pointspawns):
abc=0
efg=0
px=0
py=-16
for row in pointspawns:
#y co ordinate
py=py+16
for n in row:
#x co ordinate
n=n-1
px=n*16
point=(pointclass(px, py))
#used to draw points
point.draw(screen)
if pygame.sprite.collide_rect(sprite, point):
tempfunc(pointspawns, row, n , py)
def tempfunc(pointspawns, row, n, py):
abc=n+1
efg=py/16
efg=int(efg)
tempindex=row.index(abc)
del pointspawns[efg][tempindex]
pointspawns[int(efg)].insert(abc,0)
essentially, i had to put the spawning of the pellets into a function ,and then the collsions detection as another function, then using the vaules or row and n in my for loops i worked out the exact list and indexes i need to use, i then replaces the element with a 0 to have be redrawn no where. sorry if the code lookes a bit jimbled and im aware my variable names are terrible, but i literally just finished this now after 2 hours so im now going to take a well deserved break

How to increase points when a rect collides with another rect and the left mouse button is clicked?

So I am making a game where the player has to click on a moving rect (a tennis ball) to get points. So far I have created the tennis ball and some other balls, and I have got them moving randomly round the screen and bouncing off the edges. I have also made a rect called target which moves with the mouse. I would like the game to add 10 points every time the player clicks on the tennis ball (with the target) and deduct a life if they click elsewhere on the screen. Any help would be greatly appreciated!
Thanks :)
import pygame
import sys
from random import *
from pygame.locals import *
#game
pygame.init()
running=True
screen_width=800
screen_height=600
screen=pygame.display.set_mode([screen_width,screen_height])
background_colour = (0,0,150)
screen.fill(background_colour)
clock=pygame.time.Clock()
game_sound='pumpup.wav'
pygame.mixer.init()
points=0
lives=3
#balls
x= randint(20,40)
y= randint(20,40)
ball=pygame.image.load ('ball_t.png')
ball_movement=[x,y]#amount ball moves each time (x,y)
ball_location=[100,100]#x,y co-ordinates for start position
ball_rect=ball.get_rect()#gets rectangle for ball
x2= randint(5,15)
y2= randint(5,15)
ball2_movement=[x2,y2]#amount ball moves each time (x,y)
ball2_location=[10,10]#x,y co-ordinates for start position
ball2=pygame.image.load ('ball_tt.png')
ball2_rect=ball2.get_rect()#gets rectangle for ball
x3= randint(10,40)
y3= randint(10,30)
ball3_movement=[x3,y3]#amount ball moves each time (x,y)
ball3_location=[10,100]#x,y co-ordinates for start position
ball3=pygame.image.load ('ball_b.png')
ball3_rect=ball3.get_rect()#gets rectangle for ball
x4= randint(10,30)
y4= randint(10,30)
ball4_movement=[x4,y4]#amount ball moves each time (x,y)
ball4_location=[200,100]#x,y co-ordinates for start position
ball4=pygame.image.load ('ball_bs.png')
ball4_rect=ball4.get_rect()#gets rectangle for ball
#target
target_location=[200,100]#x,y co-ordinates for start position
target=pygame.image.load ('Target.png')
target_rect=target.get_rect()#gets rectangle for ball
target_rect.center=target_location
#score
font=pygame.font.Font(None, 50)#default font
score="Score: {}".format(points)
score_text=font.render(score,1,(0,200,250))
text_pos=[10,10] #position on screen
#lives
font=pygame.font.Font(None, 50)#default font
livest="Lives: {}".format(lives)
lives_text=font.render(livest,1,(0,200,250))
textl_pos=[650,10]#position on screen
#show initial screen
screen.blit(ball, ball_rect)#draws ball on its rectangle
screen.blit(ball2, ball2_rect)
screen.blit(ball3, ball3_rect)
screen.blit(ball4, ball4_rect)
screen.blit(target, target_rect)
screen.blit(score_text, text_pos)
screen.blit(lives_text, textl_pos)
pygame.display.flip() #displays screen
while running: #event loop
clock.tick(50) #won't run at more than 60 frames per second
screen.fill([0,0,150])#clears screen
for event in pygame.event.get():
if event.type==pygame.QUIT:
running=False
elif event.type==pygame.MOUSEMOTION:
target_rect.centerx=event.pos[0] #moves target with mouse
target_rect.centery=event.pos[1]
if event.type == pygame.MOUSEBUTTONDOWN and target_rect.colliderect(ball2_rect):
points=100
if ball_rect.left<0 or ball_rect.right>screen_width: #check whether ball is off screen (x)
ball_movement[0]=-ball_movement[0]#change direction on x axis
if ball_rect.top<0 or ball_rect.bottom>screen_height: #check whether ball is off screen (y)
ball_movement[1]=-ball_movement[1] #change direction on y axis
if ball2_rect.left<0 or ball2_rect.right>screen_width: #check whether ball is off screen (x)
ball2_movement[0]=-ball2_movement[0]#change direction on x axis
if ball2_rect.top<0 or ball2_rect.bottom>screen_height: #check whether ball is off screen (y)
ball2_movement[1]=-ball2_movement[1] #change direction on y axis
if ball3_rect.left<0 or ball3_rect.right>screen_width: #check whether ball is off screen (x)
ball3_movement[0]=-ball3_movement[0]
if ball3_rect.top<0 or ball3_rect.bottom>screen_height: #check whether ball is off screen (y)
ball3_movement[1]=-ball3_movement[1] #change direction on y axis
if ball4_rect.left<0 or ball4_rect.right>screen_width: #check whether ball is off screen (x)
ball4_movement[0]=-ball4_movement[0]
if ball4_rect.top<0 or ball4_rect.bottom>screen_height: #check whether ball is off screen (y)
ball4_movement[1]=-ball4_movement[1] #change direction on y axis
if ball_rect.top > screen_height and lives >0:
lives=lives-1
livest="Lives: {}".format(lives)
lives_text=font.render(livest,1,(0,0,0))
pygame.time.delay(500)#pause
ball_rect.topleft=[10,0] #reinstate ball
if lives ==0:
pygame.display.flip()
pygame.time.delay(2500)#pause
running=False
ball_rect=ball_rect.move(ball_movement)#move ball
ball2_rect=ball2_rect.move(ball2_movement)
ball3_rect=ball3_rect.move(ball3_movement)
ball4_rect=ball4_rect.move(ball4_movement)
screen.blit(ball, ball_rect)#redraws ball
screen.blit(ball2, ball2_rect)
screen.blit(ball3, ball3_rect)
screen.blit(ball4, ball4_rect)
screen.blit(target, target_rect)
screen.blit(score_text, text_pos)
screen.blit(lives_text, textl_pos)
pygame.display.flip() #displays screen
pygame.quit() #quits game
I would recommend not creating a ball 4 different times. Instead, create a ball class and make 4 ball objects. Try this
class ball:
def __init__(self, x, y, image, location):
self.x = x
self.y = y
self.img = image
self.movement = [x, y]
self.rect = self.img.get_rect()
self.rect.topleft = location
Then, you can get rid of all of this:
x= randint(20,40)
y= randint(20,40)
ball=pygame.image.load ('ball_t.png')
ball_movement=[x,y]#amount ball moves each time (x,y)
ball_location=[100,100]#x,y co-ordinates for start position
ball_rect=ball.get_rect()#gets rectangle for ball
x2= randint(5,15)... etc.
and replace it all with this:
balls = []
balls.append(ball(randint(20, 40), randint(20, 40), 'ball_t.png', [100, 100])
balls.append(ball(randint(5, 15), randint(5, 15), 'ball_tt.png', [10, 10])
balls.append(ball(randint(10, 40), randint(10, 30), 'ball_b.png', [10, 100])
balls.append(ball(randint(10, 30), randint(10, 30), 'ball_bs.png', [200, 100])
Then, take this part:
if ball_rect.left<0 or ball_rect.right>screen_width: #check whether ball is off screen (x)
ball_movement[0]=-ball_movement[0]#change direction on x axis
if ball_rect.top<0 or ball_rect.bottom>screen_height: #check whether ball is off screen (y)
ball_movement[1]=-ball_movement[1] #change direction on y axis
if ball2... etc.
and replace it with a method of ball.
class ball:
def __init__():
blah blah blah init
def is_touching_wall(self):
if self.rect.left < 0 or self.rect.right > screen_width:
self.movement[0] -= self.movement[0]
if self.rect.top < 0 or self.rect.bottom > screen_height:
self.movement[1] -= self.movement[1]
and then in the main function:
for ball in balls:
ball.is_touching_wall()
And then lastly, add one more method to the ball class:
def update(self):
self.rect = self.rect.move(self.movement)
screen.blit(self.img, self.rect)
and replace this part:
ball_rect=ball_rect.move(ball_movement)#move ball
ball2_rect=ball2_rect.move(ball2_movement)
ball3_rect=ball3_rect.move(ball3_movement)
ball4_rect=ball4_rect.move(ball4_movement)
screen.blit(ball, ball_rect)#redraws ball
screen.blit(ball2, ball2_rect)
screen.blit(ball3, ball3_rect)
screen.blit(ball4, ball4_rect)
with this:
for ball in balls:
ball.update()
Lastly, two more recommendations.
Don't post questions on SE saying, "Here's my code. Fix it." You never specified what you tried to fix the problem, where in your code the problem is, or even exactly what your question was. Also, try to only post the smallest part of your code that will replicate your problem. Fix your code, and add more information to your question, and then people will be a lot more willing to help you with the target.
Pay attention to formatting. Read PEP-8. Add spaces inbetween arguments and inbetween comparisons. Indent better. Import this. etc...

Single player 'pong' game

I am just starting out learning pygame and livewires, and I'm trying to make a single-player pong game, where you just hit the ball, and it bounces around until it passes your paddle (located on the left side of the screen and controlled by the mouse), which makes you lose. I have the basic code, but the ball doesn't stay on the screen, it just flickers and doesn't remain constant. Also, the paddle does not move with the mouse. I'm sure I'm missing something simple, but I just can't figure it out. Help please! Here's what I have:
from livewires import games
import random
games.init(screen_width=640, screen_height=480, fps=50)
class Paddle(games.Sprite):
image=games.load_image("paddle.bmp")
def __init__(self, x=10):
super(Paddle, self).__init__(image=Paddle.image,
y=games.mouse.y,
left=10)
self.score=games.Text(value=0, size=25, top=5, right=games.screen.width - 10)
games.screen.add(self.score)
def update(self):
self.y=games.mouse.y
if self.top<0:
self.top=0
if self.bottom>games.screen.height:
self.bottom=games.screen.height
self.check_collide()
def check_collide(self):
for ball in self.overlapping_sprites:
self.score.value+=1
ball.handle_collide()
class Ball(games.Sprite):
image=games.load_image("ball.bmp")
speed=5
def __init__(self, x=90, y=90):
super(Ball, self).__init__(image=Ball.image,
x=x, y=y,
dx=Ball.speed, dy=Ball.speed)
def update(self):
if self.right>games.screen.width:
self.dx=-self.dx
if self.bottom>games.screen.height or self.top<0:
self.dy=-self.dy
if self.left<0:
self.end_game()
self.destroy()
def handle_collide(self):
self.dx=-self.dx
def end_game(self):
end_message=games.Message(value="Game Over",
size=90,
x=games.screen.width/2,
y=games.screen.height/2,
lifetime=250,
after_death=games.screen.quit)
games.screen.add(end_message)
def main():
background_image=games.load_image("background.bmp", transparent=False)
games.screen.background=background_image
paddle_image=games.load_image("paddle.bmp")
the_paddle=games.Sprite(image=paddle_image,
x=10,
y=games.mouse.y)
games.screen.add(the_paddle)
ball_image=games.load_image("ball.bmp")
the_ball=games.Sprite(image=ball_image,
x=630,
y=200,
dx=2,
dy=2)
games.screen.add(the_ball)
games.mouse.is_visible=False
games.screen.event_grab=True
games.screen.mainloop()
main()
I can't help you because you did not post the complete code here. At least, I do not see where you're updating the positions of the sprites (self.x += self.dx somewhere?) and updating the draw to screen. You're also not utilising your classes in the main() function.
That said, I'm seeing
def __init__(self, x=10):
and inside the constructor you never used the x variable. That worries me, too.
Consider using the Paddle and Ball class as a Sprite, like the following:
if __name__ == '__main__':
background_image = games.load_image("background.bmp", transparent=False)
games.screen.background = background_image
the_paddle = Puddle()
games.screen.add(the_paddle)
the_ball = Ball()
games.screen.add(the_ball)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
Note I've taken the liberty to make your code read more Pythonic. I have never used livewires, however, so my code may not function. But it should point you to the right direction. Good luck!
Why are you using livewires? You can use only pygame for a pong game.
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480)) # window size
pygame.display.set_caption("Simple pong") # window title
# this is a rect that contains the ball
# at the beginning it is set in the center of the screen
ball_rect = pygame.Rect((312, 232), (16, 16))
# speed of the ball (x, y)
ball_speed = [4, 4]
# this contains your paddle
# vertically centered on the left side
paddle_rect = pygame.Rect((8, 200), (8, 80))
# 1 point if you hit the ball
# -5 point if you miss the ball
score = 0
# load the font for displaying the score
font = pygame.font.Font(None, 30)
# mainloop
while True:
# event handler
for event in pygame.event.get():
# quit event => close the game
if event.type == pygame.QUIT:
exit(0)
# control the paddle with the mouse
elif event.type == pygame.MOUSEMOTION:
paddle_rect.centery = event.pos[1]
# correct paddle position if it's going out of window
if paddle_rect.top < 0:
paddle_rect.top = 0
elif paddle_rect.bottom >= 480:
paddle_rect.bottom = 480
# this test if up or down keys are pressed
# if yes move the paddle
if pygame.key.get_pressed()[pygame.K_UP] and paddle_rect.top > 0:
paddle_rect.top -= 5
elif pygame.key.get_pressed()[pygame.K_DOWN] and paddle_rect.bottom < 480:
paddle_rect.top += 5
# update ball position
# this move the ball
ball_rect.left += ball_speed[0]
ball_rect.top += ball_speed[1]
# these two if block control if the ball is going out on the screen
# if it's going it reverse speed to simulate a bounce
if ball_rect.top <= 0 or ball_rect.bottom >= 480:
ball_speed[1] = -ball_speed[1]
if ball_rect.right >= 640:
ball_speed[0] = -ball_speed[0]
# this control if the ball touched the left side
elif ball_rect.left <= 0:
score -= 5
# reset the ball to the center
ball_rect = pygame.Rect((312, 232), (16, 16))
# test if the ball is hit by the paddle
# if yes reverse speed and add a point
if paddle_rect.colliderect(ball_rect):
ball_speed[0] = -ball_speed[0]
score += 1
# clear screen
screen.fill((255, 255, 255))
# draw the ball, the paddle and the score
pygame.draw.rect(screen, (0, 0, 0), paddle_rect) # paddle
pygame.draw.circle(screen, (0, 0, 0), ball_rect.center, ball_rect.width/2) # ball
score_text = font.render(str(score), True, (0, 0, 0))
screen.blit(score_text, (320-font.size(str(score))[0]/2, 5)) # score
# update screen and wait 20 milliseconds
pygame.display.flip()
pygame.time.delay(20)

Categories

Resources