You need to enable JavaScript to run this app. Pygame棋盘类游戏单格移动:解决Tile节点停滞后无法继续移动问题
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.08 20:24:01