Чертежный код для перемещения овала
Я работаю над игрой в шашки для колледжа. Я нарисовал доску, используя tk, но я не могу реализовать функцию перемещения для фигур. Если кто-нибудь увидит какие-либо ошибки в моем коде или может предложить помощь, я был бы признателен. Вот полный источник. Заранее спасибо.
Я знаю, что это рисует кусочки шашки. Я не знаю, как перерисовать части, не удаляя другие части. Я посмотрел в Интернете на функцию перемещения и попробовал простой тест, который работал, но я не смог использовать его в своем коде.
Я знаю, что такое рекурсия, но мне нужна базовая функция для работы, то есть перемещение части на экране, прежде чем я реализую какие-либо дополнительные функции.
lst2 = []
#counter variable
i=0
#board variable is what stores the X/O/- values.
# It's a 2D list. We iterate over it, looking to see
# if there is a value that is X or O. If so, we draw
# text to the screen in the appropriate spot (based on
# i and j.
while i < len(board):
j=0
while j < len(board[i]):
if board[i][j] == 2:
lst2.append(canvas.create_oval((i+1)*width + width/2 + 15,
(j+1)*height + height/2 +15,(i+1)*width + width/2 - 15,
(j+1)*width + width/2 - 15, fill="Red",outline='Black'))
elif board[i][j] == 4:
lst2.append(canvas.create_oval((i+1)*width + width/2 + 15,
(j+1)*height + height/2 +15,(i+1)*width + width/2 - 15,
(j+1)*width + width/2 - 15, fill="Red",outline='Black'))
elif board[i][j] == 1:
lst2.append(canvas.create_oval((i+1)*width + width/2 + 15,
(j+1)*height + height/2 +15,(i+1)*width + width/2 - 15,
(j+1)*width + width/2 - 15, fill="Black",outline='Black'))
elif board[i][j] == 3:
lst2.append(canvas.create_oval((i+1)*width + width/2 + 15,
(j+1)*height + height/2 +15,(i+1)*width + width/2 - 15,
(j+1)*width + width/2 - 15, fill="Black",outline='Black'))
j+=1
i+=1
2 ответа
Вы можете переместить элемент на холсте, используя координаты и / или методы перемещения, чтобы изменить координаты с того, чем они являются, на то, что вы хотите, чтобы они были.
Вот простой пример, показывающий, как создать и переместить элемент на холсте:
import Tkinter as tk
class Example(tk.Frame):
'''Illustrate how to drag items on a Tkinter canvas'''
def __init__(self, parent):
tk.Frame.__init__(self, parent)
# create a canvas
self.canvas = tk.Canvas(width=400, height=400)
self.canvas.pack(fill="both", expand=True)
# this data is used to keep track of an
# item being dragged
self._drag_data = {"x": 0, "y": 0, "item": None}
# create a couple of movable objects
self._create_token((100, 100), "white")
self._create_token((200, 100), "black")
# add bindings for clicking, dragging and releasing over
# any object with the "token" tag
self.canvas.tag_bind("token", "<ButtonPress-1>", self.on_token_press)
self.canvas.tag_bind("token", "<ButtonRelease-1>", self.on_token_release)
self.canvas.tag_bind("token", "<B1-Motion>", self.on_token_motion)
def _create_token(self, coord, color):
'''Create a token at the given coordinate in the given color'''
(x,y) = coord
self.canvas.create_oval(x-25, y-25, x+25, y+25,
outline=color, fill=color, tags="token")
def on_token_press(self, event):
'''Begining drag of an object'''
# record the item and its location
self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0]
self._drag_data["x"] = event.x
self._drag_data["y"] = event.y
def on_token_release(self, event):
'''End drag of an object'''
# reset the drag information
self._drag_data["item"] = None
self._drag_data["x"] = 0
self._drag_data["y"] = 0
def on_token_motion(self, event):
'''Handle dragging of an object'''
# compute how much the mouse has moved
delta_x = event.x - self._drag_data["x"]
delta_y = event.y - self._drag_data["y"]
# move the object the appropriate amount
self.canvas.move(self._drag_data["item"], delta_x, delta_y)
# record the new position
self._drag_data["x"] = event.x
self._drag_data["y"] = event.y
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
6-е ИЗДАНИЕ: вот два решения для вас:
- (как предлагает Брайан) либо запомните старое местоположение перемещенного фрагмента, перерисовайте его там (=> нарисуйте его в цвете фона), перерисуйте его на новом месте
- проще: очистить и перерисовать всю доску
5-е РЕДАКТИРОВАНИЕ: Хорошо, спасибо за удаление кода.
Объясните точно, в чем проблема с вашим кодом для рисования на доске? "Перемещенный фрагмент не удален из старого местоположения"? "Все части нарисованы с неправильными координатами или цветами"? ...? Недопустимо просто сохранять дамп кода и говорить: "Этот код не работает".
"Я не знаю, как перерисовать части, не удаляя другие части". Я думаю, что это ваша проблема прямо здесь. Если вы объявите и позвоните
redrawBoard()
, он должен перерисовать ВСЕ части (!), а не только перемещенную часть. Согласен? то есть вы должны перебирать всю доску [][] и вызывать drawPiece() для каждой фигуры. Но ваш код, кажется, уже делает это?
Позвольте мне предложить вам, как очистить существующий код рисования доски, и в этом процессе вы почти наверняка найдете свою ошибку. Очевидно, что вам нужно очищать и перерисовывать экран каждый раз, когда происходит какое-либо движение (или продвижение), вы на самом деле это делаете? Объявить redrawBoard()
для этого. Если вы не сделаете очистку, то после хода фигура будет отображаться в ее старых И новых местах, что, очевидно, было бы неправильно?
(Комментарий о частоте кадров - это то, как часто холст будет обновляться каждую секунду. Меня удивляет, когда вы перерисовываете, вам не нужно перерисовывать 10 раз в секунду, если у вас также нет часов или других изменяющихся данных. Но, эй, это тоже работает.)
Во-первых, настоятельно рекомендуем использовать enum для самостоятельного документирования значений, используемых в board[][]
class Checkers():
EMPTY=0
RED_PIECE=1
RED_KING=2
BLACK_PIECE=3
BLACK_KING=4
Далее вы можете значительно убрать код рисования доски. Так как все 4 случая рисования фрагментов вызывают общий случай, сделайте его fn, и сделайте этот fn незагроможденным:
def drawPiece(i,j,fillColor,outlineColor):
"""Draw single piece on screen."""
x = (i+1)*width + width/2
y = (j+1)*height + height/2
lst2.append(canvas.create_oval(x+15,y+15,x-15,y-15,fill=fillColor,outline=outlineColor))
Теперь код рисования доски, который вызывает их строго, имеет только два случая: (2,4) или (1,3), если вы правильно выполнили перечисление:
и, между прочим, никогда не используйте цикл while, когда более понятный цикл for:
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] in (RED_PIECE,RED_KING):
drawPiece(i,j,'Red','Black')
elif board[i][j] in (BLACK_PIECE,BLACK_KING):
drawPiece(i,j,'Black','Black')
Разве это не бесконечно легче читать и отлаживать? Это самодокументирование. Теперь ваша ошибка должна практически выпрыгнуть на вас.
(Кстати, вы сейчас рисуете королей точно так же, как фигуры, но я думаю, вы исправите это позже.)
4-е РЕДАКТИРОВАНИЕ: Вы заставили нас смотреть неправильные fns, grr... вы говорите, что ваша ошибка на самом деле в коде рисования доски. Не могли бы вы исправить заголовок, который по-прежнему гласит "Реализация функции движения"?
ОРИГИНАЛЬНЫЙ ОТВЕТ: О том, что жаждет машина, это не вопрос - пока нет: расскажите нам, что вы сейчас пробуете, и почему это не работает. Также удалите весь несвязанный код.
Похоже, у вас проблемы с функцией moveTo(i,j)
- а что именно?
(Глобал secondPass, secondPosition сигнализируют, что у вас могут быть проблемы... знаете ли вы рекурсию? Если нет, то не беспокойтесь.)
Кроме того, как стилистическая вещь, и чтобы сделать вашу жизнь проще, эта реализация не является ОО, глобальные крики кричат о плохой декомпозиции. Попробуйте переписать как класс Checkers
, сделайте правление и т.д. членом, напишите init()
метод. Я бы переименовал функцию grid(x,y)
в initialize(nrows,ncols)
,
(И кашель, кашель! Признаки того, что вы адаптировали это от кого-то другого...)
#Frame rate is how often canvas will be updated
# each second. For Tic Tac Toe, 10 should be plenty.
FRAME_RATE = 10