I have two ships and a set of pills that should continuously rain down from the top of the screen. When my ships collides with a pill, the pills should disappear but they don't. The pills disappear further down the screen about 50 pixels from y=win_height.
After running some tests, I can say that the pills are detected by 'collidesprite' and they are removed from the group 'pillGroup', however they are still being blitted to the screen and pass right through the ship. I want the pills to disappear immediately.
Here is an edited version of my algorithm:
pillGroup = pygame.sprite.Group()
# Gameplay
while play:
# Checks if window exit button pressed
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
# Keypresses
pill = Pill()
pill.add(pillGroup)
pillGroup.update()
pygame.sprite.spritecollide(ship_right, pillGroup, True)
# Print background
screen.fill(WHITE)
pillGroup.draw(screen)
Here is the complete version of the game. Take note that I increased the ships sizes to fill the screen. Try moving the ships to the top of the screen and you'll see that the pills disappear when they get to the bottom of the screen rather than when first touching the ships.
import sys, pygame, os, random
# Force static position of screen
os.environ['SDL_VIDEO_CENTERED'] = '1'
# Runs imported module
pygame.init()
# Constants
LEFT = 'left'
RIGHT = 'right'
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
SHIP_WIDTH = 600
SHIP_HEIGHT = 10
PILL_WIDTH = 5
PILL_HEIGHT = 20
WIN_W = 1200
WIN_H = 570
RANDOM_PILL = [700 , 658 , 58 , 795 , 687 , 308 , 785 , 828 , 670 , 187 , 603 , 994 , 990 , 923 , 523 , 849 , 229 , 804 , 618 , 733 , 614 , 209 , 941 , 872 , 528 , 438 , 793 , 879 , 327 , 539 , 571 , 886 , 452 , 627 , 267 , 662 , 655 , 772 , 904 , 769 , 197 , 1009 , 281 , 867 , 31 , 30 , 545 , 519 , 866 , 66 , 202 , 580 , 1172 , 792 , 131 , 980 , 83 , 999 , 120 , 916 , 956 , 1166 , 391 , 1127 , 675 , 868 , 851 , 725 , 869 , 702 , 767 , 692 , 695 , 564 , 978 , 834 , 866 , 340 , 78 , 396 , 195 , 480 , 1113 , 223 , 725 , 36 , 660 , 973 , 597 , 734 , 1129 , 91 , 720 , 610 , 1020 , 861 , 887 , 350 , 235 , 39 , 282 , 698 , 856 , 236 , 1077 , 191 , 1147 , 605 , 825 , 1179 , 978 , 320 , 985 , 125 , 475 , 1009 , 166 , 528 , 100 , 455 , 485 , 1066 , 38 , 408 , 235 , 410 , 1064 , 57 , 653 , 177 , 836 , 228 , 224 , 534 , 789 , 1129 , 370 , 1008 , 529 , 62 , 752 , 654 , 785 , 916 , 281 , 235 , 921 , 945 , 727 , 1138 , 585 , 168 , 1048 , 708 , 144 , 968 , 974 , 1118 , 555 , 251 , 1135 , 805 , 1121 , 360 , 968 , 228 , 988 , 49 , 536 , 117 , 726 , 65 , 177 , 925 , 923 , 239 , 1117 , 678 , 329 , 180 , 1019 , 47 , 147 , 235 , 279 , 841 , 383 , 211 , 971 , 309 , 452 , 335 , 1121 , 1091 , 247 , 790 , 418 , 961 , 323 , 458 , 970 , 752 , 888 , 719 , 318 , 930 , 797 , 537 , 1006 , 696 , 309 , 1102 , 728 , 497 , 553 , 266 , 67 , 504 , 763 , 158 , 944 , 108 , 553 , 517 , 470 , 1016 , 93 , 243 , 570 , 136 , 67 , 893 , 241 , 571 , 515 , 616 , 986 , 561 , 148 , 351 , 78 , 862 , 685 , 286 , 414 , 756 , 730 , 381 , 141 , 896]
PILL_COUNT = 0
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Ship():
def __init__(self, x, y):
self.x = x
self.y = y
self.width = SHIP_WIDTH
self.height = SHIP_HEIGHT
self.speed = 5
self.density = 0
self.ship = pygame.Surface((self.width, self.height)).convert()
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
self.up = self.down = self.left = self.right= False
def update(self, which_ship, left, right, down, up, pillGroup):
# Adjust speed
if up or down or left or right:
if up:
self.y -= self.speed
if down:
self.y += self.speed
if left:
self.x -= self.speed
if right:
self.x += self.speed
# Ship movement
if self.y < 0:
self.y = 0
if self.y > WIN_H - self.height:
self.y = WIN_H - self.height
if which_ship == 'left':
if self.x < 0:
self.x = 0
if self.x > WIN_W/2 - self.width:
self.x = WIN_W/2 - self.width
elif which_ship == 'right':
if self.x < WIN_W/2:
self.x = WIN_W/2
if self.x > WIN_W - self.width:
self.x = WIN_W - self.width
class Pill(Entity):
def __init__(self, density):
Entity.__init__(self)
global PILL_COUNT
self.speed = 3
self.density = density
self.image = pygame.Surface((PILL_WIDTH, PILL_HEIGHT)).convert()
self.rect = self.image.get_rect()
self.rect = self.rect.move(RANDOM_PILL[PILL_COUNT], -PILL_HEIGHT) #RANDOM_PILL[PILL_COUNT], PILL_HEIGHT)
PILL_COUNT += 1
def restart(self):
pass
def update(self):
if self.rect.y > WIN_H:
del self
else:
self.rect = self.rect.move((0, self.speed))
def genRandom():
for i in range(250):
print random.randrange(PILL_WIDTH, WIN_W - PILL_WIDTH), ", ",
def main():
fps = 60
pygame.display.set_caption('Pong')
screen = pygame.display.set_mode((WIN_W, WIN_H), pygame.SRCALPHA)
ship_left = Ship((WIN_W/4) - (SHIP_WIDTH/2), WIN_H - (SHIP_HEIGHT * 4))
ship_right = Ship((WIN_W/1.3) - (SHIP_WIDTH/2), WIN_H - (SHIP_HEIGHT * 4))
pillGroup = pygame.sprite.Group()
pillAlter = 0
vert_partition = pygame.Surface((1, WIN_H))
hori_partition = pygame.Surface((WIN_W, 1))
lLeft = lRight = lUp = lDown = False
rLeft = rRight = rUp = rDown = False
clock = pygame.time.Clock()
play = True
#ranList = genRandom()
# Gameplay
while play:
# Checks if window exit button pressed
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
# Keypresses
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == pygame.K_a:
lLeft = True
lRight = False
if event.key == pygame.K_d:
lLeft = False
lRight = True
if event.key == pygame.K_w:
lDown = False
lUp = True
if event.key == pygame.K_s:
lDown = True
lUp = False
if event.key == pygame.K_LEFT:
rLeft = True
rRight = False
if event.key == pygame.K_RIGHT:
rLeft = False
rRight = True
if event.key == pygame.K_UP:
rDown = False
rUp = True
if event.key == pygame.K_DOWN:
rUp = False
rDown = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a:
lLeft = False
if event.key == pygame.K_d:
lRight = False
if event.key == pygame.K_w:
lUp = False
if event.key == pygame.K_s:
lDown = False
if event.key == pygame.K_RIGHT:
rRight = False
if event.key == pygame.K_LEFT:
rLeft = False
if event.key == pygame.K_UP:
rUp = False
if event.key == pygame.K_DOWN:
rDown = False
if PILL_COUNT < 250 and pillAlter % 10 == 0:
pill = Pill(random.randrange(1,4))
pillGroup.add(pill)
pillAlter += 1
ship_left.update('left', lLeft, lRight, lDown, lUp, pillGroup)
ship_right.update('right', rLeft, rRight, rDown, rUp, pillGroup)
pillGroup.update()
pill_hit_list = pygame.sprite.spritecollide(ship_right, pillGroup, True)
pill_hit_list = pygame.sprite.spritecollide(ship_left, pillGroup, True)
# Print background
screen.fill(WHITE)
print pillGroup.draw(screen)
screen.blit(ship_left.ship, (ship_left.x, ship_left.y))
screen.blit(ship_right.ship, (ship_right.x, ship_right.y))
screen.blit(vert_partition, (WIN_W/2, WIN_H/15))
screen.blit(hori_partition, (0, WIN_H/15))
# Limits frames per iteration of while loop
clock.tick(fps)
# Writes to main surface
pygame.display.flip()
if __name__ == "__main__":
main()
The problem is that pygame.sprite.spritecollide
checks the rect
attribute of the sprite you pass as first parameter and compares it to the rect
attribute of the sprites in the sprite group.
However, you don't actually change the rect
attribute of your Ship
instances.
Get rid of the x
and y
attributes of your Ship
class and use only the rect
attribute to store the position of the sprite.
Here's an updated version:
import sys, pygame, os, random
# Force static position of screen
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
SHIP_WIDTH = 30
SHIP_HEIGHT = 10
PILL_WIDTH = 5
PILL_HEIGHT = 20
WIN_W = 1200
WIN_H = 570
RANDOM_PILL = [700 , 658 , 58 , 795 , 687 , 308 , 785 , 828 , 670 , 187 , 603 , 994 , 990 , 923 , 523 , 849 , 229 , 804 , 618 , 733 , 614 , 209 , 941 , 872 , 528 , 438 , 793 , 879 , 327 , 539 , 571 , 886 , 452 , 627 , 267 , 662 , 655 , 772 , 904 , 769 , 197 , 1009 , 281 , 867 , 31 , 30 , 545 , 519 , 866 , 66 , 202 , 580 , 1172 , 792 , 131 , 980 , 83 , 999 , 120 , 916 , 956 , 1166 , 391 , 1127 , 675 , 868 , 851 , 725 , 869 , 702 , 767 , 692 , 695 , 564 , 978 , 834 , 866 , 340 , 78 , 396 , 195 , 480 , 1113 , 223 , 725 , 36 , 660 , 973 , 597 , 734 , 1129 , 91 , 720 , 610 , 1020 , 861 , 887 , 350 , 235 , 39 , 282 , 698 , 856 , 236 , 1077 , 191 , 1147 , 605 , 825 , 1179 , 978 , 320 , 985 , 125 , 475 , 1009 , 166 , 528 , 100 , 455 , 485 , 1066 , 38 , 408 , 235 , 410 , 1064 , 57 , 653 , 177 , 836 , 228 , 224 , 534 , 789 , 1129 , 370 , 1008 , 529 , 62 , 752 , 654 , 785 , 916 , 281 , 235 , 921 , 945 , 727 , 1138 , 585 , 168 , 1048 , 708 , 144 , 968 , 974 , 1118 , 555 , 251 , 1135 , 805 , 1121 , 360 , 968 , 228 , 988 , 49 , 536 , 117 , 726 , 65 , 177 , 925 , 923 , 239 , 1117 , 678 , 329 , 180 , 1019 , 47 , 147 , 235 , 279 , 841 , 383 , 211 , 971 , 309 , 452 , 335 , 1121 , 1091 , 247 , 790 , 418 , 961 , 323 , 458 , 970 , 752 , 888 , 719 , 318 , 930 , 797 , 537 , 1006 , 696 , 309 , 1102 , 728 , 497 , 553 , 266 , 67 , 504 , 763 , 158 , 944 , 108 , 553 , 517 , 470 , 1016 , 93 , 243 , 570 , 136 , 67 , 893 , 241 , 571 , 515 , 616 , 986 , 561 , 148 , 351 , 78 , 862 , 685 , 286 , 414 , 756 , 730 , 381 , 141 , 896]
PILL_COUNT = 0
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Ship(Entity):
def __init__(self, container):
Entity.__init__(self)
self.speed = 5
self.density = 0
self.image = pygame.Surface((SHIP_WIDTH, SHIP_HEIGHT)).convert()
self.rect = self.image.get_rect(center=container.center)
self.container = container
def update(self):
self.rect.clamp_ip(self.container)
def move(self, vector):
self.rect.move_ip([self.speed * a for a in vector])
class Pill(Entity):
def __init__(self, density):
Entity.__init__(self)
global PILL_COUNT
self.speed = 3
self.density = density
self.image = pygame.Surface((PILL_WIDTH, PILL_HEIGHT)).convert()
self.rect = self.image.get_rect(topleft=(RANDOM_PILL[PILL_COUNT], -PILL_HEIGHT))
PILL_COUNT += 1
def update(self):
self.rect.move_ip((0, self.speed))
if self.rect.y > WIN_H:
self.kill()
def main():
fps = 60
pygame.display.set_caption('Pong')
screen = pygame.display.set_mode((WIN_W, WIN_H), pygame.SRCALPHA)
ship_left = Ship(pygame.rect.Rect(0, 0, WIN_W/2, WIN_H))
ship_right = Ship(pygame.rect.Rect(WIN_W/2, 0, WIN_W/2, WIN_H))
pillGroup = pygame.sprite.Group()
shipGroup = pygame.sprite.Group(ship_left, ship_right)
pillAlter = 0
vert_partition = pygame.Surface((1, WIN_H))
hori_partition = pygame.Surface((WIN_W, 1))
clock = pygame.time.Clock()
play = True
movement = {ship_left: { pygame.K_w: ( 0, -1),
pygame.K_s: ( 0, 1),
pygame.K_a: (-1, 0),
pygame.K_d: ( 1, 0)},
ship_right: { pygame.K_UP: ( 0, -1),
pygame.K_DOWN: ( 0, 1),
pygame.K_LEFT: (-1, 0),
pygame.K_RIGHT: ( 1, 0)}}
while play:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
pressed = pygame.key.get_pressed()
for ship in shipGroup:
for key, vector in movement[ship].iteritems():
if pressed[key]:
ship.move(vector) #TODO: use real vector math
if PILL_COUNT < 250 and pillAlter % 10 == 0:
pill = Pill(random.randrange(1,4))
pillGroup.add(pill)
pillAlter += 1
pillGroup.update()
shipGroup.update()
pygame.sprite.groupcollide(shipGroup, pillGroup, False, True)
# Print background
screen.fill(WHITE)
pillGroup.draw(screen)
shipGroup.draw(screen)
screen.blit(vert_partition, (WIN_W/2, WIN_H/15))
screen.blit(hori_partition, (0, WIN_H/15))
clock.tick(fps)
pygame.display.flip()
if __name__ == "__main__":
main()
Note how the movement code is simplified. I also used kill()
to actually remove the pills that go out of screen and used some features of the Rect
class, like setting the initial position, moving in place ( move_ip
) and ensuring the Rect
does not leave a specific area ( clamp_ip
).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.