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)