my pygame bullet sprites only fire once each time through loop. would like to fire multiple times - pygame

i'm very new to coding, and i'm trying to get a ship to fire multiple bullets, but every time i push spacebar the bullet sort of re-triggers and doesn't make it to the end of the screen. it seems maybe only one instance of my Bullet class is called each time but i don't know how to fix it. here is the code i have going so far:
import sys
import pygame
from pygame.sprite import Sprite
class Sideship():
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((1200,800))
self.screen_rect = self.screen.get_rect()
pygame.display.set_caption("Side Ship")
self.bg_color = (50, 50, 255)
self.bullets = pygame.sprite.Group()
self.jet = Jet()
def run_game(self):
self.jet.rect.x = -20
self.jet.rect.y = 290
self.bullet = Bullet()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
self.jet.moving_down = True
if event.key == pygame.K_UP:
self.jet.moving_up = True
if event.key == pygame.K_SPACE:
self.new_bullet = Bullet()
self.bullets.add(self.new_bullet)
self.new_bullet.rect.x = self.jet.rect.x+200
self.new_bullet.rect.y = self.jet.rect.y+30
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
self.jet.moving_down = False
if event.key == pygame.K_UP:
self.jet.moving_up = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
sys.exit()
self.jet.update()
self.bullets.update()
self.screen.fill(self.bg_color)
self.bullets.update()
for bullet in self.bullets.sprites():
pygame.draw.rect(self.screen, self.new_bullet.bullet_color, self.new_bullet.rect)
self.screen.blit(self.jet.image, self.jet.rect)
pygame.display.flip()
class Jet():
def __init__(self):
self.image = pygame.image.load('jet.bmp')
self.rect = self.image.get_rect()
self.moving_down = False
self.moving_up = False
self.rect.y = float(self.rect.y)
self.rect.x = float(self.rect.x)
def update(self):
if self.moving_down and self.rect.bottom < 801:
self.rect.y += 1.9
if self.moving_up and self.rect.top > -14:
self.rect.y -= 1.4
class Bullet(Sprite):
def __init__(self,):
super().__init__()
self.bullet_width = 30
self.bullet_height = 5
self.bullet_color = (250,250,250)
self.rect = pygame.Rect(0,0, self.bullet_width, self.bullet_height)
def update(self):
self.rect.x += 4
side_ship = Sideship()
side_ship.run_game()

The issue is in the loop, which draws the bullets. When you iterate through the bullets, the current element is referenced by bullet. Hence, you have to draw bullet, rather than self.new_bullet:
pygame.draw.rect(self.screen, self.new_bullet.bullet_color, self.new_bullet.rect)
for bullet in self.bullets.sprites():
pygame.draw.rect(self.screen, bullet.bullet_color, bullet.rect)

Related

Order class objects are displayed on the screen

I am very new to Python and Pygame, if anyone can help point me in the right direction I would really appreciate it :)
From what I understand, the order these are displayed determines how they will appear.
I need the "ticker" to appear in front of the other class object, "tickerchart" but I can't seem to figure out why it isn't working.
self.ticker_movement() is first on the list.
Can anyone tell me why the ticker is not showing up on top of the "tickerchart" image when it moves to the same space on the screen?
class Ticker:
def __init__(self, main_ticker_screen):
self.main_ticker_screen = main_ticker_screen
TICKER_IMAGE = pygame.image.load(r'C:\Desktop\Coding\PYTHON\EXPERIMENT\assets\ticker.png').convert_alpha()
self.TICKER = pygame.transform.scale(TICKER_IMAGE, (6, 95))
self.TICKER_x = 1277.5
self.TICKER_y = 841
self.TICKER_direction = 'none'
def move_right(self):
self.TICKER_direction = 'right'
def move_left(self):
self.TICKER_direction = 'left'
def stopmoving(self):
self.TICKER_direction = 'none'
def drawticker(self):
self.main_ticker_screen.fill(BLACK)
self.main_ticker_screen.blit(self.TICKER, (self.TICKER_x, self.TICKER_y))
pygame.display.flip()
def movement(self):
if self.TICKER_direction == 'right':
self.TICKER_x += 22
if self.TICKER_direction == 'left':
self.TICKER_x -= 22
if self.TICKER_direction == 'none':
self.TICKER_x = self.TICKER_x
self.drawticker()
class TickerChart:
def __init__(self, ticker_screen):
self.ticker_screen = ticker_screen
FORTY_ONE_LEFT_IMAGE = pygame.image.load(r'C:\Desktop\Coding\PYTHON\EXPERIMENT\assets\41.png').convert_alpha()
self.FORTY_ONE = pygame.transform.scale(FORTY_ONE_IMAGE, (6, 120))
def draw_tickerchart(self):
#greytickers #left - 40s
self.ticker_screen.blit(self.FORTY_ONE, (1079.5, 816))
pygame.display.flip()
class Game:
def __init__(self):
pygame.init()
self.surface = pygame.display.set_mode((2555, 1005))
pygame.display.set_caption("PBF SCORE")
self.surface.fill(BLACK)
SCOREBOARD_IMAGE = pygame.image.load(r'C:\Desktop\Coding\PYTHON\EXPERIMENT\assets\score_board.png').convert_alpha()
self.SCOREBOARD = pygame.transform.scale(SCOREBOARD_IMAGE, (1236, 700))
self.surface.blit(self.SCOREBOARD, (650, 0))
self.ticker = Ticker(self.surface)
self.ticker.drawticker()
self.tickerchart = TickerChart(self.surface)
self.tickerchart.draw_tickerchart()
def run(self):
running = True
while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
if event.key == K_q:
self.ticker.move_right()
if event.key == K_o:
self.ticker.move_left()
if event.key == K_p:
self.ticker.stopmoving()
elif event.type == QUIT:
running = False
self.ticker.movement()
self.surface.blit(self.SCOREBOARD, (650, 0))
self.tickerchart.draw_tickerchart()
time.sleep(0.65)
if __name__ == "__main__":
game = Game()
game.run()
A possible problem might be that you arent calling for Ticket to be drawn every frame, only them the Game() class is initialized.
Put this in the run loop:
class Game:
def __init__(self):
pygame.init()
self.surface = pygame.display.set_mode((2555, 1005))
pygame.display.set_caption("PBF SCORE")
self.surface.fill(BLACK)
SCOREBOARD_IMAGE = pygame.image.load(r'C:\Desktop\Coding\PYTHON\EXPERIMENT\assets\score_board.png').convert_alpha()
self.SCOREBOARD = pygame.transform.scale(SCOREBOARD_IMAGE, (1236, 700))
self.surface.blit(self.SCOREBOARD, (650, 0))
self.ticker = Ticker(self.surface)
self.ticker.drawticker()
self.tickerchart = TickerChart(self.surface)
self.tickerchart.draw_tickerchart()
def run(self):
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.key == pygame.K_q:
self.ticker.move_right()
if event.key == pygame.K_o:
self.ticker.move_left()
if event.key == pygame.K_p:
self.ticker.stopmoving()
elif event.type == pygame.QUIT:
running = False
self.ticker.movement()
self.surface.blit(self.SCOREBOARD, (650, 0))
self.tickerchart.draw_tickerchart() # just add this line!!
time.sleep(0.65)
if __name__ == "__main__":
game = Game()
game.run()
I ran this and it seemed to work fine, the ticker (the moving object i presume) does apear and it does move around.
You just need to change ONE line of code in the Game class.

Automatically quits

I'm trying to write a snake game in python but my game automatically quites after inputing out of boundaries code.
I don't understand how the coordinates of my rect are >= than the width of my game, because in the screen they are not. I think that's what happens because the game automatically quits.
I'll post my code, below, to be even more clearer
import pygame
from random import randint
pygame.init()
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
class Game():
width, height = 800, 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Second snake game.")
def __init__(self):
pass
game = Game()
class Player(pygame.sprite.Sprite):
lead_x = game.width/2
lead_y = game.height/2
lead_x_change = 0
lead_y_change = 0
velocity = 0.2
block_size = 10
def __init__(self):
pygame.sprite.Sprite.__init__(self)
def draw_character(self):
self.cube = pygame.draw.rect(game.screen, black, [self.lead_x, self.lead_y, self.block_size, self.block_size])
def change_x_right(self):
self.lead_x_change += -self.velocity
def change_x_left(self):
self.lead_x_change += self.velocity
def change_y_up(self):
self.lead_y_change += -self.velocity
def change_y_down(self):
self.lead_y_change += self.velocity
def move_x(self):
self.lead_x += self.lead_x_change
def move_y(self):
self.lead_y += self.lead_y_change
def stop_moving_x(self):
self.lead_x_change = 0
def stop_moving_y(self):
self.lead_y_change = 0
class Apple():
lead_x = randint(100, 700)
lead_y = randint(100, 500)
block_size = 10
def __init__(self):
pass
def spawn_apple_after_eaten(self):
self.lead_x = randint(100, 700)
self.lead_y = randint(100, 500)
self.apple = pygame.draw.rect(game.screen, red, [self.lead_x, self.lead_y, self.block_size, self.block_size])
def spawn_apple(self):
self.apple = pygame.draw.rect(game.screen, red, [self.lead_x, self.lead_y, self.block_size, self.block_size])
apple = Apple()
player = Player()
gameExit = False
while not gameExit:
game.screen.fill(white)
apple.spawn_apple()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
player.change_x_left()
player.stop_moving_y()
if event.key == pygame.K_a:
player.change_x_right()
player.stop_moving_y()
if event.key == pygame.K_w:
player.change_y_up()
player.stop_moving_x()
if event.key == pygame.K_s:
player.change_y_down()
player.stop_moving_x()
if event.type == pygame.KEYUP:
if event.key == pygame.K_w or event.key == pygame.K_s:
player.stop_moving_y()
if event.key == pygame.K_a or event.key == pygame.K_d:
player.stop_moving_x()
player.move_x()
player.move_y()
player.draw_character()
if player.cube.colliderect(apple.apple):
apple.spawn_apple_after_eaten()
if player.lead_x + player.block_size >= game.width or player.lead_x <= game.width:
gameExit = True
pygame.display.update()
pygame.quit()
quit()
You're setting gameExit to True if the x-coordinate is greater than or equal to game.width or if it's less than or equal to game.width, so it's always True. The second part of the conditional statement should be or player.lead_x <= 0.
if player.lead_x + player.block_size >= game.width or player.lead_x <= 0:
gameExit = True

Pygame character face mouse

I am creating a basic 2d overhead view game, and am currently working to make the character "face" the mouse as I move it.
Here is my code so far:
class Player(pygame.sprite.Sprite):
def __init__(self,x,y):
super(Player,self).__init__()
self.image=player_image
self.original_image=self.image
self.rect=self.image.get_rect(center=(x,y))
self.change_x=0
self.change_y=0
self.speed=7.5
self.inventory={'wood':0}
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self,rect):
player.rotate()
self.rect.x+=self.change_x
self.rect.y+=self.change_y
screen.blit(self.image,(rect.x,rect.y))
def check(self):
global tick
if pygame.mouse.get_pressed()[0]:
for tree in resources:
tree_rect=tree.rect
if self.rect.colliderect(tree_rect) and tick>=9:
self.inventory['wood']+=1
tick=0
def rotate(self):
mouse_x, mouse_y = pygame.mouse.get_pos()
rel_x, rel_y = mouse_x - self.rect.x, mouse_y -self.rect.y
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.image = pygame.transform.rotate(self.original_image, int(angle))
self.rect = self.image.get_rect(center=(self.rect.x,self.rect.y))
To do this, I followed this answer. It supposedly calculated the vector between the mouse and the player, and turned the character around toward the mouse each step, but for me the sprite wobbled around when the mouse moved, and turned invisible.
Full code:
import pygame
from pygame.locals import *
import sys
import math
import pygame.gfxdraw
import random
pygame.init()
black=(0,0,0)
white=(255,255,255)
forest=(34,139,34)
red=(255,0,0)
blue=(0,0,255)
green=(0,255,0)
light_green=(0,120,0)
dark_green=(0,90,0)
skin=(255,224,189)
yellow=(255,255,0)
wood_image=pygame.image.load('./assets/images/wood.png')
stone_image=pygame.image.load('./assets/images/stone.png')
player_image=pygame.image.load('./assets/images/player.png')
tick=0
def terminate():
pygame.quit()
sys.exit()
def drawTextcenter(text,font,screen,x,y,color):
textobj=font.render(text,True,color)
textrect=textobj.get_rect(center=(x,y))
screen.blit(textobj,textrect)
def drawText(text, font, surface, x, y,color):
textobj=font.render(text, 1, color)
textrect=textobj.get_rect()
textrect.topleft=(x, y)
surface.blit(textobj, textrect)
class Button(object):
global screen_width,screen_height,screen
def __init__(self,x,y,width,height,text_color,background_color,text):
self.rect=pygame.Rect(x,y,width,height)
self.x=x
self.y=y
self.width=width
self.height=height
self.text=text
self.text_color=text_color
self.background_color=background_color
self.angle=0
def check(self):
return self.rect.collidepoint(pygame.mouse.get_pos())
def draw(self):
pygame.draw.rect(screen, self.background_color,(self.rect),0)
drawTextcenter(self.text,font,screen,self.x+self.width/2,self.y+self.height/2,self.text_color)
pygame.draw.rect(screen,self.text_color,self.rect,3)
class Bar(object):
def __init__(self,x,y,length,color):
self.rect=pygame.Rect(x,y,length,17.5)
self.image=pygame.draw.rect(screen,white,(self.rect),)
self.x=x
self.y=y
self.width=100
self.height=17.5
self.color=color
self.multiplier=length/100
def draw(self,num):
rect=pygame.Rect(self.x,self.y,num*self.multiplier,self.height)
pygame.draw.rect(screen,self.color,self.rect,3)
pygame.draw.rect(screen,self.color,rect,0)
class Player(pygame.sprite.Sprite):
def __init__(self,x,y):
super(Player,self).__init__()
self.image=player_image
self.original_image=self.image
self.rect=self.image.get_rect(center=(x,y))
self.change_x=0
self.change_y=0
self.speed=7.5
self.inventory={'wood':0}
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self,rect):
self.rotate(camera)
self.rect.x += self.change_x
self.rect.y += self.change_y
rect = camera.apply(self)
screen.blit(self.image, rect)
def check(self):
global tick
if pygame.mouse.get_pressed()[0]:
for tree in resources:
tree_rect=tree.rect
if self.rect.colliderect(tree_rect) and tick>=9:
self.inventory['wood']+=1
tick=0
def rotate(self,camera):
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_x -= camera.state.x
mouse_y -= camera.state.y
rel_x, rel_y = mouse_x - self.rect.centerx, mouse_y -self.rect.centery
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pygame.transform.rotate(self.original_image, angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Tree(pygame.sprite.Sprite):
def __init__(self,x,y):
super(Tree,self).__init__()
self.rect=pygame.Rect(x,y,100,100)
self.rect.x=x
self.rect.y=y
def update(self,rect):
pygame.gfxdraw.filled_circle(screen,rect.x,rect.y,80,light_green)
pygame.gfxdraw.aacircle(screen,rect.x,rect.y,80,light_green)
class Rock(pygame.sprite.Sprite):
def __init__(self):
pass
class Camera(object):
def __init__(self,camera_func,width,height):
self.camera_func=camera_func
self.state=pygame.Rect(0,0,width,height)
def apply(self,target):
return target.rect.move(self.state.topleft)
def update(self,target):
self.state=self.camera_func(self.state,target.rect)
def complex_camera(camera, target_rect):
l, t = target_rect.center
_,_,w,h = camera
l,t,_,_ = -l+screen_width/2, -t+screen_height/2, w, h
l = min(0, l)
l = max(-(camera.width-screen_width), l)
t = max(-(camera.height-screen_height), t)
t = min(0, t)
return pygame.Rect(l, t, w, h)
clock=pygame.time.Clock()
font=pygame.font.SysFont(None,40)
screen_width=1440
screen_height=800
screen=pygame.display.set_mode([screen_width,screen_height])
pygame.display.set_caption('Survival')
total_level_width=screen_width*5
total_level_height=screen_height*5
camera = Camera(complex_camera, total_level_width, total_level_height)
player=Player(random.randint(100,7900),random.randint(100,5900))
friendlies=pygame.sprite.Group()
friendlies.add(player)
player_health_bar=Bar(125,15,200,green)
player_health=100
player_food_bar=Bar(437.5,15,200,red)
player_food=100
player_thirst_bar=Bar(750,15,200,blue)
player_thirst=100
player_energy_bar=Bar(1100,15,200,yellow)
player_energy=100
resources=pygame.sprite.Group()
wood=False
inventory={}
for i in range(1000):
tree=Tree(random.randint(100,7900),random.randint(100,5900))
resources.add(tree)
done1=False
while not done1:
screen.fill(black)
font=pygame.font.SysFont(None, 90)
text_width,text_height=font.size('Survival')
drawText('Survival', font, screen, (screen_width/2-text_width/2), (screen_height / 2-375),white)
font=pygame.font.SysFont(None, 40)
start_button=Button(screen_width/2-125,650,250,50,white,black,'Start')
start_button.draw()
back_button=Button(screen_width/2-125,725,250,50,white,black,'Back')
back_button.draw()
pygame.display.flip()
done2=False
while not done2:
for event in pygame.event.get():
if event.type==QUIT:
terminate()
elif event.type==pygame.MOUSEBUTTONDOWN:
if start_button.check()==True:
done3=False
pause_back=False
while not done3:
tick+=1
for event in pygame.event.get():
if event.type==pygame.QUIT:
terminate()
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_a:
player.changespeed(-(player.speed), 0)
elif event.key==pygame.K_d:
player.changespeed(player.speed, 0)
elif event.key==pygame.K_w:
player.changespeed(0, -(player.speed))
elif event.key==pygame.K_s:
player.changespeed(0, player.speed)
elif event.key==pygame.K_p:
font=pygame.font.SysFont(None, 90)
text_width,text_height=font.size('Paused')
drawText('Paused', font, screen, (screen_width / 2-(text_width/2)), (screen_height / 2-375),white)
resume_button=Button(screen_width/2-125,650,250,50,white,black,'Resume')
resume_button.draw()
back_button.draw()
pygame.display.flip()
back=False
while not back:
for event in pygame.event.get():
if event.type==QUIT:
terminate()
elif event.type==pygame.MOUSEBUTTONDOWN:
if resume_button.check()==True:
back=True
elif back_button.check()==True:
done3=True
done2=True
pause_back=True
back=True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.changespeed(player.speed, 0)
elif event.key == pygame.K_d:
player.changespeed(-(player.speed), 0)
elif event.key == pygame.K_w:
player.changespeed(0, player.speed)
elif event.key == pygame.K_s:
player.changespeed(0, -(player.speed))
camera.update(player)
if player.rect.x<0:
player.rect.x=0
if player.rect.right>total_level_width:
player.rect.right=total_level_width
if player.rect.y<0:
player.rect.y=0
if player.rect.bottom>total_level_height:
player.rect.bottom=total_level_height
screen.fill(dark_green)
player.update(camera)
for resource in resources:
resource.update(camera.apply(resource))
player_health_bar.draw(player_health)
player_food_bar.draw(player_food)
player_thirst_bar.draw(player_thirst)
#player_endergy_bar.draw(player_energy)
font=pygame.font.SysFont(None, 40)
drawText('Health:',font,screen,20,10,green)
drawText('Food:',font,screen,350,10,red)
drawText('Thirst:',font,screen,650,10,blue)
#drawText('Energy:', font, screen, 975, 10, yellow)
pygame.draw.rect(screen,forest,(50,675,100,100))
pygame.draw.rect(screen,forest,(175,675,100,100))
pygame.draw.rect(screen,forest,(300,675,100,100))
#player.check()
for item in player.inventory:
if item=='wood' and player.inventory['wood']>0:
wood=True
if wood:
screen.blit(wood_image,(62.5,687.5))
drawTextcenter(str(player.inventory['wood']),font,screen,100,735,black)
pygame.display.flip()
clock.tick(100)
if pause_back==True:
break
if pause_back==True:
break
screen.fill(black)
font=pygame.font.SysFont(None, 90)
text_width,text_height=font.size("Game Over")
drawText('Game Over', font, screen, (screen_width/2-text_width/2), (screen_height / 2-200),white)
font=pygame.font.SysFont(None, 40)
retry_button=Button(screen_width/2-125,650,250,50,white,black,'Retry')
retry_button.draw()
back_button.draw()
pygame.display.flip()
back=False
while not back:
for event in pygame.event.get():
if event.type==QUIT:
terminate()
elif event.type==pygame.MOUSEBUTTONDOWN:
if retry_button.check()==True:
back=True
if back_button.check()==True:
back=True
done2=True
done3=True
elif back_button.check()==True:
done2=True
done1=True
I haven't checked out your complete program because it's too much code, but I can see a mistake in the Player class. You're assigning the (self.rect.x,self.rect.y) (the top left) coordinates to the center of the new rect in the rotate method, but you have to assign the center coords of the previous rect.
self.rect = self.image.get_rect(center=(self.rect.x,self.rect.y))
Change the line above to:
self.rect = self.image.get_rect(center=self.rect.center)
Here's a minimal, complete example:
import math
import pygame as pg
class Player(pg.sprite.Sprite):
def __init__(self, pos):
super(Player,self).__init__()
x, y = pos
self.image = pg.Surface((50, 30), pg.SRCALPHA)
pg.draw.polygon(
self.image,
pg.Color('dodgerblue1'),
((1, 1), (49, 15), (1, 29)))
self.original_image = self.image
self.rect=self.image.get_rect(center=(x,y))
self.change_x=0
self.change_y=0
self.speed=7.5
self.inventory={'wood':0}
def changespeed(self,x,y):
self.change_x+=x
self.change_y+=y
def update(self):
self.rotate()
self.rect.x+=self.change_x
self.rect.y+=self.change_y
def rotate(self):
mouse_x, mouse_y = pg.mouse.get_pos()
rel_x, rel_y = mouse_x - self.rect.x, mouse_y -self.rect.y
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.image = pg.transform.rotate(self.original_image, angle)
# rect.x and .y are the topleft coords, but you need the to
# pass the center coordinates of the previous rect to the new one.
self.rect = self.image.get_rect(center=self.rect.center)
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
player = Player((300, 200))
all_sprites.add(player)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player.change_x = 4
elif event.key == pg.K_a:
player.change_x = -4
elif event.type == pg.KEYUP:
if event.key == pg.K_d:
player.change_x = 0
elif event.key == pg.K_a:
player.change_x = 0
all_sprites.update()
screen.fill((30, 30, 30))
all_sprites.draw(screen)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
The problem is caused by the camera. You have to apply the camera offset to the mouse position as well.
Here's a simple solution. First, pass the camera instead of the rect to the player.update method.
player.update(camera)
Pass it to the rotate method as well.
def update(self, camera):
self.rotate(camera)
self.rect.x += self.change_x
self.rect.y += self.change_y
rect = camera.apply(self)
screen.blit(self.image, rect)
In the rotate method you have to subtract the camera position from the mouse position to get the world coordinates.
def rotate(self, camera):
mouse_x, mouse_y = pygame.mouse.get_pos()
# Subtract the camera offset from the mouse position.
mouse_x -= camera.state.x
mouse_y -= camera.state.y
# Use the center coordinates of the rect.
rel_x, rel_y = mouse_x - self.rect.centerx, mouse_y -self.rect.centery
angle = -math.degrees(math.atan2(rel_y, rel_x))
self.image = pygame.transform.rotate(self.original_image, angle)
# Set the new center to the previous center coords.
self.rect = self.image.get_rect(center=self.rect.center)
I also had to modify the complex_camera function, because it should work with the center coordinates.
def complex_camera(camera, target_rect):
# The camera works with the center instead of
# the topleft coordinates now.
l, t = target_rect.center
_,_,w,h = camera
l,t,_,_ = -l+screen_width/2, -t+screen_height/2, w, h
l = min(0, l)
l = max(-(camera.width-screen_width), l)
t = max(-(camera.height-screen_height), t)
t = min(0, t)
return pygame.Rect(l, t, w, h)

Python sprite player control issue

I have a game that is supposed to allow two players to play. However, the second player does not move when the user pushes keys down.
(Plane2 is the second player)
class Plane(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("plane.gif")
self.image = self.image.convert()
self.rect = self.image.get_rect()
if not pygame.mixer:
print "problem with sound"
else:
pygame.mixer.init()
self.sndDing = pygame.mixer.Sound("ding.ogg")
self.sndCrash = pygame.mixer.Sound("planeCrash.ogg")
def update(self):
mousex, mousey = pygame.mouse.get_pos()
self.rect.center = (mousex, mousey)
class Plane2(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("plane2.gif")
self.image = self.image.convert()
self.rect = self.image.get_rect()
self.rect.centerx = 320
self.rect.centery = 240
def update(self):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.rect.centerx -= 8
if event.key == pygame.K_RIGHT:
self.rect.centerx += 8
if event.key == pygame.K_UP:
self.rect.centery += 8
if event.key == pygame.K_DOWN:
self.rect.centery -= 8
I tried moving the update function for Plane2 into the game loop, but that did not fix the problem.
def gameEndless():
pygame.display.set_caption("Mail Pilot!")
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0, 0))
plane = Plane()
island = Island()
ocean = Ocean()
scoreboard = Scoreboard()
oceanSprites = pygame.sprite.Group(ocean)
islandSprites = pygame.sprite.Group(island)
planeSprite = pygame.sprite.Group(plane)
scoreSprite = pygame.sprite.Group(scoreboard)
bulletSprites = pygame.sprite.Group()
enemySprites = pygame.sprite.Group()
bossSprite = pygame.sprite.Group()
bossWeaponSprites = pygame.sprite.Group()
if gameType == "coop":
scoreboard.lives = 10
player2 = Plane2()
planeSprite.add(player2)
I also tried making the second player its own sprite group, but that didn't help either.
class Plane2(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("plane2.gif")
self.image = self.image.convert()
self.rect = self.image.get_rect()
self.rect.centerx = 320
self.rect.centery = 240
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.rect.centery -= 8
if keys[pygame.K_DOWN]:
self.rect.centery += 8
if keys[pygame.K_LEFT]:
self.rect.centerx -= 8
if keys[pygame.K_RIGHT]:
self.rect.centerx += 8
fixed code
Create update() without for loop but with argument event
def update(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.rect.centerx -= 8
elif event.key == pygame.K_RIGHT:
self.rect.centerx += 8
elif event.key == pygame.K_UP:
self.rect.centery += 8
if event.key == pygame.K_DOWN
and in main loop use update() inside for loop
for event in pygame.event.get():
player1.update(event)
player2.update(event)
This way you can handle different events in update() - not only key events but also mouse events or user-defined events.
Some people use name handle_event for this function. And they use update() to change this elements which doesn't need events - ie. set next frame of animation.
# --- events ---
for event in pygame.event.get():
player1.handle_event(event)
player2.handle_event(event)
# --- updates ---
player1.update()
player2.update()

Powerup variables in a platform game

I've made a platform game that has powerups in it. One of the powerups is a lightning bolt that is meant to increase your speed. However, when I tell it to increase the speed it increases it but makes my player move without use of pressing down my arrow keys. Any help? And I know you can't see it but I have included player.update, etc. in main, but I didn't show it, so the code would be shortened.
Thanks
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width = 65, height = 35):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.hspeed,self.vspeed = 0,0
self.speed = 2
self.Jump = 10
self.images=[]
r0 = pygame.image.load("Images\Player\i1.png")
r1 = pygame.image.load("Images\Player\i2.png")
r2 = pygame.image.load("Images\Player\i3.png")
r3 = pygame.image.load("Images\Player\i4.png")
self.hurt = pygame.image.load("Images\Player\Hurt.png")
self.images.append(r0)
self.images.append(r1)
self.images.append(r2)
self.images.append(r3)
self.rotatedimages = []
rr0 = pygame.transform.flip(r0 ,True, False)
rr1 = pygame.transform.flip(r1 ,True, False)
rr2 = pygame.transform.flip(r2 ,True, False)
rr3 = pygame.transform.flip(r3 ,True, False)
self.rotatedimages.append(rr0)
self.rotatedimages.append(rr1)
self.rotatedimages.append(rr2)
self.rotatedimages.append(rr3)
self.deadimages = [self.hurt]
self.gravity = 0.35
self.index = 0
self.image = self.images[self.index]
self.rect = pygame.Rect(self.x,self.y,width,height)
self.TimeNum=0
self.TimeTarget=10
self.Timer = 0
def update(self, event = None):
self.calcgravity()
self.rect.x += self.hspeed
self.rect.y += self.vspeed
#Walking animation of animation when left or right key is pressed.
key = pygame.key.get_pressed()
if self.Timer >= 0:
if key[pygame.K_RIGHT]:
self.TimeNum+=1
if self.TimeNum == self.TimeTarget:
self.index +=1
if self.index >= len(self.images):
self.index = 0
self.image = self.images[self.index]
self.TimeNum = 0
if key[pygame.K_LEFT]:
self.TimeNum+=1
if self.TimeNum == self.TimeTarget:
self.index +=1
if self.index >= len(self.rotatedimages):
self.index = 0
self.image = self.rotatedimages[self.index]
self.TimeNum = 0
# if you go outside the boundaries of the game.
if player.rect.x < 0:
GameOver()
def move(self, hspeed, vspeed):
self.hspeed += hspeed
self.vspeed += vspeed
def Level1Coll(self,PowerUps):
PowerUpsCollision = pygame.sprite.spritecollide(self,PowerUps,True )
for speedboost in PowerUpsCollision:
self.speed = 3
def main()
GameExit = False
while GameExit==False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.move(-player.speed,0)
if event.key == pygame.K_RIGHT:
player.move(player.speed,0)
if event.key == pygame.K_UP:
player.move(0,-player.Jump)
JumpSound.play()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.move(player.speed,0)
if event.key == pygame.K_RIGHT:
player.move(-player.speed,0)
if event.key == pygame.K_UP:
player.move(0,0)
You set self.speed to be equal to 3, which usually means that the sprite will move on its own with a speed of 3. Instead create a new variable:
extra_speed = 0
and apply that to the increase of speed of the sprite:
self.rect.y += (self.vspeed + extra_speed)
Now when the sprite doesn't have the power-up, nothing changes as the speed increases by nothing. But when the sprite does get the powerup, simply change extra_speed to 3 and reset back to 0 when the sprite is finished with the power-up. To meet the problem of instant running, use another variable to determine when to run and use it before you check to run.
running = False
#A few lines later into your update function
if running:
self.rect.x += self.hspeed
self.rect.y += (self.vspeed + extra_speed)
The above code means that if running is True, then move the sprite appropriately. Otherwise, don't move the sprite.