Pygame开发Undertale战斗系统:心形角色移动速度异常求助
Undertale战斗系统心形角色移动问题修复
问题概述
开发Undertale风格战斗系统时碰到两个问题:
- 心形角色按方向键移动后,松开按键不会停止,持续移动;
- 角色碰撞战斗框边界时会来回弹跳,而不是停在框内。
问题根源
- 按键处理逻辑缺陷:原代码用KEYDOWN/KEYUP事件累加/抵消速度,这种方式依赖按键触发顺序,若同时按下多个方向键,会导致速度计算混乱。比如先按左(speed_x=-4)再按右(speed_x=0),松开左时会加4,speed_x变为4,角色持续向右移动。
- 边界碰撞逻辑错误:原代码碰撞边界时反转速度,导致角色在边界来回弹跳,不符合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
相关产品推荐
相关产品推荐

