2014-03-04 1 views
7

Это моя надежда, что щедрость привлечет человек, который знает вещь или два о внутренней работе PyGame (я попробовал, глядя на исходном коде .. есть куча его) и может сказать мне, если это это действительно , связанное с наличием threading.py или если есть практика Я могу избежать вообще, чтобы это не происходило в других проектах PyGame.python и pygame - что произошло во время выполнения этой оболочки?

Я создал обертку для объектов, которые взрываются при вызове obj.kill().

def make_explosion(obj, func): 
    def inner(*args, **kwargs): 
     newX, newY = obj.x, obj.y 
     newBoom = Explosion(newX, newY) 
     allqueue.add(newBoom) #an instance of pygame.sprite.Group 
     return func(*args, **kwargs) 
    return inner 

Он получает й объект и у координаты, а затем создает новый экземпляр Explosion в этих координатах, добавляет его к allqueue, которые я использую, чтобы убедиться, что все update d во время игры, и, наконец, возвращается функция его обертывания - в этом случае, obj.kill. obj.kill() - это метод pygame.sprite.Sprite, который удаляет объект из всех экземпляров sprite.Group, к которому принадлежит.

Я бы просто обернул метод следующим образом, во время создания экземпляра Enemy.

newEnemy = Enemy() 
##other code to add new AI, point values…eventually, the following happens: 
newEnemy.kill = make_explosion(newEnemy, newEnemy.kill) 

Когда я запустил игру, взрывы появились в случайных местах, где-то рядом с фактическими координатами x и y объекта. Анекдотически это выглядело не так, как будто это происходило на объекте (x, y) происхождения или даже на дорогах, которые они путешествовали во время их короткого существования на экране (я довольно хорош в своей игре, чтобы не хвастаться) , поэтому я чувствовал, что должен был исключить, что x и y были назначены в момент, когда метод был завернут.

Немного, бьюсь futzed вокруг и изменил код так:

def make_explosion(obj, func): 
    def inner(*args, **kwargs): 
     allqueue.add(Explosion(obj.x, obj.y)) 
     return func(*args, **kwargs) 
    return inner 

Это изменение сделало работу «как задумано» - когда метод объекта self.kill() называется, взрыв появляется на правильный координаты.

Что я не понимаю, почему это работает! Особенно учитывая документацию PyGame, в которой говорится, что kill() не обязательно удаляет объект; он просто удаляет его из всех групп, к которым он принадлежит.

от https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Sprite.kill -

убить()

удалить Sprite из всех групп убивают() -> None

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

Итак, хотя я случайно решил проблему, я вообще не понимаю ее. Почему он ведет себя таким образом?

EDIT: Исходя из некоторых ранних комментариев, я попытался воспроизвести подобное условие без использования библиотеки PyGame, и я не могу этого сделать.

Par пример:

>>> class A(object): 
...  def __init__(self, x, y): 
...    self.x = x 
...    self.y = y 
...  def go(self): 
...    self.x += 1 
...    self.y += 2 
...    print "-go-" 
...  def stop(self): 
...    print "-stop-" 
...    print "(%d, %d)" % (self.x, self.y) 
...  def update(self): 
...    self.go() 
...    if self.x + self.y > 200: 
...      self.stop() 
>>> Stick = A(15, 15) 
>>> Stick.go() 
-go- 
>>> Stick.update() 
-go- 
>>> Stick.x 
17 
>>> Stick.y 
19 
>>> def whereat(x, y): 
...  print "I find myself at (%d, %d)." % (x, y) 
... 
>>> def wrap(obj, func): 
...  def inner(*args, **kwargs): 
...    newX, newY = obj.x, obj.y 
...    whereat(newX, newY) 
...    return func(*args, **kwargs) 
...  return inner 
... 
>>> Stick.update = wrap(Stick, Stick.update) 
>>> Stick.update() 
I find myself at (17, 19). 
-go- 
>>> Stick.update() 
I find myself at (18, 21). 
-go- 
>>> Stick.update() 
I find myself at (19, 23). 
-go- 

Итак, я сразу заметил, что whereat() вызывается перед тем изменение координат при Stick.go() так он использует x и y непосредственно перед приращением, но это нормально; Я мог бы легко изменить оболочку, чтобы подождать, пока не вызывается go(). Проблема здесь отсутствует, как это было в моем проекте PyGame; взрывы не были даже «смежными врагами», они появлялись во всех видах случайных мест, а не в предыдущих (x, y) координатах спрайта (если бы это было, я, возможно, даже не заметил проблемы!).

UPDATE: После того как пользователь комментарий получил мне интересно, я порылся в Интернете немного, побежал cProfile по проекту в вопросе, и вот - PyGame определенно использует threading.py. К сожалению, тот же Интернет был недостаточно хорош, чтобы сказать мне точно , как PyGame использует threading.py, поэтому, видимо, мне нужно прочитать, как потоки даже работают. Oi. :)

После прочтения исходного кода PyGame немного (bleh) Я нашел один модуль, который, как представляется, разрешает, когда и почему PyGame порождает поток. Из того, что я знаю о потоках, это может привести к чему-то вроде состояния гонки; x не определяется «во времени» для выполнения оболочки, и поэтому (объект Explosion) заканчивается в неправильном месте. Я видел другие ошибки, возникающие в другом проекте, который немного тяжелее в математике; но они обычно включают pulse, которые не могут получить событие или время ожидания события или что-то подобное (у меня есть трассировка длинного стека, лежащая вокруг, в случае, если у кого-то возникли проблемы спать).

В конце дня я подозреваю, что это то, чего я могу избежать, придерживаясь определенных практик, но я не знаю, что эти практики на самом деле будет, и я не знаю, как предотвратить PyGame от арбитража, какие процессы получают свои собственные потоки, а когда это хуже, чем НЕ. Если для всего этого есть единая теория, я бы с удовольствием узнал об этом.

+1

Вы не используете многопоточность/многопроцессорность для чего-либо в своей игре, не так ли? –

+0

Конечно, не намеренно. Я * думаю * PyGame делает некоторую многопоточность самостоятельно, без прямого вызова пользователем любого из них, но я не уверен. –

+0

Я не верю, потому что это затрудняет создание игр с использованием pygame на малине pi, которые, как многие знают, очень возможны. – KodyVanRy

ответ

0

К сожалению, я должен сказать, что для этой конкретной проблемы ошибка была моей.

В Explosion класса, код которого не был включен здесь, я не правильно обновить свои self.x и self.y значения при его создании или его метода self.update(). Изменение этого кода в сочетании с сокращением кода I do здесь показало, что эта проблема и другие исчезли.

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

0

Я собираюсь предположить, что вы используете pygame.sprite.Group() для группировки спрайтов, а затем визуализации их на экран. Исправьте меня, если я ошибаюсь. Затем вы создаете конфликт, который создается с использованием атрибутов спрайта, но затем «уничтожает» спрайт, а это означает, что любые созданные вами группы с использованием pygame.sprite.Group, которые затем содержат этот спрайт, больше не будут содержать этот спрайт. Теперь, учитывая, что вы добавили ссылку в свой вопрос, я собираюсь предположить, что вы уже прочитали документы.

Итак, вот код, который вы опубликовали с комментариями о том, что каждый делает.

#so here is your wrapper which will call make explosion before it kills the sprite. 
def make_explosion(obj, func): 
    #you call kill and so here it goes. 
    def inner(*args, **kwargs): 
     #you add the explosion to your queue 
     allqueue.add(Explosion(obj.x, obj.y)) #create an instance of explosion inside. 
     # return to the outside function `make_explosion` 
     return func(*args, **kwargs) 
    #you call inner second and then go to the inner. 
    return inner 
    #after it returns inner kill is called 

Таким образом, это означает, что он вызывает make_explosion, а затем вызывает убить на спрайт, который удаляет его из любой группы. Скажите, пожалуйста, если вам нужно какое-либо разъяснение по этому вопросу или если вам нужен лучший или более глубокий ответ. Или скажите мне, есть ли у вас какие-то другие вещи, в которых вы нуждаетесь.

+0

Это не говорит мне, почему назначение значений в разных строках приведет к тому, что он будет работать иначе, чем делать это в однострочном пространстве. Я довольно уверен, что понимаю декоратора, это разница между моим первым примером и моим вторым примером, который озадачивает. –

+0

Ну, вот что я получил от вопроса, но я постараюсь понять это лучше, когда вернусь к своему компьютеру – KodyVanRy