2013-10-20 3 views
0

Я пишу небольшую игру с модулем tkinter python, используя виджет холста. Существует человек, который является просто мячом и бомбами, которые появляются каждые 10 секунд. Через 3 секунды после появления бомбы начинается процесс «взрыва», который я называю еще 4 способами на объекте self.bomb, чтобы «оживить» его взрыва.Отмена событий после вызова метода .after()?

Цель игры - попытаться «разоружить» бомбы. Я придумал какое-то причудливое обнаружение столкновений, которое работает. После столкновения обнаружено бомба очищаются от холста с помощью:

self.canvas.delete(self.bomb) 

Однако следующая анимация бомбы становится все больше и изменяющимся цветом (взрывающийся) все еще происходит, даже если я «разоружил» бомба. Это потому, что моя оригинальная бомба называет:

self.parent.after(3000, self.explode_first) 

... что я прикован более 3 «взрываются» функции, все связаны и вызывается методом .after().

Я попытался обойти проблему, вставив условные обозначения в каждый из методов, вызываемых в .after(), например booleans;

if self.bomb # if there's a bomb on the canvas, 
    self.parent.after(125, self.explode_second) # and explode third and so on 

который не работает. Я хочу, чтобы иметь возможность «отменить» события tkinter queue, которые были созданы с помощью метода after, но вот кикер. Я не могу (не могу) убить ВСЕ события, только те, что на холсте. У меня есть другие события, которые я хочу оставить без изменений, если это возможно.

Есть ли способ сделать это? Если нет, отзывы и/или предложения о том, как это сделать без отмены после событий, приветствуются, и спасибо заранее!

Heres соответствующий код, для справки:

def start_game(self): 
    self.Bombs += 1 
    self.bombsLabel.configure(text = "Total Bombs: %d" % self.Bombs) 
    self.b1 = random.randint(1, int(self.canvas.winfo_width())) 
    self.b2 = random.randint(1, int(self.canvas.winfo_height())) 
    self.b3 = self.b1 + 20 
    self.b4 = self.b2 + 20 
    self.create_bomb() 
    self.parent.after(10000, self.start_game) 

и:

# continuously make and explode bombs 
def create_bomb(self): 
    self.bomb = self.canvas.create_oval(self.b1, 
             self.b2, 
             self.b3, 
             self.b4, 
             fill = "red") 
    if self.bomb: 
     self.parent.after(3000, self.explode_first) 


def explode_first(self): 
    if self.bomb: 
     self.b1 -= 5 
     self.b2 -= 5 
     self.b3 += 5 
     self.b4 += 5 
     self.canvas.delete(self.bomb) 
     self.bomb = self.canvas.create_oval(self.b1, 
             self.b2, 
             self.b3, 
             self.b4, 
             fill = "orange") 
     self.parent.after(125, self.explode_second) 


def explode_second(self): 
    if self.bomb: 
     self.b1 -= 5 
     self.b2 -= 5 
     self.b3 += 5 
     self.b4 += 5 
     self.canvas.delete(self.bomb) 
     self.bomb = self.canvas.create_oval(self.b1, 
             self.b2, 
             self.b3, 
             self.b4, 
             fill = "yellow") 
     self.parent.after(125, self.explode_third) 


def explode_third(self): 
    self.b1 -= 5 
    self.b2 -= 5 
    self.b3 += 5 
    self.b4 += 5 
    self.canvas.delete(self.bomb) 
    self.bomb = self.canvas.create_oval(self.b1, 
             self.b2, 
             self.b3, 
             self.b4, 
             fill = "white") 
    self.parent.after(125, self.explode_fourth) 


def explode_fourth(self): 
    self.canvas.delete(self.bomb) 

def bomb_disarmed(self): 

    print "disarmed the bomb!" 
    self.canvas.delete(self.bomb) 
+0

Обновление: Итак, я использовал canvas.find_above (self.ball): как условное, который, кажется, работает. Однако просматривая документы для tkinter canvas, это кажется неаккуратным, и если я не разоружию бомбу, она останется там навсегда, где, как и раньше, они взорвутся. – ford

ответ

0

Вы можете добавить атрибут к классу, который вы работаете, как это:

self.isDisarmed = False 

Затем добавьте эту строку в bomb_disarmed:

self.isDisarmed = True 

Затем в explode_first, добавьте тест, чтобы увидеть, если бомба была снята с охраны:

def explode_first(self): 
    if self.bomb: 
     if self.isDisarmed: 
      self.parent.after(125, self.explode_fourth) # If bomb is disarmed, skip to the last step, where the bomb is deleted. 
     else:            # Otherwise, carry on with bomb explosion 
      self.b1 -= 5 
      self.b2 -= 5 
      self.b3 += 5 
      self.b4 += 5 
      self.canvas.delete(self.bomb) 
      self.bomb = self.canvas.create_oval(self.b1, 
              self.b2, 
              self.b3, 
              self.b4, 
              fill = "orange") 
      self.parent.after(125, self.explode_second) 

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

EDIT:

Re: рисование на холсте от метода другого класса App «s, вот один из способов:

class App: 
    def __init__(self, ...): 
     self.canvas = Tkinter.Canvas(...) 
     self.thingy = SomethingElse() 

class SomethingElse: 
    def __init__(self, parentApp): 
     self.parentApp = parentApp 
    def drawSomething(self): 
     self.parentApp.canvas.create_oval(...) 

a = App(...) 
s = SomethingElse(a) 
s.drawSomething() 
+0

Я полностью согласен со вторым битом там (я буду работать над реализацией и тестированием первого бита), но я действительно изо всех сил пытался добавить другие объекты в холст, который я инициализировал в своем основном классе. Есть ли указатели? казалось, что я не мог получить доступ к холсту App-класса любым способом, кроме как с методами, которые я строю в один класс. – ford

+0

Хм, не уверен, что вы имеете в виду. Пока вы передаете объект canvas другому методу, этот метод должен иметь возможность рисовать на холсте, независимо от того, к какому классу принадлежит этот метод. – Brionius

+0

Но в любом случае было бы проще, если бы методы класса «App' обрабатывали весь чертеж и просто имели« запрос »класса« Bomb », который он рисовал, вызывая метод из класса« App ». – Brionius

1

after метод возвращает идентификатор, который представляет собой запланированное событие.Если сохранить идентификатор, вы можете вызвать after_cancel отменить событие:

self.after_id = self.parent.after(3000, self.explode_first) 
... 
self.parent.after_cancel(self.after_id) 
Смежные вопросы