绘制椭圆的代码移动
我正在为大学做一个Python的跳棋游戏。我已经用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 个回答
第六次编辑:这里有两个解决方案给你:
- (正如Bryan所建议的)记住被移动棋子的旧位置,在那里把它“擦掉”(也就是用背景颜色画),然后在新位置重新画上它。
- 更简单的方法:清空并重新绘制整个棋盘。
第五次编辑:谢谢你简化了代码。
请准确说明你的棋盘绘制代码有什么问题?“移动的棋子没有从旧位置删除”?“所有棋子都画在错误的坐标或颜色上”?……只是一味地扔代码并说“这段代码不工作”是不可接受的。
“我不知道如何重新绘制棋子,而不删除其他棋子。”我觉得这就是你的问题所在。如果你声明并调用
redrawBoard()
,它应该重新绘制所有棋子,而不仅仅是移动的那个。你同意吗?也就是说,你必须遍历整个board[][],并对每个棋子调用drawPiece()。但你的代码似乎已经这样做了?
让我建议你如何清理现有的棋盘绘制代码,在这个过程中你几乎肯定会找到你的错误。显然,每次移动(或升变)时,你都需要清空并重新绘制屏幕,你真的这样做了吗?为此声明一个函数redrawBoard()
。如果你不清空,那么在移动后,棋子会同时显示在旧位置和新位置,这显然是错误的吧?(关于帧率是画布每秒更新的频率。的评论让我想知道,当你重新绘制时,除非你还有时钟或其他变化的数据,否则不需要每秒重绘10次。不过,这样也可以。)
首先,强烈建议你使用枚举来自我记录board[][]中使用的值。
class Checkers():
EMPTY=0
RED_PIECE=1
RED_KING=2
BLACK_PIECE=3
BLACK_KING=4
接下来,你可以大大简化棋盘绘制代码。因为所有四种棋子绘制情况都调用一个公共的情况,所以把它做成一个函数,并让这个函数简洁明了:
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),假设你正确使用了枚举:
顺便说一下,永远不要在可以用更清晰的for循环替代的地方使用while循环:
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')
这样的分解是不是容易得多阅读和调试?它是自我记录的。现在你的错误应该几乎会跳出来让你看到。
(顺便说一下,你现在绘制国王的方式和其他棋子是一样的,但我想你会在之后修复这个问题。)
第四次编辑:你让我们看到了错误的函数,真让人恼火……你说你的错误实际上在棋盘绘制代码中。请你改正标题,现在仍然写着“实现一个移动函数”吗?
原始回复:正如machine yearning所说,这还不是一个问题:告诉我们你目前尝试了什么,以及为什么它不工作。同时,去掉所有无关的代码。
看起来你在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
你可以通过使用 coords 方法和/或 move 方法来移动画布上的一个物品,这样就能把它的位置从现在的坐标改成你想要的位置。
下面是一个简单的例子,展示了如何在画布上创建并移动一个物品:
import tkinter as tk # python 3
# import Tkinter as tk # python 2
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, background="bisque")
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.drag_start)
self.canvas.tag_bind("token", "<ButtonRelease-1>", self.drag_stop)
self.canvas.tag_bind("token", "<B1-Motion>", self.drag)
def create_token(self, x, y, color):
"""Create a token at the given coordinate in the given color"""
self.canvas.create_oval(
x - 25,
y - 25,
x + 25,
y + 25,
outline=color,
fill=color,
tags=("token",),
)
def drag_start(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 drag_stop(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 drag(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()