2016-04-23 2 views
0

У меня есть сетка на моем холсте, а в некоторых ячейках - круги. Моя цель - перемещать круги вокруг сетки, но не над другим кругом. Поэтому, когда я перемещаю круг, я проверяю, есть ли что-то на его пути, если это так, отмена движения. Сначала я попытался проверить столкновение в конце движения, но я не мог заставить его работать. Поэтому я пытаюсь проверить во время перемещения, но я понял, что линии холста также являются объектами, поэтому возникают столкновения. Есть ли «простой» способ игнорировать эти столкновения строк, но не круги?Как игнорировать некоторые столкновения Tkinter?

class Deplacement: 
def __init__(self, canvas, event): 
    self.x = event.x 
    self.y = event.y 
    self.canvas = canvas 
    self.obj = "à déterminer" 
    self.obj2 = "à déterminer" 
    self.couleur = "à déterminer" 
    self.couleur2 = "à déterminer" 
    self.collision = "à déterminer" 
    canvas.bind("<ButtonPress-1>", self.StartMove) 
    canvas.bind("B1-Motion", self.OnMotion) 
    canvas.bind("<ButtonRelease-1>", self.StopMove) 

def StartMove(self, event): #Getting the object I want to move 
    self.x = event.x 
    self.y = event.y 
    self.obj = self.canvas.find_overlapping(self.x - 15, self.y - 15, self.x + 15, self.y + 15) 

def OnMotion(self, event): #This is where I struggle 
    #Trying to get the second circle if it exists 
    self.obj2 = self.canvas.find_overlapping(event.x - 15, event.y - 15, event.x + 15, event.y + 15) 
    if not self.obj2: 
     self.collision = False 
    else: 
     self.collision = True 

def StopMove(self, event): #This works fine, in context, checking items colors to move them or not 
#And objects must be moved by one axis 
    self.couleur = self.canvas.itemcget(self.obj, "fill") 
    if not self.collision: 
     if self.couleur == 'black' or self.couleur == 'white' or self.couleur == 'red': 
      if event.x > self.x and self.y - 10 <= event.y <= self.y + 10: 
       self.move(event, self.obj) 
      elif event.x < self.x and self.y - 10 <= event.y <= self.y + 10: 
       self.move(event, self.obj) 
      elif event.y > self.y and self.x - 10 <= event.x <= self.x + 10: 
       self.move(event, self.obj) 
      elif event.y < self.y and self.x - 10 <= event.x <= self.x + 10: 
       self.move(event, self.obj) 

def move(self, event, obj): #Finally moving objects, works nicely aswell 
    self.x = (event.x - 20) // 50 + 1 
    self.y = (event.y - 20) // 50 + 1 
    self.obj = obj 
    if event.x < 20: 
     self.x = 1 
     self.canvas.coords(self.obj, self.x * 50 - 25, self.y * 50 - 25, self.x * 50 + 15, self.y * 50 + 15) 
    elif event.y < 20: 
     self.y = 1 
     self.canvas.coords(self.obj, self.x * 50 - 25, self.y * 50 - 25, self.x * 50 + 15, self.y * 50 + 15) 
    elif event.x > 470: 
     self.x = 9 
     self.canvas.coords(self.obj, self.x * 50 - 25, self.y * 50 - 25, self.x * 50 + 15, self.y * 50 + 15) 
    elif event.y > 470: 
     self.y = 9 
     self.canvas.coords(self.obj, self.x * 50 - 25, self.y * 50 - 25, self.x * 50 + 15, self.y * 50 + 15) 
    else: 
     self.canvas.coords(self.obj, self.x * 50 - 25, self.y * 50 - 25, self.x * 50 + 15, self.y * 50 + 15) 

PS: Игнорировать французские слова.

ответ

0

Я предполагаю, что переменная с именем canvas является экземпляром класса Canvas Tkinters. Вы не показывали код, который заполняет холст, но я предполагаю, что вы заполняете его вызовами метода, такими как canvas.create_line() или canvas.create_oval() и так далее. Каждый из этих методов возвращает целое число, которое является идентификатором созданной фигуры. Вы должны сохранить идентификаторы фигур, которые вы хотите игнорировать, другими словами, создать набор идентификаторов формы, которые не должны составлять столкновение. Предположим, вы положили их в набор с именем ignore_these.

Метод find_overlapping возвращает кортеж форм, которые перекрываются с указанным прямоугольником. Предположим, мы назовем это возвращаемое значение possible_collisions. Так сказать, если у вас есть столкновение нужна просто строка кода что-то вроде:

if any(s not in ignore_these for s in possible_collisions): 
    # handle the collision 
else: 
    # go ahead and make the move 

Это является двухступенчатый процессом (создать множество недействующих сталкивающихся форм, а затем использовать его для анализа результатов find_overlapping). Вы попросили простой способ сделать это, но я сомневаюсь, есть ли способ избежать этих двух шагов; Tkinter по крайней мере дал вам крючки, необходимые для написания необходимой логики.

Ручное задание: http://effbot.org/tkinterbook/canvas.htm#Tkinter.Canvas

+0

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

+0

Я не понимаю, почему это проще или почему это изменило бы размер фильтрации. Речь идет только о том, есть ли в вашей логике True или False. В любом случае вы должны фильтровать каждый раз, когда хотите сделать ход. Поскольку вопрос заключался в том, как «игнорировать» некоторые столкновения, я написал ответ в терминах набора объектов, которые должны быть проигнорированы, а не набора тех, которые не подлежат игнорированию. –

+0

нет, вы должны поддерживать две коллекции и проверять только столкновения на одном, содержащем встречные предметы. –

0

При добавлении элементов на холсте, методы, используемые вернуть уникальный идентификатор для этих объектов (целое число). Вы должны собрать эти идентификаторы в коллекции, с дополнительной коллекцией для идентификаторов предметов, которые сталкиваются. (Вы могли бы отделить элементы, которые не конфликтовать, но вы должны фильтровать их каждый раз, когда вы запускаете часть обнаружения столкновений)

Это псевдо-код:

def create_canvas_objects(self): 
    id = canvas.create_object() 
    self.all_canvas_objects_ids.append(id) 
    if object_collides: 
     self.colliding_objects.append(id) 

def check_collisions(self): 
    for object in self.colliding_objects: 
     check the collision 

Таким образом, вы фильтровать сталкиваясь с не сталкивающимися объектами только один раз при их создании, а не в каждом кадре.

+0

Я думаю, что понимаю, что вы имели в виду, но элементы не сталкиваются, когда они созданы, поэтому в процессе не было бы никаких сталкивающихся объектов. [link] (http://i.imgur.com/aSFQBxs.png?1) Это то, на что это похоже, поэтому никаких столкновений при запуске – Hedowas

+0

Да, в начале нет столкновений, но вы уже знаете, для чего тип элементов, которые вы хотите отслеживать столкновения (круги), и для которых вы не хотите. Вы добавляете все объекты ids в 'all_canvas_objects_ids', а круги также находятся в коллекции' colliding_objects'. Теперь вам нужно только отслеживать круги для коллизий, а не все объекты. –

+0

Поэтому я должен проверять каждое событие в моей функции OnMotion, если этот перекрывающийся объект находится в коллекции colliding_objects. Но если я это сделаю, когда мой указатель перемещается по кругу в не сталкивающуюся ячейку, движение разрешено, не так ли? – Hedowas