Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upInput rebind patch #247
Conversation
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 17, 2017
Member
The only file modified in any meaningful way in this PR so far is src/ecs/resources/input.rs everything else is just whitespace changes.
Whitespace changes have been removed.
|
Whitespace changes have been removed. |
| @@ -62,45 +80,63 @@ impl<'a> Iterator for PressedMouseButtons<'a> { | ||
| /// ``` | ||
| #[derive(Default)] | ||
| pub struct InputHandler { | ||
| - pressed_keys: HashMap<VirtualKeyCode, KeyQueryState>, | ||
| - pressed_mouse_buttons: HashMap<MouseButton, KeyQueryState>, | ||
| + pressed_keys: Vec<VirtualKeyCode>, |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
torkleyy
Jun 17, 2017
Member
It would be great if we could instead just have a boolean Vec where the index is the key. Also see this issue.
torkleyy
Jun 17, 2017
Member
It would be great if we could instead just have a boolean Vec where the index is the key. Also see this issue.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 17, 2017
Member
I had similar thoughts, I initially wanted to store a fixed size array of bools as part of the struct, where each VirtualKeyCode (or MouseButton) as usize is the index into the array. This reduces the amount of times we have to follow pointers and do allocations, but determining what that fixed size should be is a bit hard as there isn't an easy way to get a count of all the variants of a VirtualKeyCode. I could just hard code a value but this makes for some brittle code if new codes are ever added. Additionally every frame the current input state needs to be copied to the previous input state as well, so if the input state structures are larger this gets more expensive. There are also limitations on how large this Vec<VirtualKeyCode> can get, most of the time it will have < 5 elements, so iterating it to determine key state isn't that expensive, especially when compared to the cost of copying an entire Vec<bool> of all keys every frame.
Xaeroxe
Jun 17, 2017
•
Member
I had similar thoughts, I initially wanted to store a fixed size array of bools as part of the struct, where each VirtualKeyCode (or MouseButton) as usize is the index into the array. This reduces the amount of times we have to follow pointers and do allocations, but determining what that fixed size should be is a bit hard as there isn't an easy way to get a count of all the variants of a VirtualKeyCode. I could just hard code a value but this makes for some brittle code if new codes are ever added. Additionally every frame the current input state needs to be copied to the previous input state as well, so if the input state structures are larger this gets more expensive. There are also limitations on how large this Vec<VirtualKeyCode> can get, most of the time it will have < 5 elements, so iterating it to determine key state isn't that expensive, especially when compared to the cost of copying an entire Vec<bool> of all keys every frame.
| + } | ||
| +} | ||
| + | ||
| +fn mouse_button_to_button(mb: &MouseButton) -> Button { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + } | ||
| + | ||
| + /// Returns the value of an axis by the i32 id, if the id doesn't exist this returns None. | ||
| + pub fn axis_value(&self, id: i32) -> Option<f32> { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
torkleyy
Jun 17, 2017
Member
I see, so this is how you would refer to an axis defined in the config file?
torkleyy
Jun 17, 2017
Member
I see, so this is how you would refer to an axis defined in the config file?
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 17, 2017
Member
This PR is as finished as it can be until #244 is merged.
Changelog entry:
- Add function
text_enteredwhich returns a &str of characters sent to the game window during the current frame, useful for in game text entry fields. - Add _released functions to detect when an input is released
- All _down functions have been renamed to _pressed
- All _once functions have been renamed to _down, and they all will report the correct values even if they've already been called once on this frame.
- Button type has been added, which is an enum containing the
VirtualKeyCodeandMouseButtontypes - Functions to compliment Button have been added,
- pub fn pressed_buttons(&self) -> PressedButtons
- pub fn button_pressed(&self, button: Button) -> bool
- pub fn buttons_pressed(&self, buttons: &[Button]) -> bool
- pub fn button_down(&self, button: Button) -> bool
- pub fn button_released(&self, button: Button) -> bool
- pub fn buttons_down(&self, buttons: &[Button]) -> bool
- Actions have been added, which are mappings between Buttons and i32 values, allowing for rebinding of inputs.
- Similar functions for actions were added, with the exception that there is no pressed_actions. The function was difficult to write and I couldn't think of a use case for it.
- Axis struct added, which is a mapping of two
Buttons, one positive and one negative. - Axes can be mapped to i32s on the InputHandler and then queried for with the
axis_valuefunction.
|
This PR is as finished as it can be until #244 is merged. Changelog entry:
|
Xaeroxe
changed the title from
[WIP] Input rebind patch
to
Input rebind patch
Jun 17, 2017
| + //TODO: Add controller buttons here when the engine has support. | ||
| +} | ||
| + | ||
| +impl Into<Button> for VirtualKeyCode { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| - } | ||
| - None => [0.0, 0.0], | ||
| - }, | ||
| + geometry |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
kvark
Jun 17, 2017
Member
I don't think mixing your input PR with rustfmt pass is a good idea. Better have them separate. FWIW, I like the old formatting better.
kvark
Jun 17, 2017
Member
I don't think mixing your input PR with rustfmt pass is a good idea. Better have them separate. FWIW, I like the old formatting better.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 17, 2017
Member
I asked @ebkalderon about mixing this with rustfmt and he didn't seem to mind, however in this specific instance I just realized it's very likely to have a merge conflict with #244 and I'd rather not have that. So I'll remove the other files from this PR.
Xaeroxe
Jun 17, 2017
Member
I asked @ebkalderon about mixing this with rustfmt and he didn't seem to mind, however in this specific instance I just realized it's very likely to have a merge conflict with #244 and I'd rather not have that. So I'll remove the other files from this PR.
| @@ -28,7 +41,7 @@ impl<'a> Iterator for PressedKeys<'a> { | ||
| /// An iterator over the currently pressed down mouse buttons. | ||
| pub struct PressedMouseButtons<'a> { | ||
| - iterator: Keys<'a, MouseButton, KeyQueryState>, | ||
| + iterator: Iter<'a, MouseButton>, |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
kvark
Jun 17, 2017
Member
is there any benefit over doing just type PressedMouseButtons<'a> = Iter<'a, MouseButton>?
kvark
Jun 17, 2017
Member
is there any benefit over doing just type PressedMouseButtons<'a> = Iter<'a, MouseButton>?
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 17, 2017
Member
This conceals the implementation details a bit better, but other than that no not really. When I opened the file it was a wrapper struct so I left it that way. I'm happy to change it either way.
Xaeroxe
Jun 17, 2017
Member
This conceals the implementation details a bit better, but other than that no not really. When I opened the file it was a wrapper struct so I left it that way. I'm happy to change it either way.
| // defined to match glium | ||
| mouse_position: Option<(i32, i32)>, | ||
| previous_mouse_position: Option<(i32, i32)>, | ||
| + axes: HashMap<i32, Axis>, |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
kvark
Jun 17, 2017
Member
I assume these i32 are specific indices of the elements, in which case it would be a good idea to make them opaque (i.e. struct AxeId(i32)) so that the user is not able to change them
kvark
Jun 17, 2017
Member
I assume these i32 are specific indices of the elements, in which case it would be a good idea to make them opaque (i.e. struct AxeId(i32)) so that the user is not able to change them
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
On second thought it'd probably be better for this to be transparent right now, as the facilities for making input rebinding part of the asset system don't exist yet. I'll probably see if I can do this again when #244 is merged.
Xaeroxe
Jun 18, 2017
Member
On second thought it'd probably be better for this to be transparent right now, as the facilities for making input rebinding part of the asset system don't exist yet. I'll probably see if I can do this again when #244 is merged.
| + // Before processing these events store the input states of the previous frame. | ||
| + self.previous_mouse_position = self.mouse_position; | ||
| + self.previous_pressed_keys = self.pressed_keys.clone(); | ||
| + self.previous_pressed_mouse_buttons = self.pressed_mouse_buttons.clone(); |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
kvark
Jun 17, 2017
Member
nit: should re-use the existing allocation instead of cloning, i.e.
vector.clear();
vector.extend_from_slice(&other_vector);
kvark
Jun 17, 2017
Member
nit: should re-use the existing allocation instead of cloning, i.e.
vector.clear();
vector.extend_from_slice(&other_vector);
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| - // I.e `key_once(key)` is queried after second `Pressed` event. | ||
| - if let Entry::Vacant(entry) = self.pressed_keys.entry(key_code) { | ||
| - entry.insert(KeyQueryState::NotQueried); | ||
| + if self.pressed_keys.iter().all(|&k| k != key_code) { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 17, 2017
Member
It might be, although I think the performance of Vec might actually be better as iterating over <5 elements in contiguous memory is probably faster than any hashing function
Xaeroxe
Jun 17, 2017
Member
It might be, although I think the performance of Vec might actually be better as iterating over <5 elements in contiguous memory is probably faster than any hashing function
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
kvark
Jun 18, 2017
Member
Right, but I don't think it's even worth optimizing if there are just 5 keys. HashSet is just more convenient.
kvark
Jun 18, 2017
Member
Right, but I don't think it's even worth optimizing if there are just 5 keys. HashSet is just more convenient.
| + pub fn actions_pressed(&self, actions: &[i32]) -> Result<bool, Vec<i32>> { | ||
| + let mut all_buttons_pressed = true; | ||
| + //Prefer to skip initializing a new vec if we can. | ||
| + let mut bad_values: Option<Vec<i32>> = None; |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + } | ||
| + } | ||
| + if let Some(values) = bad_values { | ||
| + return Err(values); |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + let mut all_buttons_pressed = true; | ||
| + let mut any_button_pressed_this_frame = false; | ||
| + //Prefer to skip initializing a new vec if we can. | ||
| + let mut bad_values: Option<Vec<i32>> = None; |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
kvark
Jun 18, 2017
Member
I don't think HashSet is essential here (we can change it later, it's an impl detail anyway), so I'd be ready to merge this. Unless there is something else you want to do in the PR, or other reviewers want to chime in.
|
I don't think |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
As of this moment I consider this merge ready. If any other reviewers want to chime in I'll be happy to hear what they have to say.
|
As of this moment I consider this merge ready. If any other reviewers want to chime in I'll be happy to hear what they have to say. |
Aceeri
approved these changes
Jun 18, 2017
•
Looks good to me. Would this also give the benefit of keys pressed in a specific order? As in you could have something based on whether A->B was pressed or if B->A was pressed or would that depend more on glutin's input handling?
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
@Aceeri This API doesn't store key press ordering in any way, in order to accomplish that you'd need some kind of state machine, which could be powered by the functions given here but no this won't handle the order in which keys are pressed. I'd recommend storing that information in the state of your components, as it's probably much better suited to that in my opinion. That way you can also have your visuals and audio respond to keys being pressed in a specific order. For example:
Press A -> UI icon flashes and changes what image is displayed, accompanied by some kind of "acknowledged" sound effect
Press B -> Action executes, UI icon switches back
Press B -> UI icon flashes and changes to a different image than it would if A were pressed, also accompanied by some kind of "acknowledged" sound effect
Press A -> Action executes, UI icon switches back
|
@Aceeri This API doesn't store key press ordering in any way, in order to accomplish that you'd need some kind of state machine, which could be powered by the functions given here but no this won't handle the order in which keys are pressed. I'd recommend storing that information in the state of your components, as it's probably much better suited to that in my opinion. That way you can also have your visuals and audio respond to keys being pressed in a specific order. For example: Press A -> UI icon flashes and changes what image is displayed, accompanied by some kind of "acknowledged" sound effect Press B -> UI icon flashes and changes to a different image than it would if A were pressed, also accompanied by some kind of "acknowledged" sound effect |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
@Xaeroxe How should we handle text input (e.g. for an in-game chat)? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
@torkleyy That's a great question. This API is awful for that currently. I'd like to change that. Please don't merge until I have that in.
|
@torkleyy That's a great question. This API is awful for that currently. I'd like to change that. Please don't merge until I have that in. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
@torkleyy function text_entered has been added, which returns a &str of all characters sent to the window during the current frame, you can insert the output of that function wherever your cursor is in your text entry field.
I consider this ready to merge again.
|
@torkleyy function I consider this ready to merge again. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
Also as an aside: This won't handle for backspace and delete (backspace and delete "characters" will likely be directly in the output of text_entered). Full text entry support is more of a UI problem and in my opinion slightly out of scope for this, but at least now we have the facilities to add full text entry support at a later date.
|
Also as an aside: This won't handle for backspace and delete (backspace and delete "characters" will likely be directly in the output of |
| } | ||
| impl InputHandler { | ||
| /// Creates a new input handler. | ||
| pub fn new() -> InputHandler { | ||
| InputHandler { | ||
| - pressed_keys: HashMap::default(), | ||
| - pressed_mouse_buttons: HashMap::default(), | ||
| + pressed_keys: Vec::new(), |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
msiglreith
Jun 18, 2017
Contributor
Abstracting pressed_* and previous_* into a separate struct could reduce code duplication.
msiglreith
Jun 18, 2017
Contributor
Abstracting pressed_* and previous_* into a separate struct could reduce code duplication.
| } | ||
| /// Checks if all the given keys are being pressed. | ||
| - pub fn keys_down(&self, keys: &[VirtualKeyCode]) -> bool { | ||
| + pub fn keys_pressed(&self, keys: &[VirtualKeyCode]) -> bool { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
msiglreith
Jun 18, 2017
Contributor
keys_pressed and key_pressed seem to have a different behavior as the first one uses key_down internally.
msiglreith
Jun 18, 2017
Contributor
keys_pressed and key_pressed seem to have a different behavior as the first one uses key_down internally.
| - keys.iter().any(|key| self.key_once(*key)) && self.keys_down(keys) | ||
| + /// Checks if the all the given keys are down and at least one was pressed on this frame. | ||
| + pub fn keys_down(&self, keys: &[VirtualKeyCode]) -> bool { | ||
| + keys.iter().any(|key| self.key_down(*key)) && self.keys_down(keys) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| } | ||
| /// Checks if all the given mouse buttons are being pressed. | ||
| - pub fn mouse_buttons_down(&self, buttons: &[MouseButton]) -> bool { | ||
| + pub fn mouse_buttons_pressed(&self, buttons: &[MouseButton]) -> bool { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| - buttons.iter().any(|btn| self.mouse_button_once(*btn)) && self.mouse_buttons_down(buttons) | ||
| + /// Checks if the all the given mouse buttons are down and at least one was pressed this frame. | ||
| + pub fn mouse_buttons_down(&self, buttons: &[MouseButton]) -> bool { | ||
| + buttons.iter().any(|&btn| self.mouse_button_down(btn)) && self.mouse_buttons_down(buttons) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + bad_values.push(*action); | ||
| + } | ||
| + } | ||
| + if bad_values.len() > 0 { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + bad_values.push(*action); | ||
| + } | ||
| + } | ||
| + if bad_values.len() > 0 { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + if let Some(a) = self.axes.get(&id) { | ||
| + let pos = self.button_down(a.pos); | ||
| + let neg = self.button_down(a.neg); | ||
| + if pos == neg { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
Some(if pos == neg {
0.0
} else if pos {
1.0
} else {
-1.0
})This is the rustfmt version of that. In my opinion it really hurts readability.
Xaeroxe
Jun 18, 2017
Member
Some(if pos == neg {
0.0
} else if pos {
1.0
} else {
-1.0
})This is the rustfmt version of that. In my opinion it really hurts readability.
| + pub fn action_down(&self, action: i32) -> Option<bool> { | ||
| + self.actions | ||
| + .get(&action) | ||
| + .and_then(|&b| Some(self.button_down(b))) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + // can't think of a use case for it. | ||
| + | ||
| + /// Checks if the given button is currently pressed. | ||
| + pub fn action_pressed(&self, action: i32) -> Option<bool> { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
Oh man @msiglreith found lots of problematic typos. Thanks a ton @msiglreith I'll get to work on your comments.
|
Oh man @msiglreith found lots of problematic typos. Thanks a ton @msiglreith I'll get to work on your comments. |
Xaeroxe
added some commits
Jun 18, 2017
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
Code has been rearranged to have specific InputFrameData structures, this is nice because it more clearly separates where the functionality lives and makes my code less error prone.
Ready for review.
|
Code has been rearranged to have specific InputFrameData structures, this is nice because it more clearly separates where the functionality lives and makes my code less error prone. Ready for review. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
@msiglreith since all your comments are outdated I'm giving you a
|
@msiglreith since all your comments are outdated I'm giving you a |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
Just added _released functions to detect when an input is released. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 18, 2017
Member
I skipped having functions like keys_released because the behavior of that would be pretty wonky and hard to predict. It'd only be reasonable to check if any of the given keys were released this frame, which is not how it's opposite keys_down behaves. You can make keys_down work because it relies on action rather than inaction, but keys_released would rely on inaction making it a bit confusing.
|
I skipped having functions like |
ebkalderon
requested changes
Jun 19, 2017
Terrific work all around, @Xaeroxe! Just a few nits to handle before merging.
| + } | ||
| + } | ||
| + | ||
| + fn advance_frame(&mut self, previous_frame: &mut FrameInputData) { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + } | ||
| + | ||
| + // Pressed actions has been omitted as the function is a little difficult to write and I | ||
| + // can't think of a use case for it. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ebkalderon
Jun 19, 2017
Member
Given that action_pressed() is present below, this comment seems somewhat misleading.
ebkalderon
Jun 19, 2017
Member
Given that action_pressed() is present below, this comment seems somewhat misleading.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 19, 2017
Member
Maybe this is a good reason to rename these functions. This comment is actually referring to pressed_actions, with pressed_ in front and an s on actions. It's a different operation from action_pressed. See key_pressed vs pressed_keys for a comparison.
Xaeroxe
Jun 19, 2017
Member
Maybe this is a good reason to rename these functions. This comment is actually referring to pressed_actions, with pressed_ in front and an s on actions. It's a different operation from action_pressed. See key_pressed vs pressed_keys for a comparison.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ebkalderon
Jun 19, 2017
Member
Oh, I see what you mean now. Sorry, the terminology is a bit confusing.
ebkalderon
Jun 19, 2017
Member
Oh, I see what you mean now. Sorry, the terminology is a bit confusing.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 19, 2017
Member
I just renamed the functions to
pressed_keys()
key_is_pressed()
keys_are_pressed()
I think that helps disambiguate it a bit better.
Xaeroxe
Jun 19, 2017
Member
I just renamed the functions to
pressed_keys()
key_is_pressed()
keys_are_pressed()
I think that helps disambiguate it a bit better.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + let mouse_button_convert = mouse_button_to_button as fn(&MouseButton) -> Button; | ||
| + let key_convert = key_to_button as fn(&VirtualKeyCode) -> Button; | ||
| + let mouse_buttons = self.pressed_mouse_buttons().map(mouse_button_convert); | ||
| + let keys = self.pressed_keys().map(key_convert); |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ebkalderon
Jun 19, 2017
Member
Perhaps you could use closures here instead of free-standing functions?
ebkalderon
Jun 19, 2017
Member
Perhaps you could use closures here instead of free-standing functions?
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 19, 2017
Member
I tried, it seems rustc doesn't support casting closures to fn types yet. I spent a few hours trying to get this to work and this was the best I could do. Storing functions in types without using trait objects or generics turns out to be a bit of a sore spot for Rust currently.
Xaeroxe
Jun 19, 2017
Member
I tried, it seems rustc doesn't support casting closures to fn types yet. I spent a few hours trying to get this to work and this was the best I could do. Storing functions in types without using trait objects or generics turns out to be a bit of a sore spot for Rust currently.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ebkalderon
Jun 19, 2017
Member
I meant passing closures into the map() methods directly, rather than storing them as types.
ebkalderon
Jun 19, 2017
Member
I meant passing closures into the map() methods directly, rather than storing them as types.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 19, 2017
Member
I sincerely would love to do this, but this is the compiler error I get:
jacob@jacob-laptop ~/amethyst $ cargo check
Compiling amethyst v0.4.3 (file:///home/jacob/amethyst)
error: non-capturing closure to fn coercion is experimental (see issue #39817)
--> src/ecs/resources/input.rs:139:36
|
139 | let mouse_button_convert = (|&mb| Button::Mouse(mb)) as fn(&MouseButton) -> Button;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: non-scalar cast: `[closure@src/ecs/resources/input.rs:139:36: 139:61]` as `fn(&glutin::MouseButton) -> ecs::resources::input::Button`
--> src/ecs/resources/input.rs:139:36
|
139 | let mouse_button_convert = (|&mb| Button::Mouse(mb)) as fn(&MouseButton) -> Button;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: non-capturing closure to fn coercion is experimental (see issue #39817)
--> src/ecs/resources/input.rs:140:27
|
140 | let key_convert = (|&k| Button::Key(k)) as fn(&VirtualKeyCode) -> Button;
| ^^^^^^^^^^^^^^^^^^^^^
error: non-scalar cast: `[closure@src/ecs/resources/input.rs:140:27: 140:48]` as `fn(&glutin::VirtualKeyCode) -> ecs::resources::input::Button`
--> src/ecs/resources/input.rs:140:27
|
140 | let key_convert = (|&k| Button::Key(k)) as fn(&VirtualKeyCode) -> Button;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
error: Could not compile `amethyst`.
To learn more, run the command again with --verbose.
These fns have to be stored in the PressedButtons iterator that is passed back so it is necessary to define a type for them. I could just Box the iterator but then we're moving this structure onto the heap unnecessarily.
Basically this whole system ends up being a type system jigsaw puzzle and this was the only way I could see to solve it and maintain performance.
Xaeroxe
Jun 19, 2017
Member
I sincerely would love to do this, but this is the compiler error I get:
jacob@jacob-laptop ~/amethyst $ cargo check
Compiling amethyst v0.4.3 (file:///home/jacob/amethyst)
error: non-capturing closure to fn coercion is experimental (see issue #39817)
--> src/ecs/resources/input.rs:139:36
|
139 | let mouse_button_convert = (|&mb| Button::Mouse(mb)) as fn(&MouseButton) -> Button;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: non-scalar cast: `[closure@src/ecs/resources/input.rs:139:36: 139:61]` as `fn(&glutin::MouseButton) -> ecs::resources::input::Button`
--> src/ecs/resources/input.rs:139:36
|
139 | let mouse_button_convert = (|&mb| Button::Mouse(mb)) as fn(&MouseButton) -> Button;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: non-capturing closure to fn coercion is experimental (see issue #39817)
--> src/ecs/resources/input.rs:140:27
|
140 | let key_convert = (|&k| Button::Key(k)) as fn(&VirtualKeyCode) -> Button;
| ^^^^^^^^^^^^^^^^^^^^^
error: non-scalar cast: `[closure@src/ecs/resources/input.rs:140:27: 140:48]` as `fn(&glutin::VirtualKeyCode) -> ecs::resources::input::Button`
--> src/ecs/resources/input.rs:140:27
|
140 | let key_convert = (|&k| Button::Key(k)) as fn(&VirtualKeyCode) -> Button;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
error: Could not compile `amethyst`.
To learn more, run the command again with --verbose.
These fns have to be stored in the PressedButtons iterator that is passed back so it is necessary to define a type for them. I could just Box the iterator but then we're moving this structure onto the heap unnecessarily.
Basically this whole system ends up being a type system jigsaw puzzle and this was the only way I could see to solve it and maintain performance.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ebkalderon
Jun 19, 2017
Member
I'm sorry, perhaps I'm not being very clear. I meant you could do something like:
let mouse_buttons = self.pressed_mouse_buttons().map(|mb| Button::Mouse(mb));
let keys = self.pressed_keys().map(|k| Button::Key(k));
ebkalderon
Jun 19, 2017
•
Member
I'm sorry, perhaps I'm not being very clear. I meant you could do something like:
let mouse_buttons = self.pressed_mouse_buttons().map(|mb| Button::Mouse(mb));
let keys = self.pressed_keys().map(|k| Button::Key(k));
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 19, 2017
Member
Tried that too, with that you get
jacob@jacob-laptop ~/amethyst $ cargo check
Compiling amethyst v0.4.3 (file:///home/jacob/amethyst)
error[E0308]: mismatched types
--> src/ecs/resources/input.rs:141:36
|
141 | PressedButtons { iterator: mouse_buttons.chain(keys) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found closure
|
= note: expected type `std::iter::Chain<std::iter::Map<ecs::resources::input::PressedMouseButtons<'_>, fn(&glutin::MouseButton) -> ecs::resources::input::Button>, std::iter::Map<ecs::res
ources::input::PressedKeys<'_>, fn(&glutin::VirtualKeyCode) -> ecs::resources::input::Button>>`
found type `std::iter::Chain<std::iter::Map<ecs::resources::input::PressedMouseButtons<'_>, [closure@src/ecs/resources/input.rs:139:62: 139:85]>, std::iter::Map<ecs::resources
::input::PressedKeys<'_>, [closure@src/ecs/resources/input.rs:140:44: 140:63]>>`
error: aborting due to previous error
error: Could not compile `amethyst`.
To learn more, run the command again with --verbose.
Xaeroxe
Jun 19, 2017
Member
Tried that too, with that you get
jacob@jacob-laptop ~/amethyst $ cargo check
Compiling amethyst v0.4.3 (file:///home/jacob/amethyst)
error[E0308]: mismatched types
--> src/ecs/resources/input.rs:141:36
|
141 | PressedButtons { iterator: mouse_buttons.chain(keys) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found closure
|
= note: expected type `std::iter::Chain<std::iter::Map<ecs::resources::input::PressedMouseButtons<'_>, fn(&glutin::MouseButton) -> ecs::resources::input::Button>, std::iter::Map<ecs::res
ources::input::PressedKeys<'_>, fn(&glutin::VirtualKeyCode) -> ecs::resources::input::Button>>`
found type `std::iter::Chain<std::iter::Map<ecs::resources::input::PressedMouseButtons<'_>, [closure@src/ecs/resources/input.rs:139:62: 139:85]>, std::iter::Map<ecs::resources
::input::PressedKeys<'_>, [closure@src/ecs/resources/input.rs:140:44: 140:63]>>`
error: aborting due to previous error
error: Could not compile `amethyst`.
To learn more, run the command again with --verbose.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 19, 2017
Member
I spent hours trying to jam a closure in there and I couldn't see a way to do it. I'm sorry if I come off flippant, it's just the majority of the time spent on this PR was trying to get this piece of code to compile.
Xaeroxe
Jun 19, 2017
Member
I spent hours trying to jam a closure in there and I couldn't see a way to do it. I'm sorry if I come off flippant, it's just the majority of the time spent on this PR was trying to get this piece of code to compile.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 19, 2017
Member
Relevant rustc issue: rust-lang/rust#39817
It seems that we'll be able to correct this code in a very short time, as this has been stabilized in the master branch of rustc.
Xaeroxe
Jun 19, 2017
Member
Relevant rustc issue: rust-lang/rust#39817
It seems that we'll be able to correct this code in a very short time, as this has been stabilized in the master branch of rustc.
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ebkalderon
Jun 19, 2017
Member
@Xaeroxe No problem at all; I was just curious.
ebkalderon
Jun 19, 2017
Member
@Xaeroxe No problem at all; I was just curious.
| + pub neg: Button, | ||
| +} | ||
| + | ||
| +#[derive(Default)] |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
| + } | ||
| +} | ||
| + | ||
| +pub struct Axis { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
added some commits
Jun 19, 2017
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
@ebkalderon ready for your review again |
Xaeroxe
closed this
Jun 19, 2017
Xaeroxe
reopened this
Jun 19, 2017
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
Woops, closing was a misclick, my bad. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
@Xaeroxe Thank you so much for addressing all my comments. LGTM! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Xaeroxe
Jun 19, 2017
Member
Excellent! So what's our usual procedure for merging? It's gotten approval from 3 collaborators, so I think it's ready now.
|
Excellent! So what's our usual procedure for merging? It's gotten approval from 3 collaborators, so I think it's ready now. |
Xaeroxe commentedJun 17, 2017
I'm working on enhancements to the input system and adding support for key rebinding. I'm opening this pull request now to start gathering feedback.