问题
I am making a game at the moment and I am experiencing problems with collision detection. I am making an end of level block but it can not detect if the player is standing on it to change to level 2. The collision detection for the block is found in player.updater(). As well as this the block is a class and in a group called endPlatform to allow the collision detection to work. The game runs perfectly fine however it can not detect when the Player hits Endplatform. I get no errors which show up.
EndPlatform:
class EndPlatform(pygame.sprite.Sprite):
def __init__(self, display):
super().__init__()
self.image = pygame.image.load("endPlatform.png")
self.rect = self.image.get_rect()
display.blit(self.image, self.rect)
Player:
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
# Is it touching the floor?
self.standing = True
# Rendering image and creating some variables
self.image = pygame.image.load("Slime.png")
self.sprite_x_change = 0
self.sprite_y_change = 0
self.rect = self.image.get_rect()
self.rect.y = 460
self.rect.x = 120
# Mobility: Left, right, up and stop
def move_right(self):
self.sprite_x_change = 8
def move_left(self):
self.sprite_x_change = -8
def move_up(self, platform):
if self.standing == True:
self.sprite_y_change = -25
self.standing = False
def stop(self):
self.sprite_x_change = 0
def sprint(self):
self.sprite_x_change += 10
def updater(self, platforms, powerups, score, endPlatform):
self.gravity()
self.rect.x += self.sprite_x_change
self.standing = False
platforms_hit = pygame.sprite.spritecollide(self, platforms, False)
for blocks in platforms_hit:
if self.sprite_x_change > 0:
self.rect.right = blocks.rect.left
elif self.sprite_x_change < 0:
self.rect.left = blocks.rect.right
self.rect.y += self.sprite_y_change
platforms_hit = pygame.sprite.spritecollide(self, platforms, False)
for blocks in platforms_hit:
# Going down
if self.sprite_y_change > 0:
self.rect.bottom = blocks.rect.top - 1
self.standing = True
# Going up
elif self.sprite_y_change < 0:
self.rect.top = blocks.rect.bottom
self.standing = False
self.sprite_y_change = 0
coins_hit = pygame.sprite.spritecollide(self, powerups, True)
if len(coins_hit) > 0:
score.add()
endLevel = pygame.sprite.spritecollide(self, endPlatform, True)
if len(endLevel) > 0:
score.add()
All the code:
import pygame
import random
pygame.font.init()
# Colours + Global constants
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
RANDOM = (12, 211, 123)
WIDTH = 800
HEIGHT = 600
SIZE = (WIDTH, HEIGHT)
AGENT = pygame.font.SysFont("Agent Orange", 30)
# CLASSES
# Block is the common platform
class EndPlatform(pygame.sprite.Sprite):
def __init__(self, display):
super().__init__()
self.image = pygame.image.load("endPlatform.png")
self.rect = self.image.get_rect()
display.blit(self.image, self.rect)
class Coins(pygame.sprite.Sprite):
def __init__(self, display):
super().__init__()
self.image = pygame.image.load("hud_coins.png")
self.rect = self.image.get_rect()
display.blit(self.image, self.rect)
class Score:
def __init__(self):
self.score = 0
def msgs(self, msg, colour, display):
screen_text = AGENT.render(msg, True, colour)
display.blit(screen_text, [0, 0])
def add(self):
self.score += 1
class Monster(pygame.sprite.Sprite):
def __init__(self, length, height, colour):
super().__init__()
self.image = pygame.Surface([length, height])
self.image.fill(colour)
self.rect = self.image.get_rect()
# Setting Y coordinates
self.rect.y = HEIGHT - 80
def jump(self):
self.rect.y = -10
class Block(pygame.sprite.Sprite):
def __init__(self, length, height, colour):
super().__init__()
# Making image
self.image = pygame.Surface([length, height])
self.image.fill(colour)
self.rect = self.image.get_rect()
# Setting Y coordinates
self.rect.y = 468
class Platform(pygame.sprite.Sprite):
def __init__(self, display, x_screen, y_screen, x_sheet, y_sheet, height, length):
super().__init__()
self.tiles = pygame.image.load("tiles_spritesheet.png")
self.image = self.tiles.subsurface(pygame.Rect(x_sheet, y_sheet, height, length))
self.rect = self.image.get_rect(x=x_screen, y=y_screen)
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
# Is it touching the floor?
self.standing = True
# Rendering image and creating some variables
self.image = pygame.image.load("Slime.png")
self.sprite_x_change = 0
self.sprite_y_change = 0
self.rect = self.image.get_rect()
self.rect.y = 460
self.rect.x = 120
# Mobility: Left, right, up and stop
def move_right(self):
self.sprite_x_change = 8
def move_left(self):
self.sprite_x_change = -8
def move_up(self, platform):
if self.standing == True:
self.sprite_y_change = -25
self.standing = False
def stop(self):
self.sprite_x_change = 0
def sprint(self):
self.sprite_x_change += 10
def updater(self, platforms, powerups, score, endPlatform):
self.gravity()
self.rect.x += self.sprite_x_change
self.standing = False
platforms_hit = pygame.sprite.spritecollide(self, platforms, False)
for blocks in platforms_hit:
if self.sprite_x_change > 0:
self.rect.right = blocks.rect.left
elif self.sprite_x_change < 0:
self.rect.left = blocks.rect.right
self.rect.y += self.sprite_y_change
platforms_hit = pygame.sprite.spritecollide(self, platforms, False)
for blocks in platforms_hit:
# Going down
if self.sprite_y_change > 0:
self.rect.bottom = blocks.rect.top - 1
self.standing = True
# Going up
elif self.sprite_y_change < 0:
self.rect.top = blocks.rect.bottom
self.standing = False
self.sprite_y_change = 0
coins_hit = pygame.sprite.spritecollide(self, powerups, True)
if len(coins_hit) > 0:
score.add()
endLevel = pygame.sprite.spritecollide(self, endPlatform, True)
if len(endLevel) > 0:
score.add()
def gravity(self):
self.sprite_y_change += 3
class Level:
def __init__(self):
# Creating groups
self.endPlatform = pygame.sprite.Group()
self.powerups = pygame.sprite.Group()
self.sprites = pygame.sprite.Group()
self.all_things = pygame.sprite.Group()
self.platforms = pygame.sprite.Group()
self.entities = pygame.sprite.Group()
self.shift_x = 0
self.shift_y = 0
def updater(self, display, score):
self.all_things.draw(display)
score.msgs("Score: " + str(score.score), RED, display)
def scroll_x(self, shift_x_change):
self.shift_x += shift_x_change
for platform in self.entities:
platform.rect.x += shift_x_change
def scroll_y(self, shift_y_change):
self.shift_y += shift_y_change
for platform in self.entities:
platform.rect.y += shift_y_change
class Level01(Level):
def __init__(self, player1, monster, display):
# Initialise level1
super().__init__()
# Level01 things
block = Block(245, 3, BLACK)
Level.all_things = self.all_things
self.sprites.add(player1, monster)
self.platforms.add(block)
self.all_things.add(player1, block, monster)
self.entities.add(block)
theLevel = []
level = [[600, 400, 648, 0, 70, 70],
[740, 320, 648, 0, 70, 70],
[380, 400, 648, 0, 70, 70],
[900, 280, 648, 0, 70, 70],
[1200, 530, 648, 0, 70, 70],
[1350, 450, 648, 0, 70, 70],
[1500, 550, 648, 0, 70, 70],
[1680, 500, 648, 0, 70, 70],
]
for platform in theLevel:
block = Block(platform[0], platform[1], RED)
block.rect.x = platform[2]
block.rect.y = platform[3]
self.platforms.add(block)
self.all_things.add(block)
self.entities.add(block)
for goodPlatform in level:
platform = Platform(display, goodPlatform[0], goodPlatform[1], goodPlatform[2], goodPlatform[3], goodPlatform[4], goodPlatform[5])
self.platforms.add(platform)
self.all_things.add(platform)
self.entities.add(platform)
for n in range(1):
coin = Coins(display)
coin.rect.x = random.randint(0, WIDTH*3)
coin.rect.y = 400
self.all_things.add(coin)
self.entities.add(coin)
self.powerups.add(coin)
platforms_hit = pygame.sprite.spritecollide(coin, self.entities, False)
for hit in platforms_hit:
coin.rect.x = random.randrange(0, WIDTH*3)
finalPlatform = EndPlatform(display)
finalPlatform.rect.x = 1900
finalPlatform.rect.y = 420
self.all_things.add(finalPlatform)
self.entities.add(finalPlatform)
self.platforms.add(finalPlatform)
self.endPlatform.add(finalPlatform)
class Level02(Level):
def __init__(self, player1, monster):
super().__init__()
# Level01 things
block = Block(245, 3, BLACK)
Level.all_things = self.all_things
self.sprites.add(player1, monster)
self.platforms.add(block)
self.all_things.add(player1, block, monster)
def main():
# Init pygame
pygame.init()
# Set screen
backgrounds = ["background2.jpg", "background.jpg"]
background = pygame.image.load(backgrounds[0])
backgroundRect = background.get_rect()
display = pygame.display.set_mode(background.get_size())
# Creating FPS thingy
clock = pygame.time.Clock()
# Making levels + Player
score = Score()
monster = Monster(30, 30, RANDOM)
player = Player()
level_1 = Level01(player, monster, display)
level_2 = Level02(player, monster)
# Choosing level
levelList = []
levelList.append(level_1)
levelList.append(level_2)
currentLevelNumber = 0
# Game loop
loop = True
while loop == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.move_right()
if event.key == pygame.K_LEFT:
player.move_left()
if event.key == pygame.K_UP:
player.move_up(currentLevel.platforms)
if event.key == pygame.KMOD_LSHIFT and event.key == pygame.K_RIGHT:
player.sprint()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.sprite_x_change < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.sprite_x_change > 0:
player.stop()
if event.key == pygame.KMOD_LSHIFT:
player.sprite_x_change -= 10
# Update things
#monster.jump()
if player.rect.x > 400:
player.rect.x = 400
currentLevel.scroll_x(-10)
if player.rect.x >= WIDTH:
player.rect.x = WIDTH
currentLevel.scroll(0)
if player.rect.y >= HEIGHT:
main()
if player.sprite_x_change < 0 and player.rect.x >= 120:
currentLevel.scroll_x(0)
if player.rect.left <= 120 and player.sprite_x_change < 0:
player.rect.x = 120
player.rect.left = 120
currentLevel.scroll_x(10)
'''
if player.rect.y <= 300:
if player.standing == False and player.sprite_y_change < 0:
currentLevel.scroll_y(10)
if currentLevel.shift_y > 0:
y_speed = -4
if player.standing == True and player.rect.y < 300:
y_speed = 4
print(currentLevel.shift_y)
currentLevel.scroll_y(y_speed)
'''
currentLevel = levelList[currentLevelNumber]
if currentLevel.shift_x > 0:
currentLevel.scroll_x(currentLevel.shift_x * -1)
display.blit(background, backgroundRect)
player.updater(currentLevel.platforms, currentLevel.powerups, score, currentLevel.endPlatform)
currentLevel.updater(display, score)
# Refresh screen
clock.tick(30)
pygame.display.update()
pygame.quit()
loop = False
if __name__ == "__main__":
main()
回答1:
It seems I found the problem, for some daft reason you can't use collision detection twice on the same object. I used it once so that the player could stand on the block and another time so that you could go on to the next level!
回答2:
The reason why it doesn't switch to the next level is that you change the position of the rect when it collides with a platform, so the player.rect gets moved out of the blocks.rect and therefore can't collide again when you call spritecollide with the endPlatform group.
A quick and dirty fix would be to check in the for blocks in platforms_hit: loops if the block is in the endPlatform group and then return True:
for blocks in platforms_hit:
if blocks in endPlatform:
score.add()
return True
And then increase the currentLevelNumber in the main function if True is returned:
change_level = player.updater(currentLevel.platforms, currentLevel.powerups, score, currentLevel.endPlatform)
if change_level:
currentLevelNumber += 1
来源:https://stackoverflow.com/questions/33922546/collision-detection-not-working-in-pygame