在使用 Python 进行游戏开发时,碰撞检测是一个常见的问题。尽管 Livewires 是一个较旧的库,它通常是在 Pygame 的基础上构建的,用于简化某些游戏开发任务。如果大家在使用 Livewires 与 Pygame 进行碰撞检测时遇到问题,我可以提供一些基本的策略和解决方法。

Livewires 与 Pygame 碰撞检测问题_Game

1、问题背景

我们正在尝试使用 Livewires 和 Pygame 开发一款游戏,其中厨师(我们手头上唯一的图像)需要躲避从天而降的岩石。岩石应该随机出现在不同的地点。我们希望一开始只有一块岩石落下,然后每次成功躲避一块岩石,就会有 2 块新的岩石落下,直到游戏结束。

目前我们已经实现了厨师和一块岩石下落的功能。但是,出于某种原因,如果精灵发生碰撞或岩石触碰到屏幕底部,游戏就会结束,而不会显示我们设置的“游戏结束”消息。我们感到非常困惑,无法找出问题所在。

我们知道,对于 2 块岩石的部分,我们的代码编写得不够正确,但我们甚至无法让它稍微运行起来。需要帮助!以下是我们目前为止的代码:

from livewires import games, color
import random

games.init(screen_width = 640, screen_height = 480, fps = 50)


class Chef(games.Sprite):

    image = games.load_image("chef.bmp")

    def __init__(self):
        super(Chef, self).__init__(image = Chef.image,
                                  x = games.mouse.x,
                                  bottom = games.screen.height)

    def update(self):
        self.x = games.mouse.x

        if self.left < 0:
            self.left = 0

        if self.right > games.screen.width:
            self.right = games.screen.width

        self.check_catch()

    def check_catch(self):
        for pizza in self.overlapping_sprites:
            if not self.bottom>games.screen.height:
                self.end_game()


class Rock(games.Sprite):

    def update(self):
        if self.bottom > games.screen.height:
                new_rock=Rock(x=random.randrange(games.screen.width),
                              y=10,
                              dy=1)
                games.screen.add(new_rock)

    def end_game(self):
        end_message = games.Message(value = "Game Over",
                                    size = 90,
                                    color = color.red,
                                    x = games.screen.width/2,
                                    y = games.screen.height/2,
                                    lifetime = 5 * games.screen.fps,
                                    after_death = games.screen.quit)
        games.screen.add(end_message)


def main():

    wall_image = games.load_image("wall.jpg", transparent = False)
    games.screen.background = wall_image

    the_chef = Chef()
    games.screen.add(the_chef)

    rock_image=games.load_image("rock.bmp")
    the_rock=Rock(image=rock_image,
                  x=random.randrange(games.screen.width),
                  y=10,
                  dy=1)
    games.screen.add(the_rock)

    games.mouse.is_visible = False

    games.screen.event_grab = True
    games.screen.mainloop()

main()

2、解决方案

i. 碰撞检测问题:

Chef 类中的 check_catch() 方法存在问题。if not self.bottom>games.screen.height: 语句检查的是厨师的底部是否不在屏幕高度之外。如果厨师的底部不在屏幕高度之外,则调用 self.end_game() 方法,结束游戏。

Rock 类中的 update() 方法也存在问题。if self.bottom > games.screen.height: 语句检查的是岩石的底部是否已经超出屏幕高度。如果是,则创建一块新的岩石并将其添加到屏幕中。

这些检查条件都是错误的,因为它们会导致岩石一碰到屏幕底部或厨师的顶部就结束游戏。我们需要更改这些条件,让游戏能够正常进行。

ii. 代码修改:

以下是修改后的代码:

class Chef(games.Sprite):

    image = games.load_image("chef.bmp")

    def __init__(self):
        super(Chef, self).__init__(image = Chef.image,
                                  x = games.mouse.x,
                                  y = games.screen.height - 100)

    def update(self):
        self.x = games.mouse.x

        if self.left < 0:
            self.left = 0

        if self.right > games.screen.width:
            self.right = games.screen.width

        self.check_catch()

    def check_catch(self):
        for rock in self.overlapping_sprites:
            self.end_game()


class Rock(games.Sprite):

    def update(self):
        if self.bottom > games.screen.height:
            self.destroy()  # Destroy the rock instead of creating a new one

    def end_game(self):
        end_message = games.Message(value = "Game Over",
                                    size = 90,
                                    color = color.red,
                                    x = games.screen.width/2,
                                    y = games.screen.height/2,
                                    lifetime = 5 * games.screen.fps,
                                    after_death = games.screen.quit)
        games.screen.add(end_message)


def main():

    wall_image = games.load_image("wall.jpg", transparent = False)
    games.screen.background = wall_image

    the_chef = Chef()
    games.screen.add(the_chef)

    rock_image=games.load_image("rock.bmp")
    the_rock=Rock(image=rock_image,
                  x=random.randrange(games.screen.width),
                  y=10,
                  dy=1)
    games.screen.add(the_rock)

    games.mouse.is_visible = False

    games.screen.event_grab = True
    games.screen.mainloop()

main()

我们修改了 Chef 类中的 check_catch() 方法。现在,当厨师与岩石发生碰撞时,才会调用 self.end_game() 方法结束游戏。

我们还修改了 Rock 类中的 update() 方法。现在,当岩石触碰到屏幕底部时,它将被销毁,而不是创建一块新的岩石。

这些修改之后,游戏就可以正常运行了,只有当厨师与岩石发生碰撞时才会结束游戏。

iii. 关于 2 块岩石的部分:

要实现每次成功躲避一块岩石,就会有 2 块新的岩石落下,需要修改以下代码:

Rock 类的 end_game() 方法中,增加以下代码:

for i in range(2):  # Create 2 new rocks
            new_rock = Rock(x=random.randrange(games.screen.width),
                            y=10,
                            dy=1)
            games.screen.add(new_rock)

这样,当岩石与厨师发生碰撞时,就会创建 2 块新的岩石并将其添加到屏幕中。

对于更复杂的游戏,你可能需要使用更高级的碰撞检测技术,如空间划分(如四叉树)来提高性能。这些技术可以帮助减少需要检查的碰撞对数,从而在游戏中处理大量对象时提高效率。

如果你有具体的代码或错误消息,我可以帮助你更具体地解决问题!