绘制棋盘代码来移动椭圆
- 2025-03-12 08:50:00
- admin 原创
- 56
问题描述:
我正在为大学开发一款 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
解决方案 1:
您可以使用坐标和/或移动方法移动画布上的项目,以将坐标从原来的坐标更改为您想要的坐标。
这是一个简单的例子,展示如何在画布上创建和移动一个项目:
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()
解决方案 2:
第六次编辑:这里有两个解决方案供您使用:
(正如 Bryan 建议的那样)要么记住移动棋子的旧位置,在那里取消绘制(=> 用背景颜色绘制),要么在新位置重新绘制它
更简单:清除并重新绘制整个棋盘
第五次编辑:好的,谢谢您删去代码。
请准确解释一下您的棋盘绘制代码存在什么问题?“移动的棋子未从原位置删除”?“所有棋子都绘制在错误的坐标或颜色上”?……?
只是不断地转储代码并说“此代码不起作用”是不可接受的。
“我不知道如何在不删除其他棋子的情况下重新绘制棋子。”
我认为这就是你的问题所在。如果你声明并调用redrawBoard()
,它应该重新绘制所有棋子(!),而不仅仅是移动的棋子。同意吗?即你必须遍历整个 board[][] 并对每个棋子调用 drawPiece()。但你的代码似乎已经做到了这一点?
让我建议你如何清理现有的棋盘绘制代码,在此过程中,你几乎肯定会发现你的错误。显然,每次移动(或升级)时,你都需要清除并重新绘制屏幕,你真的会这样做吗?redrawBoard()
为此声明一个 fn。如果你不清除,那么移动后,棋子将显示在其旧位置和新位置,这显然是错误的?(关于帧速率的评论是画布每秒更新的频率。这让我想知道当你重新绘制时,你不需要每秒重新绘制 10 次,除非你还有时钟或其他变化数据。但是,嘿,这也有效。)
首先,强烈建议您使用枚举来自我记录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')
这种分解不是更容易阅读和调试吗?它是自文档化的。现在你的错误应该会立即显现出来。
(顺便说一句,你现在画的王和棋子一模一样,但我想你稍后会解决这个问题。)
第四次编辑:你让我们看错了 fns,哎呀……你说你的错误实际上是在画板代码中。你能更正一下标题吗?标题仍然是“实现移动功能”?
原始回复: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
扫码咨询,免费领取项目管理大礼包!