Проблема с обнаружением 2D-столкновений от новичка

Я прошел вводный курс по компьютерным наукам, но недавно решил попробовать сделать игру. У меня проблема с обнаружением столкновений. Моя идея заключалась в том, чтобы переместить объект и, если произошло столкновение, переместить его в исходное положение до тех пор, пока столкновение не прекратится. Вот мой код:

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

*Я подставил несколько разных значений для n, как целых, так и с плавающей запятой, чтобы изменить приращение, на которое игрок перемещается назад. Я думал, что, попробовав большой поплавок, он будет перемещаться только на один пиксель за раз.

Когда я запускаю программу, спрайт игрока очень быстро вибрирует в диапазоне около 5 пикселей всякий раз, когда я натыкаюсь на стену. Если я отпущу клавишу со стрелкой, спрайт навсегда застрянет в стене. Мне интересно, почему спрайт в первую очередь находится внутри стены, поскольку к тому времени, когда я вывел спрайт на экран, он должен был быть перемещен сразу за стену.

Что-то не так с моим методом или проблема заключается в моем исполнении?


person Kevin    schedule 29.07.2010    source источник


Ответы (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
person Mike Sherov    schedule 29.07.2010
comment
Хм, странно. Я на самом деле поймал эту ошибку, прежде чем опубликовать это. Я не знаю, как эта ошибка попала в браузер. Первоначально я собирался сделать то, что вы предложили (спроецировать hitBox в новую позицию, а затем проверить), но если что-то мешало, я хотел двигаться против него, а не вообще не двигаться. Я боюсь, что процесс движения к стене почти идентичен процессу удаления, и что у меня будет такая же проблема, когда я внесу это изменение. Я попробую это в то же время. - person Kevin; 30.07.2010
comment
Не обращайте внимания на мой первый комментарий. Есть два экземпляра этих двух строк. Я исправил второе, но не первое. Теперь все работает отлично, спасибо! - person Kevin; 30.07.2010
comment
@Kevin, я предлагаю вам создать функцию, которая инкапсулирует изменение положения и одновременное обновление горячей ячейки, чтобы вам не приходилось менять ее в нескольких местах. Кроме того, вы можете посмотреть вперед, чтобы по-прежнему перемещать персонажа прямо к стене без мерцания. Просто добавьте инкрементное расстояние от проекции вместо вычитания из промаха. - person Mike Sherov; 30.07.2010