如何检测碰撞? pygame
How to detect collision? pygame
我正在创建平台游戏并且有红色方块(他们应该杀了我)和白色方块(平台)
当我死了,我应该在当前水平的开始复活。
我做了碰撞检测,但它只有在我移动时才有效(当我跳到红色方块并且我没有按下任何东西时,它不起作用)
所以我真的很想知道如何更好地处理碰撞。
谢谢
代码:
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()```
您检查每个帧中每个事件与 killing_entities
列表的冲突。因此,如果事件队列中当前没有事件,则行:
if pygame.sprite.spritecollideany(player, killing_entities):
main()
永远不会执行。我猜你只想在主循环中使用该代码,而不是在事件处理循环中。
您的代码中还有一些奇怪的地方,例如
您没有操作QUIT
event所以您无法关闭游戏window.
您使用相同的变量 running
作为主循环的条件并更改播放器的 xvel
.
也无需更新显示两次(只需使用 pygame.display.flip()
)。
您正在将一个巨大的 (3200x32px) 表面每帧传输到屏幕 1024 次。如果你想用黑色填充屏幕,只需每帧调用一次screen.fill('black')
。
我正在创建平台游戏并且有红色方块(他们应该杀了我)和白色方块(平台) 当我死了,我应该在当前水平的开始复活。 我做了碰撞检测,但它只有在我移动时才有效(当我跳到红色方块并且我没有按下任何东西时,它不起作用)
所以我真的很想知道如何更好地处理碰撞。
谢谢 代码:
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()```
您检查每个帧中每个事件与 killing_entities
列表的冲突。因此,如果事件队列中当前没有事件,则行:
if pygame.sprite.spritecollideany(player, killing_entities):
main()
永远不会执行。我猜你只想在主循环中使用该代码,而不是在事件处理循环中。
您的代码中还有一些奇怪的地方,例如
您没有操作
QUIT
event所以您无法关闭游戏window.您使用相同的变量
running
作为主循环的条件并更改播放器的xvel
.也无需更新显示两次(只需使用
pygame.display.flip()
)。您正在将一个巨大的 (3200x32px) 表面每帧传输到屏幕 1024 次。如果你想用黑色填充屏幕,只需每帧调用一次
screen.fill('black')
。