Cant move sprite on screen [duplicate] - python

This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
Closed 1 year ago.
The sprite is just stuck in the top left corner. It moves sligthly when pressing "wasd".
I am trying to make a simple clone of Mayhem/xPilot. A 2 player game where there are 2 rockets that can shoot eachother down.
I am fairly new to coding and python, I would be gratefull if you could ELI5.
Has anyone else had this problem?
import pygame as pg
import sys
x, y = 0, 0
class Rocket(pg.sprite.Sprite):
def __init__(self, picture_path, x, y):
super().__init__()
self.image = pg.image.load(picture_path)
self.image = pg.transform.scale(self.image, (120, 100))
self.rect = self.image.get_rect()
self.rect.x = 900
self.rect.y = 400
self.pressed_w = False
self.pressed_a = False
self.pressed_s = False
self.pressed_d = False
self.speed = 3
self.gravity = False
def update(self):
self.rect.x = 0
self.rect.y = 0
if self.pressed_a and self.rect.left > 0:
self.rect.x = self.speed
if self.pressed_d and self.rect.right < width:
self.rect.x = self.speed
if self.pressed_s and self.rect.bottom < height:
self.rect.y = self.speed
if self.pressed_w and self.rect.top > 0:
self.rect.y = -self.speed
if self.gravity and self.rect.bottom < height:
self.rect.y = self.speed
self.rect.x += x
self.rect.y += y
pg.init()
clock = pg.time.Clock()
width = 1920
height = 1080
screen = pg.display.set_mode((width, height))
background = pg.image.load("bg.jpg")
#rocket
player_rect = Rocket("rocket.png", x, y)
rocket_group = pg.sprite.Group()
rocket_group.add(player_rect)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_w:
player_rect.pressed_w = True
player_rect.gravity = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_s:
player_rect.pressed_s = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player_rect.pressed_d = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
player_rect.pressed_a = True
if event.type == pg.KEYUP:
if event.key == pg.K_w:
player_rect.pressed_w = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_s:
player_rect.pressed_s = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_d:
player_rect.pressed_d = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_a:
player_rect.pressed_a = False
player_rect.gravity = True
pg.display.flip()
screen.blit(background, (0, 0))
rocket_group.draw(screen)
rocket_group.update()
clock.tick(120)

The problem is in the update method. The method has to change the coordinates of the rect attribute. However, your method continuously sets self.rect.x = 0 and self.rect.y = 0.
Change update:
class Rocket(pg.sprite.Sprite):
# [...]
def update(self):
if self.pressed_a:
self.rect.x -= self.speed
if self.pressed_d
self.rect.x += self.speed
if self.pressed_w
self.rect.y -= self.speed
if self.pressed_s
self.rect.y += self.speed
if self.gravity
self.rect.y += self.speed
if self.rect.left < 0: self.rect.left = 0
if self.rect.right > width: self.rect.right = width
if self.rect.top < 0: self.rect.top = 0
if self.rect.bottom > height: self.rect.bottom = height

Related

How to use groupcollide?

So I've been wondering how to use the pygame groupcollide. And I'm utterly stumped right now. As I am using collide_rect and it is fine. But for groupcollide I can't seem to figure out how to call the properties of the item inside of that group. And I can't do collide rect because there's going to be a lot of bullets.
def check_blast_collisions(player,bullet):
hits = pg.sprite.groupcollide(player,bullet,False,True)
for hit in hits:
print (hits)
if hit.vx == 20:
player.vx += 40
elif hit.vx == -20:
player.vx += -40
Here is a snippet of where I'm trying to use groupcollide.
After I made this function, the bullets don't even show up. (The bullets are supposed to be called blasts but I forgot about it in this function.)
import pygame as pg
#settings
CAPTION = "Knockback Arena"
resolution = 1600,900
WIDTH = resolution[0]
HEIGHT = resolution[1]
FPS = 60
player_jump_height = 30
player_max_fall_speed = 30
player_fall_speed_increase = 2
player_lives = 5
shoot_cooldown = 500
#initialize pygame
pg.init()
pg.mixer.init()
pg.font.init
screen = pg.display.set_mode(resolution)
pg.display.set_caption(CAPTION)
clock = pg.time.Clock()
#sprites
class Platform(pg.sprite.Sprite):
def __init__(self,x,y,width,height,r,g,b):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((width,height))
self.image.fill((r,g,b))
self.rect = self.image.get_rect()
self.rect.center = (x,y)
class Player(pg.sprite.Sprite):
def __init__(self,r,g,b,x,y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((40, 100))
self.image.fill((r,g,b))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.startx = x
self.starty = y
self.vx = 0
self.vy = 5
self.vy_max = player_max_fall_speed
self.vy_increase = player_fall_speed_increase
self.lives = player_lives
self.last_shot = 0
self.facing_right = False
self.facing_left = False
def update(self):
self.rect.x += self.vx
self.rect.y += self.vy
if self.vy >= self.vy_max:
self.vy = self.vy_max
self.vy_increase = 0
if self.vy < self.vy_max:
self.vy_increase = player_fall_speed_increase
if self.rect.bottom < HEIGHT:
self.vy += self.vy_increase
if self.rect.top >= HEIGHT:
self.rect.x = self.startx
self.rect.y = self.starty
self.lives -= 1
if self.lives <= 0:
self.kill()
if self.rect.right >= WIDTH:
self.rect.right = WIDTH
self.vx = 0
if self.rect.left <= 0:
self.rect.left = 0
self.vx = 0
def jump(self):
if self.rect.bottom >= main_platform.rect.top:
self.vy -= player_jump_height
if self.rect.bottom >= HEIGHT:
self.vy -= player_jump_height
def shoot(self):
if pg.time.get_ticks() - self.last_shot >= shoot_cooldown:
if self.facing_left == True:
return "shoot_left"
elif self.facing_right == True:
return "shoot_right"
else:
return "cd_not_done"
class Blast(pg.sprite.Sprite):
def __init__(self,player,direction):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((20,10))
self.image.fill((0,255,255))
self.rect = self.image.get_rect()
self.rect.center = (player.rect.center)
self.direction = direction
if self.direction == 0:
self.vx = -20
elif self.direction == 1:
self.vx = 20
def update(self):
self.rect.x += self.vx
if self.rect.right < 0:
self.kill()
if self.rect.left > WIDTH:
self.kill()
#functions
def check_for_collisions(player,platform):
hits = pg.sprite.collide_rect(player,platform)
if hits:
if hits and player.vy > 0:
player.rect.bottom = platform.rect.top
player.vy = 0
def check_blast_collisions(player,bullet):
hits = pg.sprite.groupcollide(player,bullet,False,True)
for hit in hits:
print (hits)
if hit.vx == 20:
player.vx += 40
elif hit.vx == -20:
player.vx += -40
font = pg.font.Font('font/Roboto-Light.ttf', 30)
all_sprites = pg.sprite.Group()
players = pg.sprite.Group()
platforms = pg.sprite.Group()
blasts = pg.sprite.Group()
main_platform = Platform(WIDTH/2,650,1000,100,0,200,0)
player_1 = Player(0,0,255,WIDTH/2 + -100,200)
player_2 = Player(255,0,0,WIDTH/2 + 100,200)
platforms.add(main_platform)
players.add(player_1)
players.add(player_2)
all_sprites.add(player_1)
all_sprites.add(player_2)
all_sprites.add(main_platform)
menu = True
run = True
while run:
#check for closing window
for event in pg.event.get():
if event.type == pg.KEYDOWN:
if event.key == pg.K_w:
player_1.jump()
if event.key == pg.K_a:
player_1.vx = -10
player_1.facing_left = True
player_1.facing_right = False
elif event.key == pg.K_d:
player_1.vx = 10
player_1.facing_right = True
player_1.facing_left = False
if event.key == pg.K_UP:
player_2.jump()
if event.key == pg.K_LEFT:
player_2.vx = -10
player_2.facing_left = True
player_2.facing_right = False
elif event.key == pg.K_RIGHT:
player_2.vx = 10
player_2.facing_right = True
player_2.facing_left = False
if event.key == pg.K_j:
if player_1.shoot() == "shoot_left":
b = Blast(player_1,0)
all_sprites.add(b)
blasts.add(b)
elif player_1.shoot() == "shoot_right":
b = Blast(player_1,1)
all_sprites.add(b)
blasts.add(b)
if event.key == pg.K_KP1:
if player_2.shoot() == "shoot_left":
b = Blast(player_2,0)
all_sprites.add(b)
blasts.add(b)
elif player_2.shoot() == "shoot_right":
b = Blast(player_2,1)
all_sprites.add(b)
blasts.add(b)
elif event.type == pg.KEYUP:
if event.key == pg.K_a:
player_1.vx = 0
if event.key == pg.K_d:
player_1.vx = 0
if event.key == pg.K_LEFT:
player_2.vx = 0
if event.key == pg.K_RIGHT:
player_2.vx = 0
if event.type == pg.QUIT:
pg.quit()
exit()
#update all sprites
all_sprites.update()
check_for_collisions(player_1,main_platform)
check_for_collisions(player_2,main_platform)
check_blast_collisions(players,blasts)
#draw sprites
screen.fill((255,255,255))
all_sprites.draw(screen)
#draw other stuff
p1lives = font.render(str(player_1.lives), False, (0,0,255))
screen.blit(p1lives,(20,50))
p2lives = font.render(str(player_2.lives), False, (255,0,0))
screen.blit(p2lives,(1580,50))
clock.tick(FPS)
pg.display.flip()
Here is the entire code.
Any help is much appreciated. Thanks.
You cannot use pygame.sprite.groupcollide() here, because the bullets collide with the player that shoots the bullets.
You have to use pygame.sprite.spritecollide(), with one player and the bullets of the opponent. Call it once for each player.

How to i make an sprite rotate smoothly

I neew help with making my sprites rotate smoothly.
Right now i have to press the botton multiple times to rotate the sprites.
When I rotate the sprites it also warps the sprites in a weird way.
if you go down to the main loop you can see how i tried to implement the rotation in my code right now.
I am new to programming so i would appreciate if anyone could ELI5.
import pygame as pg
import sys
x, y = 0, 0
class Rocket(pg.sprite.Sprite):
def __init__(self, picture_path, x, y):
super().__init__()
self.image = pg.image.load(picture_path)
self.image = pg.transform.scale(self.image, (120, 100))
self.angle_change = 0
self.angle = 90 + self.angle_change
self.image = pg.transform.rotate(self.image, self.angle)
self.rect = self.image.get_rect()
self.rect.x = 900
self.rect.y = 400
self.pressed_w = False
self.pressed_a = False
self.pressed_s = False
self.pressed_d = False
self.speed = 3
self.gravity = False
def update(self):
if self.pressed_a:
self.rect.x -= self.speed
if self.pressed_d:
self.rect.x += self.speed
if self.pressed_w:
self.rect.y -= self.speed
if self.pressed_s:
self.angle_change += 3
if self.gravity:
self.rect.y += self.speed
if self.rect.left < 0: self.rect.left = 0
if self.rect.right > width: self.rect.right = width
if self.rect.top < 0: self.rect.top = 0
if self.rect.bottom > height: self.rect.bottom = height
class Rocket1(pg.sprite.Sprite):
def __init__(self, picture_path, x, y):
super().__init__()
self.image = pg.image.load(picture_path)
self.image = pg.transform.scale(self.image, (120, 100))
self.rotate = 90
self.image = pg.transform.rotate(self.image, self.rotate)
self.rect = self.image.get_rect()
self.rect.x = 900
self.rect.y = 400
self.pressed_up = False
self.pressed_left = False
self.pressed_down = False
self.pressed_right = False
self.speed = 3
self.gravity = False
def update(self):
if self.pressed_left:
self.rect.x -= self.speed
if self.pressed_right:
self.rect.x += self.speed
if self.pressed_up:
self.rect.y -= self.speed
if self.pressed_down:
self.rect.y += self.speed
if self.gravity:
self.rect.y += self.speed
if self.rect.left < 0: self.rect.left = 0
if self.rect.right > width: self.rect.right = width
if self.rect.top < 0: self.rect.top = 0
if self.rect.bottom > height: self.rect.bottom = height
pg.init()
clock = pg.time.Clock()
width = 1920
height = 1080
screen = pg.display.set_mode((width, height))
background = pg.image.load("bg.jpg")
#rocket
player_rect = Rocket("rocket.png", x, y)
player_rect1 = Rocket1("rocketflames.png", x, y)
rocket_group = pg.sprite.Group()
rocket_group.add(player_rect,player_rect1)
while True:
rocket_rotate = 0
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_w:
player_rect.pressed_w = True
player_rect.gravity = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_s:
rocket_rotate += 1
for rocket in rocket_group:
rocket.image = pg.transform.rotate(rocket.image, rocket_rotate)
if event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player_rect.pressed_d = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
player_rect.pressed_a = True
if event.type == pg.KEYUP:
if event.key == pg.K_w:
player_rect.pressed_w = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_s:
rocket_rotate += 0
for rocket in rocket_group:
rocket.image = pg.transform.rotate(rocket.image, rocket_rotate)
if event.type == pg.KEYUP:
if event.key == pg.K_d:
player_rect.pressed_d = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_a:
player_rect.pressed_a = False
player_rect.gravity = True
###
if event.type == pg.KEYDOWN:
if event.key == pg.K_UP:
player_rect1.pressed_up = True
player_rect1.gravity = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_DOWN:
player_rect1.pressed_down = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_RIGHT:
player_rect1.pressed_right = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_LEFT:
player_rect1.pressed_left = True
if event.type == pg.KEYUP:
if event.key == pg.K_UP:
player_rect1.pressed_up = False
player_rect1.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_DOWN:
player_rect1.pressed_down = False
player_rect1.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_RIGHT:
player_rect1.pressed_right = False
player_rect1.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_LEFT:
player_rect1.pressed_left = False
player_rect1.gravity = True
pg.display.flip()
screen.blit(background, (0, 0))
rocket_group.draw(screen)
rocket_group.update()
clock.tick(120)
You have to use the pygame.key.get_pressed() instead of the keybord events.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
pygame.key.get_pressed() returns a list with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
Additionally I recommend reading How do I rotate an image around its center using PyGame?.

Pygame Movement of Flag and Character With Walls

I am making a capture the flag type game. From the code below, I have the fundamentals set up. However, I don't know how I stop the flag from moving when the character hits a wall. Can anyone help me with this? As you can see if you run the code, the flag is effectively picked up by the character and carried but the flag will not stop if the character hits a wall. I want the flag to stay on the right side of the character as well. Thanks for any help. (CODE HAS BEEN UPDATED SINCE ORIGINAL POST)
import pygame
def start():
pygame.init()
BLUE = (0, 0, 128)
RED = (204, 0, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
screen = pygame.display.set_mode((1920,1080), flags=pygame.FULLSCREEN)
pygame.display.set_caption("Recovery")
clock = pygame.time.Clock()
bigJoe = pygame.image.load("bigJoe.png")
characterSelected = bigJoe
game(BLACK, WHITE, BLUE, RED, screen, clock, characterSelected, bigJoe)
def game(BLACK, WHITE, BLUE, RED, screen, clock, characterSelected, bigJoe):
if characterSelected == bigJoe:
gameCharacter = "gameJoe.png"
all_sprite_list = pygame.sprite.Group()
playerList = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
flagList = pygame.sprite.Group()
playerFlag = pygame.sprite.Group()
flag = Flag(1810,540)
flagList.add(flag)
'''Design of Map Below'''
topWall = Wall(0, 0, 1920, 5, BLUE)
bottomWall = Wall(0, 1075, 1920, 5, BLUE)
leftWall = Wall(0, 0, 5, 1080, BLUE)
rightWall = Wall(1915, 0, 5, 1080, BLUE)
baseWall1 = Wall(5, 300, 150, 75, WHITE)
baseWall2 = Wall(5, 375, 100, 330, WHITE)
baseWall3 = Wall(5, 705, 150, 75, WHITE)
baseSquare = Wall(30, 530, 40, 40, RED)
wall1 = Wall(400, 400, 200, 300, RED)
wall_list.add(topWall, bottomWall, leftWall, rightWall, baseWall1, wall1, baseWall2, baseWall3)
all_sprite_list.add(topWall, bottomWall, leftWall, rightWall, baseWall1, wall1, baseWall2, baseWall3, baseSquare, flag)
'''Adding Character to Game'''
player = Player(110, 550, gameCharacter)
flag.player = playerFlag
player.wall = wall_list
all_sprite_list.add(player)
playerFlag.add(player, flag)
playerList.add(player)
flag.player = player
flag.carried = playerFlag
flag.walls = wall_list
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.changespeed(-3, 0)
flag.moveFlag(-3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(3, 0)
flag.moveFlag(3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, -3)
flag.moveFlag(0, -3,)
elif event.key == pygame.K_DOWN:
player.changespeed(0, 3)
flag.moveFlag(0, 3)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player.changespeed(3, 0)
flag.moveFlag(3, 0)
elif event.key == pygame.K_RIGHT:
player.changespeed(-3, 0)
flag.moveFlag(-3, 0)
elif event.key == pygame.K_UP:
player.changespeed(0, 3)
flag.moveFlag(0, 3)
elif event.key == pygame.K_DOWN:
player.changespeed(0, -3)
flag.moveFlag(0, -3)
all_sprite_list.update()
screen.fill(BLACK)
all_sprite_list.draw(screen)
pygame.display.flip()
clock.tick(75)
start()
On a separate file
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, gameCharacter):
super().__init__()
self.image = pygame.image.load(gameCharacter)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.change_x = 0
self.change_y = 0
self.wall = None
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
wallHitList = pygame.sprite.spritecollide(self, self.wall, False)
for wall in wallHitList:
if self.change_x > 0:
self.rect.right = wall.rect.left
else:
self.rect.left = wall.rect.right
self.rect.y += self.change_y
wallHitList = pygame.sprite.spritecollide(self, self.wall, False)
for wall in wallHitList:
if self.change_y > 0:
self.rect.bottom = wall.rect.top
else:
self.rect.top = wall.rect.bottom
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height,color):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Flag(pygame.sprite.Sprite):
def __init__(self, x, y,):
super().__init__()
self.image = pygame.image.load("flag.png")
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.change_x = 0
self.change_y = 0
def moveFlag(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
hit = False
allowMove = True
flagCharacterList = pygame.sprite.spritecollide(self, self.carried, False)
for i in flagCharacterList:
if len(flagCharacterList) == 2:
hit = True
else:
hit = False
block_hit_list = pygame.sprite.groupcollide(self.walls, self.carried, False, False)
for block in block_hit_list:
if len(block_hit_list) == 1:
allowMove = False
else:
allowMove = True
if hit and allowMove:
self.rect.x += self.change_x
self.rect.y += self.change_y
The flag doesn't move bit itself. bit the player carries the flag. Possibly the player can carry more than 1 flag.
Remove the collision detection from the method Flag.update:
class Flag(pygame.sprite.Sprite):
def __init__(self, x, y,):
super().__init__()
#self.image = pygame.image.load("flag.png")
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
self.change_x = 0
self.change_y = 0
def moveFlag(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
Add an attribute self.flags to the player and move all the flags contained in the list by the same amount as the player:
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, gameCharacter):
# [...]
self.flags = []
# [...]
def update(self):
current_pos = (self.rect.x, self.rect.y)
self.rect.x += self.change_x
wallHitList = pygame.sprite.spritecollide(self, self.wall, False)
for wall in wallHitList:
if self.change_x > 0:
self.rect.right = wall.rect.left
else:
self.rect.left = wall.rect.right
self.rect.y += self.change_y
wallHitList = pygame.sprite.spritecollide(self, self.wall, False)
for wall in wallHitList:
if self.change_y > 0:
self.rect.bottom = wall.rect.top
else:
self.rect.top = wall.rect.bottom
for flag in self.flags:
flag.rect.x += self.rect.x - current_pos[0]
flag.rect.y += self.rect.y - current_pos[1]
flag.move() is not needed any more. But if the player hits the flag, then the flag is add player.flags. That caused, that the plyer carries the flag:
def game(BLACK, WHITE, BLUE, RED, screen, clock, characterSelected, bigJoe):
# [...]
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT: player.changespeed(-3, 0)
elif event.key == pygame.K_RIGHT: player.changespeed(3, 0)
elif event.key == pygame.K_UP: player.changespeed(0, -3)
elif event.key == pygame.K_DOWN: player.changespeed(0, 3)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT: player.changespeed(3, 0)
elif event.key == pygame.K_RIGHT: player.changespeed(-3, 0)
elif event.key == pygame.K_UP: player.changespeed(0, 3)
elif event.key == pygame.K_DOWN: player.changespeed(0, -3)
if flag not in player.flags:
if pygame.sprite.collide_rect(flag, player):
player.flags.append(flag)
flag.rect.left = player.rect.right
# [...]

Multiple sprite collision detections

Ok, so I have been trying to figure out how to set this up and can't get it working properly. I'm trying to get the functionality similar to the moving logs in the game Frogger if you are familiar with it. So far what I have works with the collision detection for only one pygame.sprite.Group()
import pygame
import os
import random
os.environ['SDL_VIDEO_CENTERED'] = '1'
WIDTH = 480
HEIGHT = 720
FPS = 60
# Moving Object spacing setup first row
INSTANCE_COUNT = 0
BOX_WIDTH = 30
SPACING = 120
# object speed
pos_objspeed = 1
neg_objspeed = -1
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((30, 30))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 96
self.speedx = 0
self.speedy = 0
class MovingObj_Test(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((90, 30))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = (INSTANCE_COUNT * (SPACING+ BOX_WIDTH))
#self.rect.x = random.randrange(WIDTH)
self.rect.bottom = 384
self.speedx = pos_objspeed
def update(self):
self.rect.x += self.speedx
if self.rect.x >= 480:
self.rect.x = -30
self.rect.bottom = 384
self.speedx = pos_objspeed
class MovingObj_TestTwo(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((90, 30))
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = (INSTANCE_COUNT * (SPACING+ BOX_WIDTH))
#self.rect.x = random.randrange(WIDTH)
self.rect.bottom = 336
self.speedx = neg_objspeed
def update(self):
self.rect.x += self.speedx
if self.rect.x >= 480:
self.rect.x = -30
self.rect.bottom = 336
self.speedx = neg_objspeed
all_sprites = pygame.sprite.Group()
movingobj_l = pygame.sprite.Group()
movingobj_r = pygame.sprite.Group()
for i in range (3):
INSTANCE_COUNT = i + 1
obj1 = MovingObj_Test()
all_sprites.add(obj1)
movingobj_l.add(obj1)
for i in range (3):
INSTANCE_COUNT = i + 1
obj2 = MovingObj_TestTwo()
all_sprites.add(obj2)
movingobj_r.add(obj2)
player = Player()
all_sprites.add(player)
running = True
onLogLeft = False
onLogRight = False
groundSpd = 48
while running:
clock.tick(FPS)
hitsleft = pygame.sprite.spritecollide(player, movingobj_l, False, pygame.sprite.collide_rect)
for hit in hitsleft:
player.speedx = pos_objspeed
player.speedy = 0
onLogLeft = True
if len(hitsleft) == 0:
onLogLeft = False
player.speedx = 0
player.speedy = 0
hitsright = pygame.sprite.spritecollide(player, movingobj_r, False, pygame.sprite.collide_rect)
for hit in hitsright:
player.speedx = neg_objspeed
player.speedy = 0
onLogRight = True
if len(hitsright) == 0:
onLogRight = False
player.speedx = 0
player.speedy = 0
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.speedx = -groundSpd
if event.key == pygame.K_RIGHT:
player.speedx = groundSpd
if event.key == pygame.K_UP:
player.speedy = -groundSpd
if event.key == pygame.K_DOWN:
player.speedy = groundSpd
if event.type == pygame.KEYUP and onLogLeft == False and onLogRight == False:
if event.key == pygame.K_LEFT:
player.speedx = 0
if event.key == pygame.K_RIGHT:
player.speedx = 0
if event.key == pygame.K_UP:
player.speedy = 0
if event.key == pygame.K_DOWN:
player.speedy = 0
if onLogLeft == False and onLogRight == False and player.rect.bottom <= 384:
running = False
player.rect.x += player.speedx
player.rect.y += player.speedy
if event.type == pygame.QUIT:
running = False
#player.rect.x += player.speedx
#player.rect.y += player.speedy
all_sprites.update()
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
quit()
Ok so in my code the
hitsright = pygame.sprite.spritecollide(player, movingobj_r, False, pygame.sprite.collide_rect)
checks the collision and updates the players speed how I'm expecting it to but, the
hitsleft = pygame.sprite.spritecollide(player, movingobj_l, False, pygame.sprite.collide_rect)
is not doing the same.
I'm confused as to why this is if anyone has any ideas. Also how could I fix it to work for both?
The code for left and right behaves different, because if a collision with hitsleft is detected, the player.speedx is set:
for hit in hitsleft:
player.speedx = pos_objspeed
But if there is a collision with hitsleft there it no collision with hitsright and player.speedx is reset immediately:
if len(hitsright) == 0:
onLogRight = False
player.speedx = 0
You have to set player.speedx dependent on both conditions (e.g. in a if - elif - else statement):
while running:
# [...]
hitsleft = pygame.sprite.spritecollide(player, movingobj_l, False, pygame.sprite.collide_rect)
onLogLeft = any(hitsleft)
hitsright = pygame.sprite.spritecollide(player, movingobj_r, False, pygame.sprite.collide_rect)
onLogRight = any(hitsright)
player.speedy = 0
if onLogLeft:
player.speedx = pos_objspeed
elif onLogRight:
player.speedx = neg_objspeed
else:
player.speedx = 0

Space Invaders - Pygame - Make enemy shoot

I am making the game Space Invaders with Pygame and I am trying to make the enemy shoot, firstly by pressing the TAB button. When I get this working I will let the enemy shoot randomly. At this moment I cannot see the BulletEnemy and when I press TAB it does not shoot anything. What am I doing wrong?
Thanks.
import pygame, sys
from pygame.locals import *
import random
screenWidth = 800
screenHeight = 600
FPS = 60
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()
shipWidth = 78
#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)
def app_quit():
pygame.quit()
sys.exit("System exit.")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("spaceship7.png").convert()
self.image.set_colorkey(white)#make white transparant
self.rect = self.image.get_rect()
self.rect.centerx = screenWidth / 2
self.rect.bottom = screenHeight - 10
self.speedx = 0
def update(self):
self.speedx = 0
if event.type == KEYDOWN and event.key == K_LEFT:
self.speedx = -2
elif event.type == KEYDOWN and event.key == K_RIGHT:
self.speedx = 2
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.right = screenWidth
if self.rect.left < 0:
self.rect.left = 0
def shootPlayer(self):
bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
allSprites.add(bulletPlayer)
bulletsPlayer.add(bulletPlayer)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("enemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = random.randrange(0, 200)
self.speedx = random.randrange(1,2)
def update(self):
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.x = 50
self.rect.y = random.randrange(0, 250)
self.speedx = random.randrange(1,3)
if self.rect.x > screenWidth:
self.kill()
def shootEnemy(self):
bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
allSprites.add(bulletEnemy)
bulletsEnemy.add(bulletEnemy)
class BulletPlayer(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class BulletEnemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bulletenemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom > screenHeight:
self.kill()
class Wall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("wall.png").convert()
self.rect = self.image.get_rect()
self.rect.center = 100, 300
allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)
for i in range(1):
e = Enemy()
allSprites.add(e)
enemy.add(e)
running = True
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
running = False
app_quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_TAB:
enemy.shootEnemy()
allSprites.update()
screen.fill(black)
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
Spaceship
Enemy
Wall
BulletPlayer
BulletEnemy
The problem is here:
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_TAB:
enemy.shootEnemy()
Once event.type == KEYDOWN one time, the second evaluation is ignored.
Try this
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
elif event.key == pygame.K_TAB:
enemy.shootEnemy()
This checks for a KEYDOWN event, then for the specific key that's pressed.

Categories