初学者的2D碰撞检测问题

1 投票
1 回答
1463 浏览
提问于 2025-04-16 02:02

我之前上过一门计算机科学的入门课程,最近决定尝试制作一个游戏。不过,我在碰撞检测方面遇到了问题。我的想法是移动一个物体,如果发生碰撞,就把它往回移动,直到不再发生碰撞。以下是我的代码:

class Player(object):  
    ...  
    def move(self):
        #at this point, velocity = some linear combination of (5, 0)and (0, 5)
        #gPos and velocity are types Vector2    
        self.hitBox = Rect(self.gPos.x, self.gPos.y, 40, 40)
        self.gPos += self.velocity  
        while CheckCollisions(self):  
            self.gPos -= self.velocity/n #see footnote  
            self.hitBox = Rect(self.gPos.x, self.gPos.y, 40, 40)
    ...
def CheckCollisions(obj):
    #archList holds all 'architecture' objects, solid == True means you can't walk        
    #through it. colliderect checks to see if the rectangles are overlapping
    for i in archList:
        if i.solid:
            if i.hitBox.colliderect(obj.hitBox):
                return True
    return False

*我尝试了几种不同的值来改变玩家后退的步幅,包括整数和浮点数。我以为如果用一个比较大的浮点数,物体每次只会移动一个像素。

但是当我运行程序时,玩家的角色在碰到墙壁时会在大约5个像素的范围内快速抖动。如果我松开方向键,角色就会永久卡在墙里。我在想,角色为什么一开始会在墙里,因为在我把角色显示到屏幕上之前,它应该已经移动到墙外了。

我想知道,是我的方法有问题,还是在执行过程中出现了问题?

1 个回答

1

看起来你是在更新位置之前就设置了碰撞盒。这个问题的解决办法似乎很简单。

找到:

    self.hitBox = Rect(self.gPos.x, self.gPos.y, 40, 40)
    self.gPos += self.velocity  

替换为:

    self.gPos += self.velocity  
    self.hitBox = Rect(self.gPos.x, self.gPos.y, 40, 40)

其他建议:你应该在移动之前检查一下目标位置,如果那里已经被占据了,就不要移动。这部分代码没有经过测试,所以请把它当作示例代码来理解:

class Player(object):  
    ...  
    def move(self):
        #at this point, velocity = some linear combination of (5, 0)and (5, 5)
        #gPos and velocity are types Vector2    
        selfCopy = self
        selfCopy.gPos += self.velocity
        selfCopy.hitBox = Rect(selfCopy.gPos.x, selfCopy.gPos.y, 40, 40)
        if not CheckCollisions(selfCopy)    
            self.gPos += self.velocity
    ...
def CheckCollisions(obj):
    #archList holds all 'architecture' objects, solid == True means you can't walk        
    #through it. colliderect checks to see if the rectangles are overlapping
    for i in archList:
        if i.solid:
            if i.hitBox.colliderect(obj.hitBox):
                return True
    return False

撰写回答