Перемещение шара внутри виджета Tkinter Canvas (простая арканоидная игра)

#python #canvas #tkinter

#python #холст #tkinter

Вопрос:

Я пытаюсь написать простой арканоид с помощью Python и Tkinter. Цель состоит в том, чтобы заставить мяч отражаться от верхней, правой и левой сторон. И если игрок пропустит мяч, так что он коснется нижней стороны, игра остановится.

Вот код:

 from Tkinter import *
import time

root = Tk()
canv = Canvas(root, highlightthickness=0)
canv.pack(fill='both', expand=True)
top = canv.create_line(0, 0, 640, 0, fill='green', tags=('top'))
left = canv.create_line(0, 0, 0, 480, fill='green', tags=('left'))
right = canv.create_line(639, 0, 639, 480, fill='green', tags=('right'))
bottom = canv.create_line(0, 478, 640, 478, fill='red', tags=('bottom'))

rect = canv.create_rectangle(270, 468, 365, 478, outline='black', fill='gray40', tags=('rect'))
ball = canv.create_oval(0, 20, 20, 40, outline='black', fill='gray40', tags=('ball'))

delta_x = delta_y = 3
new_x, new_y = delta_x, -delta_y
while True:
    time.sleep(0.025)
    if canv.find_overlapping(canv.coords(ball)[0], canv.coords(ball)[1], canv.coords(ball)[2], canv.coords(ball)[3])[0] == 1:
        new_x, new_y = delta_x, -delta_y
        canv.move(ball, new_x, new_y)
        print 'fitst if', new_x, new_y
    if canv.find_overlapping(canv.coords(ball)[0], canv.coords(ball)[1], canv.coords(ball)[2], canv.coords(ball)[3])[0] == 2:
        new_x, new_y = delta_x, delta_y
        canv.move(ball, new_x, new_y)
        print '2nd if', new_x, new_y
    if canv.find_overlapping(canv.coords(ball)[0], canv.coords(ball)[1], canv.coords(ball)[2], canv.coords(ball)[3])[0] == 3:
        new_x, new_y = -delta_x, delta_y
        canv.move(ball, new_x, new_y)
    if canv.find_overlapping(canv.coords(ball)[0], canv.coords(ball)[1], canv.coords(ball)[2], canv.coords(ball)[3])[0] == 4:
        new_x, new_y = delta_x, -delta_y
        canv.move(ball, new_x, new_y)
    print new_x, new_y
    canv.move(ball, new_y, new_y)
    canv.update()

def move_right(event):
        canv.move(rect, 7, 0)
        pass

def move_left(event):
    canv.move(rect, -7, 0)
    pass

root.bind('<Right>', move_right)
root.bind('<Left>', move_left)

root.geometry('%sx%s %s %s' %(640, 480, 100, 100))
root.resizable(0, 0)
root.mainloop()
  

Почему шар отражается неправильно?

скриншот программы

Комментарии:

1. Разве «отражение» не подразумевает движение? Сначала вам нужно переместить шар, периодически обновляя его положение в зависимости от скорости. После того, как вы переместите шар, когда его ограничивающая рамка пересечет прямоугольник, измените знак скорости (например, скорость x от 5 до -5) в зависимости от того, с какой стороны произошло пересечение. Кроме того, если это домашнее задание, пожалуйста, добавьте тег «домашнее задание».

2. Вам действительно следует избегать использования while True и. time.sleep Ни один из них не работает хорошо с циклом событий. Используйте код, подобный тому, который я показал вам, с помощью которого вы обновляете экран after .

3. ваш код не выполняется. Вообще. В нем есть ошибки отступа, и он ссылается на «self», который нигде не задается.

4. @BryanOakley, я только что исправил код. теперь он должен работать.

Ответ №1:

Для перемещения объекта вам нужно использовать coords метод или move метод, который изменяет координаты объекта. Вы можете использовать coords метод для получения текущих координат.

Для создания анимации вы можете использовать after . Вызовите функцию, затем попросите ее after снова вызвать себя через короткое время в будущем. Как далеко в будущем будет определяться ваша частота кадров (т. Е. Каждые 10 мс означают примерно 100 кадров в секунду)

Например:

 def moveit(self):

    # move the object
    <get the existing coordinates using the coords method>
    <adjust the coordinates relative to the direction of travel>
    <give the object new coordinates using the coords method>

    # cause this movement to happen again in 10 milliseconds
    self.after(10, self.moveit)
  

Как только вы вызываете moveit() только один раз, начинается цикл. Этот же метод можно использовать для обновления нескольких объектов, или у вас могут быть разные методы для разных объектов.

редактировать: Вы полностью изменили свой вопрос с «как мне переместить что-то на холсте?» на «почему оно движется в неправильном направлении?». Ответ на последний вопрос прост: вы говорите ему двигаться в неправильном направлении. Используйте отладчик или некоторые инструкции печати, чтобы увидеть, где и как вы вычисляете delta_y.

Ответ №2:

вот простой способ решения этой проблемы:

 delta_x = delta_y = 3
while True:
      objects = canv.find_overlapping(canv.coords(ball)[0], canv.coords(ball)[1], canv.coords(ball)[2], canv.coords(ball)[3])
      for obj in objects:
        if obj == 1:
            delta_y = -delta_y
        if obj == 2:
            delta_x = -delta_x
        if obj == 3:
            delta_x = -delta_x
        if obj == 4:
            delta_y = -delta_y

      new_x, new_y = delta_x, delta_y
      canv.move(ball, new_x, new_y)
      canv.update()
      time.sleep(0.025)

      root.bind('<Right>', move_right)
      root.bind('<Left>', move_left)
  

Комментарии:

1. Этот ответ показывает менее оптимальный способ создания анимации. Вы не должны вызывать sleep графический интерфейс пользователя, и обычно у вас также не должно быть бесконечного цикла. В графическом интерфейсе уже есть бесконечный цикл — цикл событий.