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

Pygame开发Undertale战斗系统:心形角色移动速度异常求助

Undertale战斗系统心形角色移动问题修复

问题概述

开发Undertale风格战斗系统时碰到两个问题:

  • 心形角色按方向键移动后,松开按键不会停止,持续移动;
  • 角色碰撞战斗框边界时会来回弹跳,而不是停在框内。

问题根源

  1. 按键处理逻辑缺陷:原代码用KEYDOWN/KEYUP事件累加/抵消速度,这种方式依赖按键触发顺序,若同时按下多个方向键,会导致速度计算混乱。比如先按左(speed_x=-4)再按右(speed_x=0),松开左时会加4,speed_x变为4,角色持续向右移动。
  2. 边界碰撞逻辑错误:原代码碰撞边界时反转速度,导致角色在边界来回弹跳,不符合Undertale的移动逻辑(角色应被限制在战斗框内,无法移出)。

修复方案

1. 改用实时按键状态检测

用pygame.key.get_pressed()在主循环中实时获取所有按键状态,每个方向单独判断,按下时设置对应速度,松开时直接设为0,彻底避免速度累加错误。

2. 重写边界限制逻辑

计算战斗框的有效移动区域,直接将角色坐标限制在该区域内,确保角色无法移出战斗框。

完整修复代码

import pygame
import sys

# setup
pygame.init()
clock = pygame.time.Clock()

# main window
screen_width = 900
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Undertale')
icon = pygame.image.load('heart.png')
pygame.display.set_icon(icon)

# game rectangles
heart = pygame.image.load('heart.png')
DEFAULT_IMAGE_SIZE = (20, 20)
heart_img = pygame.transform.scale(heart, DEFAULT_IMAGE_SIZE)
heart_width, heart_height = DEFAULT_IMAGE_SIZE

battle_width = 10
battle_height = 200
middle_offset = 30
# 计算战斗框的有效移动区域(去掉边框宽度,角色在内部移动)
battle_inner_left = screen_width/2 - 100 + battle_width
battle_inner_right = screen_width/2 + 100
battle_inner_top = screen_height/2 + middle_offset + battle_width
battle_inner_bottom = screen_height/2 + middle_offset + battle_height

# 绘制战斗框的四个边框
battle_left = pygame.Rect(screen_width/2 - 100, screen_height/2 + middle_offset, battle_width, battle_height)
battle_right = pygame.Rect(screen_width/2 + 100, screen_height/2 + middle_offset, battle_width, battle_height)
battle_up = pygame.Rect(screen_width/2 - 100, screen_height/2 + middle_offset, 200 + 2*battle_width, battle_width)
battle_down = pygame.Rect(screen_width/2 - 100, screen_height/2 + middle_offset + battle_height, 200 + 2*battle_width, battle_width)

# colours
bg_color = pygame.Color(0, 0, 0)
white = (255, 255, 255)

# game vars
# 初始位置设为战斗框中心
heart_x = battle_inner_left + (battle_inner_right - battle_inner_left - heart_width)/2
heart_y = battle_inner_top + (battle_inner_bottom - battle_inner_top - heart_height)/2
speed = 4

while True:
    # 处理退出事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    # 改用实时按键状态检测,替代原事件驱动逻辑
    keys = pygame.key.get_pressed()
    heart_speed_x = 0
    heart_speed_y = 0
    if keys[pygame.K_LEFT]:
        heart_speed_x -= speed
    if keys[pygame.K_RIGHT]:
        heart_speed_x += speed
    if keys[pygame.K_UP]:
        heart_speed_y -= speed
    if keys[pygame.K_DOWN]:
        heart_speed_y += speed

    # 更新角色位置
    heart_x += heart_speed_x
    heart_y += heart_speed_y

    # 边界限制逻辑:确保角色在战斗框内部,不会超出
    heart_x = max(battle_inner_left, min(heart_x, battle_inner_right - heart_width))
    heart_y = max(battle_inner_top, min(heart_y, battle_inner_bottom - heart_height))

    # visuals
    screen.fill(bg_color)
    pygame.draw.rect(screen, white, battle_left)
    pygame.draw.rect(screen, white, battle_right)
    pygame.draw.rect(screen, white, battle_up)
    pygame.draw.rect(screen, white, battle_down)
    screen.blit(heart_img, (heart_x, heart_y))

    # window update
    pygame.display.flip()
    clock.tick(60)

代码修改说明

  • 新增battle_inner_*变量,明确战斗框的有效移动区域(去掉边框);
  • 替换按键处理逻辑:用pygame.key.get_pressed()实时检测,每次循环重置速度,避免累加错误;
  • 重写边界限制:用max()和min()直接限制角色坐标,确保不会超出战斗框;
  • 调整初始位置为战斗框中心,更符合Undertale的初始状态。

内容的提问来源于stack exchange,提问作者Elyctricity

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 08:20:34