You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 02:28:21