python 3.2.2中的碰撞检测和掩码

时间:2012-03-03 01:27:01

标签: python python-3.x collision-detection pygame

我和我的朋友正在尝试制作游戏。在这个游戏中我们希望有很好的碰撞检测。但我们似乎无法找到在定义循环时更新掩码的方法。 :S我们已经测试了很多次,具有不同的值,甚至一些非常不逻辑的东西。

每当我们移动玩家时,游戏会在与面具碰撞时崩溃。它就像循环一样永远存在,即使我们移动面具和背景时玩家和丛林应该远离彼此。

def check_collision():
    while pygame.sprite.collide_mask(player, rock):
       bg.x -= 1 #the x-value of the background
       rock.x -=1 #the x-value of the object
  • 使用按钮“a”向左移动时只是碰撞。
  • 我们还会移动背景和所有精灵而不是播放器。
  • 我们需要使用面具。
  • 我们知道它会检查碰撞,但是在更改bg.x和rock.x之后,掩码不会更新。
  • 我们假设这是因为图像没有在屏幕上移动。因此我们尝试在while循环中放置一个blit。它仍然行不通。

感谢您的帮助,最后一个问题是,有没有办法手动移动蒙版/对象?

1 个答案:

答案 0 :(得分:1)

首先,使用蒙版进行碰撞检测非常耗时。无论您的游戏是否已进入无限循环,位掩码位掩码重叠检查的处理要求将使您的游戏运行得太慢。

然而,存在一个简单的优化:

任何能够与物体碰撞的物体都必须有一些最大尺寸 - 也就是说,你可以找到一个总是包含你的玩家的矩形,你的巨石可以放在另一个里面。因此,如果你的玩家的盒子没有碰到巨石的盒子,它们就不会重叠。由于你坚持使用碰撞遮挡(可以为任何pixelart游戏添加一些真实感),你可以计算每个像素的碰撞(并且时)边界框碰撞。

现在,您的编码风格:>:O

在一个理想情况下计算即时冲突检查的函数中放置一个潜在的无限循环绝不是一个好主意。在最好的情况下(这当然是可以实现的),你将有一个函数来检查两个对象是否发生冲突,并告诉你一些更有用的信息(一个相对于另一个的位置,等等);而每个移动物体的单独方法都可以修复碰撞。

这会转化为:

class CollidingObject:
    #This class controls an object which can move and fix collisions

    def __init__(self):
        self.x = 0 #add relevant initialization code here
        self.y = 0
        self.xVel = 0 # X and Y velocity (for movement)
        self.yVel = 0
        self.xSize = 0 # the width of the object in pixels
        self.ySize = 0 # the height of the object in pixels

    def iscolliding(self, other):
        # using x and y as the center of the object, 
        # this returns an empty tuple if  they don't collide
        if ((self.xSize + other.xSize) / 2 <= abs(self.x - other.x)) and 
           ((self.ySize + other.ySize) / 2 <= abs(self.y - other.y)): return ()
        """ 
        use pygame collidemask here to compute whether they collide.
        if they do, return a vector of 'other's' position relative to self.
        (this can be used to decide how to separate the objects)
        """

    def restitute(self, overlaps_with, distances):
        """
        Given some objects which overlap, and a list of 2D vectors of their 
        relative distances, this separates them however much you like.
        """
        pass

关于完成切割检查的位置,这取决于对象管理基础的实现。到目前为止,我将假设您的所有游戏内对象都包含在可迭代内;并且在你遍历对象的每一帧上,一次渲染,一次移动它们 - 这样的结构:

while NOT_QUIT:

    for object in objects:
        object.draw_to_screen()
        object.move() # moves the object -- collisions, etc in here

    event_handling_stuff() # handles events

在这种情况下,每个对象都可以计算对象中跟随它的任何内容的冲突检查。在这样做时,每个对象可以收集它们从每个对象移动的距离。之后,每个物体可以移动到尽可能远离每个对撞机。

在我写过的一些游戏中,我会让物体移动得越远,它们越重叠,使碰撞具有弹性,即使非常粗糙的恢复算法看起来也很性感。一般来说,一旦你进行了工作检查,你就可以修补常数,这是你最不担心的事情。

希望这对你们两个人有所帮助(我现在意识到我在切线上走了一段路,但你们问的是如何更有效地做错事:P)。

tl; dr:请勿尝试修复碰撞检查功能中的碰撞。相反,将其分成一个找到与其他对象的所有碰撞,另一个同时修复对象的所有碰撞。 添加其他问题,我会更新(:。


更新1

"vector of other to self"位上扩展(粗略地解释了一下:/)

一般情况下,当两个物体在现实生活中发生碰撞时,它们会在它们来自的方向上稍微反弹(当你将橡胶弹力球放在地板上时,它会从那里反弹回来 - 它不仅仅是通过它来反射地上)。在大多数编程应用程序中,你想让弹性球(以及其他碰撞的东西)以相同的方式运行(好吧,有时你可能希望球在地板上消失,但这更容易弹跳恕我直言:P)。

要知道对象必须以哪种方式反弹,您必须知道它来自哪个方向。更严格地说,你必须知道它碰撞的角度。如果比较碰撞过程中每个物体中心之间的距离和方向,则很容易找到。如果你使用的中心距离它们的质心很近(在大多数游戏中,物体的中间是一个简单而好的近似),这将提供两个物体弹跳的非常精确的表示。

所以,既然我们不需要担心质心和所有这些,我们只测量物体位置之间的矢量距离:

#Continuing the previous example, we put some code like this in 'iscolliding' :)
if they collide (pygame mask stuff) :
    x_distance = self.x - other.x
    y_distance = self.y - other.y
    return (x_distance, y_distance)

此代码可以为您提供每个对象应移动的线,以尽快解决冲突。其余的是沿着这条线加速每个物体的问题,确保它们不会靠得更近(注意标志),并调整常数以产生逼真的效果。