#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
графический интерфейс пользователя, и обычно у вас также не должно быть бесконечного цикла. В графическом интерфейсе уже есть бесконечный цикл — цикл событий.