Pygame棋盘类游戏单格移动:解决Tile节点停滞后无法继续移动问题
棋盘格单步移动实现方案
原逻辑核心问题
- 无状态隔离:只要玩家坐标等于Tile坐标,就无条件将移动速度置0,没有区分“移动过程中刚抵达格位”和“停在格位等待输入”两种场景,导致停驻时的坐标匹配判断会持续抵消新输入触发的移动速度,玩家无法再次移动
- 逻辑耦合:将坐标判定、事件输入、状态修改全揉在事件遍历流程中,触发条件没有生效范围限制
具体调整步骤
1. 为玩家新增状态标识属性
首先给Player类补充两个核心属性,拆分移动与停驻状态:
class Player: def __init__(self): # 基础坐标与速度属性 self.x = TileModel.xCoords[0] self.y = TileModel.yCoords[0] self.xChange = 0 self.yChange = 0 self.move_step = 8 # 单帧移动的像素步长,小于Tile间距保证平滑 # 新增状态属性 self.is_moving = False # 标记当前是否处于格间移动过程 self.prev_x = self.x # 记录上一帧x坐标,用于跨点检测 self.prev_y = self.y # 记录上一帧y坐标,用于跨点检测
2. 拆分循环内的逻辑流程
将原来混在一起的逻辑拆成三个独立执行的模块,彻底切断停驻状态下的速度抵消链路:
模块1:事件输入检测(仅响应停驻状态下的新指令)
def game(): running = True while running: # 遍历事件队列 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # 仅当玩家停驻在格位时,才响应新的方向按键 if event.type == pygame.KEYDOWN and not player.is_moving: if event.key == pygame.K_a: player.xChange = -player.move_step player.is_moving = True elif event.key == pygame.K_d: player.xChange = player.move_step player.is_moving = True elif event.key == pygame.K_w: player.yChange = -player.move_step player.is_moving = True elif event.key == pygame.K_s: player.yChange = player.move_step player.is_moving = True
模块2:逐帧坐标更新
在事件遍历完成后,按当前速度更新玩家坐标,不要在事件循环内做坐标更新:
# 记录更新前的坐标,供后续跨点检测 player.prev_x = player.x player.prev_y = player.y # 更新当前坐标 player.x += player.xChange player.y += player.yChange
模块3:抵达格位检测(仅生效于移动状态)
这部分逻辑是解决原问题的核心:只有在玩家处于is_moving = True的移动过程中,才会执行Tile匹配与速度清零操作。停在格位上时哪怕坐标完全等于Tile坐标,也不会触发任何速度修改逻辑。
同时为了避免移动步长过大导致坐标不连续、永远碰不上精确Tile坐标的问题,用跨点判断替代直接坐标相等判断:
# 仅在移动状态下做抵达检测 if player.is_moving: # 检测x方向是否抵达任意Tile的x坐标 for target_x in TileModel.xCoords: # 判断移动路径是否已经跨过目标x坐标 if (player.xChange > 0 and player.prev_x < target_x <= player.x) or \ (player.xChange < 0 and player.x <= target_x < player.prev_x): # 强制对齐到Tile精确坐标,消除步长带来的误差 player.x = target_x player.xChange = 0 # x方向抵达后,如果y方向已经停止,就重置为停驻状态 if player.yChange == 0: player.is_moving = False break # 检测y方向是否抵达任意Tile的y坐标,逻辑与x方向一致 for target_y in TileModel.yCoords: if (player.yChange > 0 and player.prev_y < target_y <= player.y) or \ (player.yChange < 0 and player.y <= target_y < player.prev_y): player.y = target_y player.yChange = 0 if player.xChange == 0: player.is_moving = False break
可选的停顿效果实现
如果需要模拟象棋走棋的短暂停驻感,只需要在抵达检测触发时增加一个帧计数逻辑:
- 抵达Tile时初始化
pause_counter = 10(对应10帧停顿,约160ms) - 每帧将计数器减1,计数器归0之前,哪怕检测到按键输入,也不触发新的移动指令
- 计数器归0后,恢复按键响应能力,即可实现单步移动-短暂停顿-再响应下一次输入的效果
内容的提问来源于stack exchange,提问作者Suikyo
相关产品推荐
相关产品推荐

