输入处理
input基础
本教程基于Bevy官方示例,提供了完整的输入系统开发指南。
教程结构
- 键盘输入: 基础按键、事件监听、修饰键、字符输入
- 鼠标输入: 按钮、移动、滚轮、事件监听、光标控制
- 触摸输入: 基础触摸、事件监听、多点触摸
- 游戏手柄输入: 基础手柄、事件监听、连接管理
- 文本输入: IME支持、多语言输入、特殊键处理
- 游戏手柄震动: 力反馈、自定义震动模式
- 输入映射和绑定: 动态绑定、配置管理
- 输入事件处理: 优先级、过滤、转换
- 输入状态管理: 状态机、上下文管理
- 自定义输入系统: 扩展输入类型、模拟回放
- 输入优化: 缓存、批处理、预测插值
核心概念速查
基础输入资源
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Res<ButtonInput<KeyCode>>
Res<ButtonInput<MouseButton>> Res<AccumulatedMouseMotion> Res<AccumulatedMouseScroll>
Res<Touches>
Query<(Entity, &Gamepad)>
|
输入事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| EventReader<KeyboardInput>
EventReader<MouseButtonInput> EventReader<MouseMotion> EventReader<CursorMoved> EventReader<MouseWheel>
EventReader<TouchInput>
EventReader<GamepadConnectionEvent> EventReader<GamepadAxisChangedEvent> EventReader<GamepadButtonChangedEvent>
|
输入状态检查
1 2 3 4 5 6 7 8
| keyboard_input.pressed(KeyCode::KeyA) keyboard_input.just_pressed(KeyCode::KeyA) keyboard_input.just_released(KeyCode::KeyA)
input.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight])
|
常用模式
1. 基础输入处理
1 2 3 4 5 6 7 8 9 10
| fn input_system(keyboard_input: Res<ButtonInput<KeyCode>>) { if keyboard_input.pressed(KeyCode::KeyW) { }
if keyboard_input.just_pressed(KeyCode::Space) { } }
|
2. 组合键处理
1 2 3 4 5 6 7 8 9
| fn combo_input_system(input: Res<ButtonInput<KeyCode>>) { let ctrl = input.any_pressed([KeyCode::ControlLeft, KeyCode::ControlRight]); let shift = input.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight]);
if ctrl && shift && input.just_pressed(KeyCode::KeyS) { } }
|
3. 游戏手柄输入
1 2 3 4 5 6 7 8 9 10 11 12 13
| fn gamepad_system(gamepads: Query<(Entity, &Gamepad)>) { for (entity, gamepad) in &gamepads { if gamepad.just_pressed(GamepadButton::South) { }
let left_stick_x = gamepad.get(GamepadAxis::LeftStickX).unwrap(); if left_stick_x.abs() > 0.01 { } } }
|
4. 触摸输入
1 2 3 4 5 6 7 8 9 10 11 12
| fn touch_system(touches: Res<Touches>) { for touch in touches.iter_just_pressed() { info!("触摸按下 - ID: {}, 位置: {}", touch.id(), touch.position()); }
for touch in touches.iter() { if touches.pressed(touch.id()) { } } }
|
5. 输入事件监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| fn event_system(mut events: EventReader<KeyboardInput>) { for event in events.read() { match event.logical_key { Key::Character(c) => { } Key::Enter => { } _ => {} } } }
|
高级功能
1. 游戏手柄震动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| fn rumble_system( gamepads: Query<(Entity, &Gamepad)>, mut rumble_requests: EventWriter<GamepadRumbleRequest>, ) { for (entity, gamepad) in &gamepads { if gamepad.just_pressed(GamepadButton::North) { rumble_requests.send(GamepadRumbleRequest::Add { gamepad: entity, intensity: GamepadRumbleIntensity::strong_motor(0.5), duration: Duration::from_secs(2), }); } } }
|
2. 输入映射系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #[derive(Resource)] struct InputMapping { keyboard_bindings: HashMap<InputAction, Vec<KeyCode>>, mouse_bindings: HashMap<InputAction, Vec<MouseButton>>, gamepad_bindings: HashMap<InputAction, Vec<GamepadButton>>, }
fn input_processing_system( keyboard_input: Res<ButtonInput<KeyCode>>, input_mapping: Res<InputMapping>, ) { for (action, keys) in &input_mapping.keyboard_bindings { let is_pressed = keys.iter().any(|key| keyboard_input.pressed(*key)); } }
|
3. 输入状态机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #[derive(States)] enum InputState { Normal, Menu, Combat, }
fn input_state_system( mut input_context: ResMut<InputContext>, keyboard_input: Res<ButtonInput<KeyCode>>, ) { match input_context.current_state { InputState::Normal => { if keyboard_input.just_pressed(KeyCode::Escape) { input_context.current_state = InputState::Menu; } } InputState::Menu => { if keyboard_input.just_pressed(KeyCode::Escape) { input_context.current_state = InputState::Normal; } } _ => {} } }
|
性能优化技巧
1. 输入缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #[derive(Resource)] struct InputCache { keyboard_cache: HashMap<KeyCode, bool>, last_update: f32, cache_duration: f32, }
fn optimized_input_system( mut input_cache: ResMut<InputCache>, keyboard_input: Res<ButtonInput<KeyCode>>, time: Res<Time>, ) { let current_time = time.elapsed_secs();
if input_cache.needs_update(current_time) { input_cache.update_cache(&keyboard_input, current_time); }
if input_cache.is_key_pressed(KeyCode::KeyW) { } }
|
2. 输入批处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| fn batched_input_system( mut input_events: EventReader<InputEvent>, mut batched_actions: EventWriter<BatchedAction>, ) { let mut actions = Vec::new();
for event in input_events.read() { actions.push(event.action.clone()); }
if !actions.is_empty() { batched_actions.send(BatchedAction { actions }); } }
|
3. 事件优先级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| fn priority_input_system( mut high_priority: EventReader<HighPriorityEvent>, mut normal_priority: EventReader<NormalPriorityEvent>, ) { for event in high_priority.read() { }
for event in normal_priority.read() { } }
|
常见问题解决
1. 输入延迟
1 2 3 4 5 6 7
| let cached_state = input_cache.get_key_state(key);
let batched_events = collect_events(); process_batch(batched_events);
|
2. 输入冲突
1 2 3 4 5 6 7 8 9 10
| match current_input_state { InputState::Gameplay => { } InputState::UI => { } }
|
3. 多设备支持
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| fn unified_input_system( keyboard_input: Res<ButtonInput<KeyCode>>, gamepads: Query<&Gamepad>, input_mapping: Res<InputMapping>, ) { if keyboard_input.pressed(input_mapping.get_key(InputAction::MoveForward)) { }
for gamepad in &gamepads { if gamepad.pressed(input_mapping.get_gamepad_button(InputAction::MoveForward)) { } } }
|
4. 输入验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| fn input_filter_system( keyboard_input: Res<ButtonInput<KeyCode>>, input_filter: Res<InputFilter>, mut filtered_events: EventWriter<FilteredInputEvent>, ) { for key_code in KeyCode::iter() { if keyboard_input.just_pressed(key_code) { if !input_filter.is_disabled(key_code) { filtered_events.send(FilteredInputEvent { key: key_code }); } } } }
|
最佳实践
1. 输入系统设计
- 使用状态机管理不同的输入上下文
- 实现输入映射系统支持自定义绑定
- 使用事件系统处理输入,避免直接修改游戏状态
- 实现输入缓冲和预测提高响应性
2. 性能优化
- 缓存输入状态减少重复检查
- 使用批处理减少事件处理开销
- 实现输入预测和插值
- 优化输入事件的分发和处理
3. 用户体验
- 支持多种输入设备
- 提供输入配置选项
- 实现输入反馈(震动、音效等)
- 处理输入冲突和优先级
4. 错误处理
- 验证输入数据的有效性
- 处理设备连接和断开
- 提供合理的默认输入配置
- 记录输入错误便于调试
扩展资源
官方文档
社区资源
学习路径建议
- 初学者: 从基础教程开始,掌握各种输入设备的基本使用
- 进阶用户: 学习高级教程,了解输入映射、状态管理等
- 高级用户: 探索自定义输入系统、性能优化、输入预测等
结语
Bevy的输入系统提供了强大而灵活的输入处理能力,从基础的键盘鼠标输入到高级的游戏手柄震动和自定义输入类型。通过本教程的学习,您应该能够:
- 处理各种输入设备的输入
- 实现复杂的输入映射和绑定
- 管理输入状态和上下文
- 优化输入系统的性能
- 创建自定义输入类型
- 实现输入预测和插值
建议在实际项目中逐步应用这些知识,并根据具体需求选择合适的特性组合。Bevy的ECS架构和模块化设计使得输入系统易于扩展和维护,是开发高质量交互体验的优秀选择。