使用Tkinter Canvas.move()实现外星人移动时拖影问题的解决请求
解决Tkinter太空侵略者游戏外星人移动拖影问题
我用Python的Tkinter制作《太空侵略者》游戏时,遇到了外星人横向移动留下像素拖影的问题。玩家和激光用同样的Canvas.move()方法却没有这个问题,现在外星人移动逻辑还没完成,想先解决拖影,让外星人正常向右移动。我是编程新手,Tkinter和游戏开发经验不足,附上外星人相关代码恳请帮助。
外星人相关代码(不含玩家和激光部分)
from tkinter import * # Graphical user interface (GUI) module as part of standard library import random import time GAME_WIDTH = 1000 GAME_HEIGHT = 500 ALIEN_SPEED = 100 ALIEN_SIZE = 50 BACKGROUND_COLOUR = "black" score = 0 #initial score direction = "right" #initial direction aliens = [] #global variable to create a row of aliens #initial set up window = Tk() #from tkinter to create the window window.title("Alien Game") label = Label(window, text = f"Score: {score}", font = ('consolas', 40)) label.pack() canvas = Canvas(window, background= BACKGROUND_COLOUR, height= GAME_HEIGHT, width= GAME_WIDTH) canvas.pack() class Alien: #create individual alien body def __init__(self, x, y): self.x, self.y = x, y self.body = [] self.face = canvas.create_rectangle(self.x, self.y, self.x+ALIEN_SIZE, self.y+ALIEN_SIZE, fill = 'yellow', outline='', width=0) self.eye1 = canvas.create_rectangle(self.x+0.2*ALIEN_SIZE, self.y+0.2*ALIEN_SIZE, self.x+0.4*ALIEN_SIZE, self.y+0.4*ALIEN_SIZE, fill = 'black', outline='', width=0) self.eye2 = canvas.create_rectangle(self.x+0.6*ALIEN_SIZE, self.y+0.2*ALIEN_SIZE, self.x+0.8*ALIEN_SIZE, self.y+0.4*ALIEN_SIZE, fill = 'black', outline='', width=0) self.mouth = canvas.create_rectangle(self.x+0.2*ALIEN_SIZE, self.y+0.8*ALIEN_SIZE, self.x+0.8*ALIEN_SIZE, self.y+ALIEN_SIZE, fill = 'black', outline='', width=0) self.body.extend((self.face, self.eye1, self.eye2, self.mouth)) def create_aliens(): # create multiple aliens in a row for i in range (int((GAME_WIDTH/(2*ALIEN_SIZE))*0.8)): aliens.append(Alien(x = i*2*ALIEN_SIZE, y = ALIEN_SIZE/2)) return aliens def move_aliens(): #move row of alien across screen global direction aliens = create_aliens() if direction == 'right': if aliens[-1].x <= (GAME_WIDTH-ALIEN_SIZE): # test if reached screen edge for alien in aliens: for body_part in alien.body: canvas.move(body_part, 10, 0) else: direction = 'left' elif direction == 'left': if aliens[0].x >= (0): for alien in aliens: canvas.move(alien.body, -5, 0) alien.x -=5 else: direction = 'right' print (direction) window.after(ALIEN_SPEED, move_aliens) #to centre the window on the screen (top left is position 0,0) window.update() x= int((window.winfo_screenwidth() - window.winfo_width())/2) #centre x position y = int((window.winfo_screenheight() - window.winfo_height())/2) #centre y position window.geometry(f'{window.winfo_width()}x{window.winfo_height()}+{x}+{y-30}') #format of (window width) x (window height) at + (position width) + (position height) move_aliens() window.mainloop()
问题截图
- 初始状态:

- 移动后状态:

问题根源与解决方法
问题出在哪?
每次调用move_aliens()时,你都执行了aliens = create_aliens(),这会重新创建一整排外星人,而之前的外星人并没有被删除。旧外星人留在画布上,新外星人跟着移动,就出现了拖影。另外,向右移动时没有更新外星人的self.x属性,导致判断边界的逻辑失效,外星人会一直往右跑。
修改步骤
- 只初始化一次外星人:在游戏启动时调用
create_aliens(),不要在move_aliens()里重复创建 - 同步外星人坐标:每次移动后更新外星人的
self.x,保证边界判断准确 - 修正移动逻辑:移除
move_aliens()里的create_aliens()调用,直接使用全局的aliens列表
修改后的完整代码
from tkinter import * import time GAME_WIDTH = 1000 GAME_HEIGHT = 500 ALIEN_SPEED = 100 ALIEN_SIZE = 50 BACKGROUND_COLOUR = "black" score = 0 direction = "right" aliens = [] window = Tk() window.title("Alien Game") label = Label(window, text = f"Score: {score}", font = ('consolas', 40)) label.pack() canvas = Canvas(window, background= BACKGROUND_COLOUR, height= GAME_HEIGHT, width= GAME_WIDTH) canvas.pack() class Alien: def __init__(self, x, y): self.x, self.y = x, y self.body = [] self.face = canvas.create_rectangle(self.x, self.y, self.x+ALIEN_SIZE, self.y+ALIEN_SIZE, fill = 'yellow', outline='', width=0) self.eye1 = canvas.create_rectangle(self.x+0.2*ALIEN_SIZE, self.y+0.2*ALIEN_SIZE, self.x+0.4*ALIEN_SIZE, self.y+0.4*ALIEN_SIZE, fill = 'black', outline='', width=0) self.eye2 = canvas.create_rectangle(self.x+0.6*ALIEN_SIZE, self.y+0.2*ALIEN_SIZE, self.x+0.8*ALIEN_SIZE, self.y+0.4*ALIEN_SIZE, fill = 'black', outline='', width=0) self.mouth = canvas.create_rectangle(self.x+0.2*ALIEN_SIZE, self.y+0.8*ALIEN_SIZE, self.x+0.8*ALIEN_SIZE, self.y+ALIEN_SIZE, fill = 'black', outline='', width=0) self.body.extend((self.face, self.eye1, self.eye2, self.mouth)) def create_aliens(): for i in range (int((GAME_WIDTH/(2*ALIEN_SIZE))*0.8)): aliens.append(Alien(x = i*2*ALIEN_SIZE, y = ALIEN_SIZE/2)) return aliens def move_aliens(): global direction # 移除重复创建外星人的代码 if direction == 'right': # 用最后一个外星人的当前x判断边界 if aliens[-1].x <= (GAME_WIDTH - ALIEN_SIZE - 10): # 减去移动步长,避免超出屏幕 for alien in aliens: for body_part in alien.body: canvas.move(body_part, 10, 0) alien.x += 10 # 更新外星人的x坐标 else: direction = 'left' elif direction == 'left': if aliens[0].x >= 10: # 减去移动步长,避免超出屏幕 for alien in aliens: for body_part in alien.body: canvas.move(body_part, -10, 0) alien.x -= 10 # 更新外星人的x坐标 else: direction = 'right' window.after(ALIEN_SPEED, move_aliens) # 初始化窗口位置 window.update() x= int((window.winfo_screenwidth() - window.winfo_width())/2) y = int((window.winfo_screenheight() - window.winfo_height())/2) window.geometry(f'{window.winfo_width()}x{window.winfo_height()}+{x}+{y-30}') # 只创建一次外星人 create_aliens() move_aliens() window.mainloop()
关键修改点说明
- 把
create_aliens()的调用移到move_aliens()外面,游戏启动时只创建一次外星人 - 向右移动时,每次移动后更新
alien.x +=10,保证和Canvas元素的实际位置同步 - 边界判断时减去移动步长,避免外星人刚好碰到边界时就转向,导致视觉上的卡顿
- 左右移动的步长统一为10,让移动更平滑
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

