Flame游戏玩家无按键时停止移动失效问题求助
问题分析与解决方案
你的代码存在两个核心问题,导致移动逻辑异常:
1. 键盘事件处理返回值错误
Flame 的 KeyboardHandler 要求 onKeyEvent 返回 true 来标记事件已被处理,否则 Flame 会忽略你的状态修改逻辑。原代码返回父类默认的 false,这是移除末尾else语句后按键才响应的根本原因。
2. 方向状态初始化逻辑不严谨
原逻辑未先默认重置方向,多键冲突或按键抬起时可能出现状态残留。
修改后的完整代码
import 'dart:async'; import 'package:farm_game/farm_lands.dart'; import 'package:flame/components.dart'; import 'package:flame/sprite.dart'; import 'package:flutter/src/services/raw_keyboard.dart'; enum PlayerState { idle, backIdle, leftIdle, rightIdle, walkFront, walkBack, walkLeft, walkRight } enum PlayerDirection { front, back, left, right, none } class Player extends SpriteAnimationGroupComponent with HasGameRef<FarmLands>, KeyboardHandler { late final SpriteSheet spriteSheet; final double stepTime = 0.3; PlayerDirection playerDirection = PlayerDirection.none; double moveSpeed = 50; Vector2 velocity = Vector2.zero(); Player({position}): super(position: position); @override FutureOr<void> onLoad() { spriteSheet = SpriteSheet.fromColumnsAndRows( image: game.images.fromCache('characters/Character_Spritesheet.png'), columns: 4, rows: 4, ); _loadAllAnimations(); return super.onLoad(); } @override void update(double dt) { _updatePlayerMovement(dt); super.update(dt); } @override bool onKeyEvent(RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) { final isLeftKeyPressed = keysPressed.contains(LogicalKeyboardKey.keyA) || keysPressed.contains(LogicalKeyboardKey.arrowLeft); final isRightKeyPressed = keysPressed.contains(LogicalKeyboardKey.keyD) || keysPressed.contains(LogicalKeyboardKey.arrowRight); final isUpKeyPressed = keysPressed.contains(LogicalKeyboardKey.keyW) || keysPressed.contains(LogicalKeyboardKey.arrowUp); final isDownKeyPressed = keysPressed.contains(LogicalKeyboardKey.keyS) || keysPressed.contains(LogicalKeyboardKey.arrowDown); // 先默认重置为无方向,避免状态残留 playerDirection = PlayerDirection.none; // 处理相反方向同时按下的情况 if (isLeftKeyPressed && isRightKeyPressed) { playerDirection = PlayerDirection.none; } else if (isUpKeyPressed && isDownKeyPressed) { playerDirection = PlayerDirection.none; } // 处理单个方向按键 else if (isLeftKeyPressed) { playerDirection = PlayerDirection.left; } else if (isRightKeyPressed) { playerDirection = PlayerDirection.right; } else if (isUpKeyPressed) { playerDirection = PlayerDirection.back; } else if (isDownKeyPressed) { playerDirection = PlayerDirection.front; } // 必须返回true,告知Flame事件已被处理 return true; } void _updatePlayerMovement(double dt){ double dirX = 0.0; double dirY = 0.0; switch(playerDirection){ case PlayerDirection.front: current = PlayerState.walkFront; dirY += moveSpeed; break; case PlayerDirection.back: current = PlayerState.walkBack; dirY -= moveSpeed; break; case PlayerDirection.left: current = PlayerState.walkLeft; dirX -= moveSpeed; break; case PlayerDirection.right: current = PlayerState.walkRight; dirX += moveSpeed; break; case PlayerDirection.none: current = PlayerState.idle; break; default: } velocity = Vector2(dirX, dirY); position += velocity * dt; } void _loadAllAnimations() { animations = { PlayerState.idle: spriteSheet.createAnimation( row: 0, stepTime: stepTime, from: 0, to: 2, ), PlayerState.backIdle: spriteSheet.createAnimation( row: 1, stepTime: stepTime, from: 0, to: 2 ), PlayerState.leftIdle: spriteSheet.createAnimation( row: 2, stepTime: stepTime, from: 0, to: 2 ), PlayerState.rightIdle: spriteSheet.createAnimation( row: 3, stepTime: stepTime, from: 0, to: 2 ), PlayerState.walkFront: spriteSheet.createAnimation( row: 0, stepTime: stepTime, from: 2, to: 4 ), PlayerState.walkBack: spriteSheet.createAnimation( row: 1, stepTime: stepTime, from: 2, to: 4 ), PlayerState.walkLeft: spriteSheet.createAnimation( row: 2, stepTime: stepTime, from: 2, to: 4 ), PlayerState.walkRight: spriteSheet.createAnimation( row: 3, stepTime: stepTime, from: 2, to: 4 ), }; } }
额外优化:支持斜向移动
如果需要同时按下两个垂直方向键实现斜向移动,可以放弃PlayerDirection枚举,直接通过向量计算速度:
// 移除PlayerDirection枚举,修改onKeyEvent和_updatePlayerMovement @override bool onKeyEvent(RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) { final isLeft = keysPressed.contains(LogicalKeyboardKey.keyA) || keysPressed.contains(LogicalKeyboardKey.arrowLeft); final isRight = keysPressed.contains(LogicalKeyboardKey.keyD) || keysPressed.contains(LogicalKeyboardKey.arrowRight); final isUp = keysPressed.contains(LogicalKeyboardKey.keyW) || keysPressed.contains(LogicalKeyboardKey.arrowUp); final isDown = keysPressed.contains(LogicalKeyboardKey.keyS) || keysPressed.contains(LogicalKeyboardKey.arrowDown); velocity.x = 0; velocity.y = 0; if (isLeft && !isRight) velocity.x -= moveSpeed; if (isRight && !isLeft) velocity.x += moveSpeed; if (isUp && !isDown) velocity.y -= moveSpeed; if (isDown && !isUp) velocity.y += moveSpeed; // 斜向移动时保持速度大小一致(可选) if (velocity.x != 0 && velocity.y != 0) { velocity.normalize().scale(moveSpeed); } // 更新动画状态 if (velocity.x > 0) { current = PlayerState.walkRight; } else if (velocity.x < 0) { current = PlayerState.walkLeft; } else if (velocity.y > 0) { current = PlayerState.walkFront; } else if (velocity.y < 0) { current = PlayerState.walkBack; } else { current = PlayerState.idle; } return true; } void _updatePlayerMovement(double dt){ position += velocity * dt; }
内容的提问来源于stack exchange,提问作者Brenz Gwynne Hababag
相关产品推荐
相关产品推荐

