I am creating platfrormer game and there are red squares (they should kill me) and white squares (platforms) when I die, I should revive on the start of current level. I did collision detection, but it works only if I´m moving (when I jump to red squares and i´m not pressing anything, it doesn´t work)
so I really want to know how to do collisions better.
thanks code:
from pygame import *
WIN_WIDTH = 1923
WIN_HEIGHT = 1000
DISPLAY = (WIN_WIDTH, WIN_HEIGHT)
DEPTH = 32
FLAGS = 0
CAMERA_SLACK = 30
pygame.init()
green = (0, 255, 0)
screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH)
font = pygame.font.SysFont('Consolas', 30)
text = font.render('Your Score: ', True, (0, 255, 0))
textRect = text.get_rect()
textRect.center = (40, 55)
level = [
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"P P",
"P P",
"P PP P",
"P P",
"P PP P",
"P P",
"P P",
"P PP P",
"P P",
"P P",
"P P",
"P P",
"P PP P",
"P P",
"P P",
"P P",
"P P P",
"P PP P P",
"P P P",
"P P P",
"P P P",
"P PP P P",
"P P P",
"P P P",
"P PP P P",
"P P P",
"P PPP P PP",
"P P P",
"P P LP",
"PSSSSSSSSSSSSSSSSSSSSSSPPPSSSSSSSSSSSSSSSSSSSSSSSSSSPSSPPPPPPP",
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
]
def main():
pygame.display.set_caption("Use W,A,S,D and Space to move!")
timer = pygame.time.Clock()
up = down = left = right = running = left_dash = right_dash = dashing = False
bg = Surface((3200,32))
bg.convert()
bg.fill(Color("#000000"))
entities = pygame.sprite.Group()
platforms = []
killing_entities = []
another_level = []
blockade = []
player = Player(767, 900)
x = y = 0
global level
for row in level:
for col in row:
if col == "P":
p = Platform(x, y)
platforms.append(p)
entities.add(p)
if col == "E":
e = Block(x, y)
platforms.append(e)
entities.add(e)
if col == "S":
s = Spike(x, y)
killing_entities.append(s)
entities.add(s)
if col == "L":
l = Another_Level(x, y)
another_level.append(l)
entities.add(l)
x += 32
y += 32
x = 0
entities.add(player)
running = True
while running:
screen.blit(text, textRect)
timer.tick(65)
for e in pygame.event.get():
if e.type == KEYDOWN and e.key == K_SPACE:
up = True
if e.type == KEYDOWN and e.key == K_s:
down = True
if e.type == KEYDOWN and e.key == K_a:
left = True
if e.type == KEYDOWN and e.key == K_d:
right = True
if e.type == KEYDOWN and e.key == K_q:
running = True
if e.type == KEYDOWN and e.key == K_LEFT:
left_dash = True
if e.type == KEYDOWN and e.key == K_RIGHT:
right_dash = True
if e.type == KEYUP and e.key == K_SPACE:
up = False
if e.type == KEYUP and e.key == K_s:
down = False
if e.type == KEYUP and e.key == K_d:
right = False
if e.type == KEYUP and e.key == K_a:
left = False
if e.type == KEYUP and e.key == K_d:
right = False
if pygame.sprite.spritecollideany(player, killing_entities):
main()
if pygame.sprite.spritecollideany(player, another_level):
level = [
"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"P P",
"PPS P",
"PEE P",
"PSS P",
"P P",
"P P",
"PP P",
"P P",
"P P",
"P P",
"P P",
"P P P",
"PSSSSSSSSSSSSSSSSSSSSSSPPPSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSPPPP",
"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
]
main()
for y in range(32):
for x in range(32):
screen.blit(bg, (x * 32, y * 32))
player.update(up, down, left, right, left_dash, right_dash, running, dashing, platforms)
entities.draw(screen)
pygame.display.flip()
pygame.display.update()
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Player(Entity):
def __init__(self, x, y):
Entity.__init__(self)
self.xvel = 0
self.yvel = 0
self.onGround = False
self.image = Surface((32,32))
self.image.fill(Color("#0000FF"))
self.image.convert()
self.rect = Rect(x, y, 32, 32)
def update(self, up, down, left, right, left_dash, right_dash, running, dashing, platforms):
if up:
if self.onGround: self.yvel -= 9
if down:
pass
if running:
self.xvel = 12
if left_dash:
self.rect.move_ip(-20, -2)
left_dash = False
if right_dash:
self.rect.move_ip(20, -2)
right_dash = False
if left:
self.xvel = -8
if right:
self.xvel = 8
if not self.onGround:
self.yvel += 0.25
if self.yvel > 100: self.yvel = 100
if not(left or right):
self.xvel = 0
self.rect.left += self.xvel
self.collide(self.xvel, 0, platforms)
self.rect.top += self.yvel
self.onGround = False
self.collide(0, self.yvel, platforms)
def collide(self, xvel, yvel, platforms):
for p in platforms:
if pygame.sprite.collide_rect(self, p):
if isinstance(p, Block):
pygame.event.post(pygame.event.Event(QUIT))
if xvel > 0:
self.rect.right = p.rect.left
if xvel < 0:
self.rect.left = p.rect.right
if yvel > 0:
self.rect.bottom = p.rect.top
self.onGround = True
self.yvel = 0
if yvel < 0:
self.rect.top = p.rect.bottom
self.onGround = False
class Platform(Entity):
def __init__(self, x, y):
Entity.__init__(self)
self.image = Surface((32, 32))
self.image.convert()
self.image.fill(Color("#DDDDDF"))
self.rect = Rect(x, y, 32, 32)
def update(self):
pass
class Block(Platform):
def __init__(self, x, y):
Platform.__init__(self, x, y)
self.image.fill(Color("#000000"))
class Spike(pygame.sprite.Sprite):
def __init__(self, x, y):
Platform.__init__(self, x, y)
self.image = Surface((33, 33))
self.image.convert()
self.image.fill(Color("#E70018"))
self.rect = Rect(x, y, 33, 33)
class Another_Level(pygame.sprite.Sprite):
def __init__(self, x, y):
Platform.__init__(self, x, y)
self.image = Surface((33, 33))
self.image.convert()
self.image.fill(Color("#8C563E"))
self.rect = Rect(x, y, 33, 33)
if __name__ == "__main__":
main()```
You check for collisions with the killing_entities
list for each event in each frame. So if there's currently not event in the event queue, the lines:
if pygame.sprite.spritecollideany(player, killing_entities):
main()
are never executed. I guess you want that code in your main loop only, not in the event handling loop.
There are some more oddities in your code, e.g.
You don't handle the QUIT
event so you can't close the game's window.
You use the same variable running
as condition for your main loop and to change the player's xvel
.
There's also no need to update the display twice (just use pygame.display.flip()
).
You're blitting a huge (3200x32px) Surface 1024 times per frame to the screen. If you want to fill the screen with the color black, just call screen.fill('black')
once per frame.