Avoid triggering change detection for inputs (#6847)

# Objective
Fix #5292.

## Solution
Avoid derefencing when clearing to ensure that change detection is not triggered when there is nothing to clear.
This commit is contained in:
James Liu 2022-12-11 18:22:09 +00:00
parent b37a6ca9a2
commit 0d67c32153
4 changed files with 18 additions and 7 deletions

View file

@ -1,6 +1,9 @@
use crate::{Axis, Input};
use bevy_ecs::event::{EventReader, EventWriter};
use bevy_ecs::system::{Res, ResMut, Resource};
use bevy_ecs::{
change_detection::DetectChanges,
system::{Res, ResMut, Resource},
};
use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect};
use bevy_utils::{tracing::info, HashMap};
use thiserror::Error;
@ -1160,7 +1163,7 @@ pub fn gamepad_event_system(
mut events: EventWriter<GamepadEvent>,
settings: Res<GamepadSettings>,
) {
button_input.clear();
button_input.bypass_change_detection().clear();
for event in raw_events.iter() {
match &event.event_type {
GamepadEventType::Connected(_) => {

View file

@ -34,6 +34,13 @@ use bevy_ecs::schedule::State;
/// * Call the [`Input::press`] method for each press event.
/// * Call the [`Input::release`] method for each release event.
/// * Call the [`Input::clear`] method at each frame start, before processing events.
///
/// Note: Calling `clear` from a [`ResMut`] will trigger change detection.
/// It may be preferable to use [`DetectChanges::bypass_change_detection`]
/// to avoid causing the resource to always be marked as changed.
///
///[`ResMut`]: bevy_ecs::system::ResMut
///[`DetectChanges::bypass_change_detection`]: bevy_ecs::change_detection::DetectChanges::bypass_change_detection
#[derive(Debug, Clone, Resource, Reflect)]
#[reflect(Default)]
pub struct Input<T: Copy + Eq + Hash + Send + Sync + 'static> {

View file

@ -1,5 +1,5 @@
use crate::{ButtonState, Input};
use bevy_ecs::{event::EventReader, system::ResMut};
use bevy_ecs::{change_detection::DetectChanges, event::EventReader, system::ResMut};
use bevy_reflect::{FromReflect, Reflect};
#[cfg(feature = "serialize")]
@ -41,8 +41,9 @@ pub fn keyboard_input_system(
mut key_input: ResMut<Input<KeyCode>>,
mut keyboard_input_events: EventReader<KeyboardInput>,
) {
scan_input.clear();
key_input.clear();
// Avoid clearing if it's not empty to ensure change detection is not triggered.
scan_input.bypass_change_detection().clear();
key_input.bypass_change_detection().clear();
for event in keyboard_input_events.iter() {
let KeyboardInput {
scan_code, state, ..

View file

@ -1,5 +1,5 @@
use crate::{ButtonState, Input};
use bevy_ecs::{event::EventReader, system::ResMut};
use bevy_ecs::{change_detection::DetectChanges, event::EventReader, system::ResMut};
use bevy_math::Vec2;
use bevy_reflect::{FromReflect, Reflect};
@ -132,7 +132,7 @@ pub fn mouse_button_input_system(
mut mouse_button_input: ResMut<Input<MouseButton>>,
mut mouse_button_input_events: EventReader<MouseButtonInput>,
) {
mouse_button_input.clear();
mouse_button_input.bypass_change_detection().clear();
for event in mouse_button_input_events.iter() {
match event.state {
ButtonState::Pressed => mouse_button_input.press(event.button),