Tkinter中使用canvas.coords更新多边形坐标导致图形消失求助
问题解决与代码修复
你的代码存在三个核心问题,导致飞船在执行canvas.coords后消失:
1. 事件绑定错误,初始化时直接执行了旋转函数
在Game类的binds方法中,self.root.bind('<a>', self.player1.rotate(1))会立即调用rotate(1),而不是绑定按键触发的回调。这会导致程序启动时就执行旋转逻辑,飞船初始位置被错误修改。
修复方式:使用lambda包装回调,传递事件参数:
def binds(self): self.root.bind('<a>', lambda e: self.player1.rotate(1))
2. 质心计算函数错误,X坐标未累加
Ship类的centroid函数中,temp1变量未累加任何X坐标值,始终为0,导致质心的X坐标错误为0。旋转时飞船会被错误平移到X=0的区域,超出可见范围。
修复方式:补充X坐标的累加:
def centroid(self): temp1 = 0 temp2 = 0 inc = 0 for i in range(len(self.pos)): temp1 += self.pos[i][0] # 修复:累加X坐标 temp2 += self.pos[i][1] inc += 1 return((temp1/inc, temp2/inc))
3. 旋转公式错误,坐标计算逻辑颠倒
原旋转公式的三角函数应用顺序和符号错误,导致旋转后的坐标完全偏离预期位置。正确的2D旋转公式(绕原点旋转θ弧度)应为:
- 新X = 原X * cosθ - 原Y * sinθ
- 新Y = 原X * sinθ + 原Y * cosθ
同时,旋转前需要将点平移到质心(减去质心坐标),旋转后再平移回原位置(加上质心坐标)。
修复后的rotate函数:
def rotate(self, theta): theta = (theta * math.pi) / 180 cx, cy = self.centroid() # 提前计算质心,避免重复调用 # 1. 将所有点平移到以质心为原点的坐标系 translated = [] for x, y in self.pos: translated.append((x - cx, y - cy)) # 2. 应用旋转公式 rotated = [] cos_theta = math.cos(theta) sin_theta = math.sin(theta) for x, y in translated: new_x = x * cos_theta - y * sin_theta new_y = x * sin_theta + y * cos_theta rotated.append((new_x, new_y)) # 3. 平移回原坐标系 new_pos = [] for x, y in rotated: new_pos.append((x + cx, y + cy)) # 更新位置并刷新画布 self.pos = new_pos self.canvas.coords(self.ship, sum(new_pos, ())) # 扁平化坐标列表
完整修复后的代码
Game类
import tkinter as tk import math from ship import Ship class Game: def __init__(self, gamewidth, gameheight): self.root = tk.Tk() self.gamewidth = gamewidth self.gameheight = gameheight self.canvas = tk.Canvas(height=self.gameheight, width=self.gamewidth, bg="black") self.objects() self.binds() self.canvas.pack() self.root.mainloop() def objects(self): self.player1 = Ship(self.canvas) def binds(self): self.root.bind('<a>', lambda e: self.player1.rotate(1)) # 可添加反向旋转绑定 self.root.bind('<d>', lambda e: self.player1.rotate(-1)) gun = Game(700, 500)
Ship类
import math import tkinter as tk class Ship: def __init__(self, canvas): self.pos = [(5, 5), (5, 25), (30, 15)] self.canvas = canvas self.ship = self.canvas.create_polygon(self.pos, outline="white", fill="white") def rotate(self, theta): theta = (theta * math.pi) / 180 cx, cy = self.centroid() # 平移到质心原点 translated = [(x - cx, y - cy) for x, y in self.pos] # 旋转计算 cos_theta = math.cos(theta) sin_theta = math.sin(theta) rotated = [ (x * cos_theta - y * sin_theta, x * sin_theta + y * cos_theta) for x, y in translated ] # 平移回原位置 self.pos = [(x + cx, y + cy) for x, y in rotated] # 更新画布上的飞船坐标 self.canvas.coords(self.ship, sum(self.pos, ())) def centroid(self): total_x = sum(x for x, y in self.pos) total_y = sum(y for x, y in self.pos) count = len(self.pos) return (total_x / count, total_y / count)
优化提问的建议
- 明确说明复现步骤:比如“程序启动后飞船直接消失”还是“按下A键后消失”
- 补充错误现象细节:比如是否在控制台看到报错,或者通过打印坐标发现位置异常
- 简化代码示例:保留最小可复现的代码,去掉无关部分(比如未使用的变量)
内容的提问来源于stack exchange,提问作者FacelessAnt
相关产品推荐
相关产品推荐

