Keyboard Input
There are two major ways to check the keyboard state - the simple and the event-based ones.
Simple way
The simplest way to check if a key was pressed/released or if it is still down is three methods of InputState
:
is_key_down
- returnstrue
if the specified key is pressed,false
- otherwise.is_key_pressed
- returnstrue
if the specified key was pressed in the current frame,false
- otherwise. This method will returnfalse
if the key is still pressed in the next frame. This is useful to check if a key was pressed and some action, but do not repeat the same action over and over until the key is released.is_key_released
- returnstrue
if the specified key was released in the current frame,false
- otherwise. This method will returnfalse
if the key is still released in the next frame. This is useful to check if a key was released and some action, but do not repeat the same action over and over until the key is pressed.
Typical usage of these methods is the following.
#![allow(unused)] fn main() { #[derive(Clone, Debug, Reflect, Visit, TypeUuidProvider, ComponentProvider)] #[type_uuid(id = "abbad54c-e267-4d7e-a3cd-e125a7e87ff0")] #[visit(optional)] pub struct Player {} impl ScriptTrait for Player { fn on_update(&mut self, ctx: &mut ScriptContext) { let node = &mut ctx.scene.graph[ctx.handle]; let transform = node.local_transform_mut(); // Check if the keys are down and move the player accordingly. if ctx.input_state.is_key_down(KeyCode::KeyA) { transform.offset(Vector3::new(-1.0, 0.0, 0.0)); } if ctx.input_state.is_key_down(KeyCode::KeyD) { transform.offset(Vector3::new(1.0, 0.0, 0.0)); } // It is also possible to check if a key was pressed or released on this frame. This // could be useful to do something only once per each press or release. For example, // jump could be performed on a key press. if ctx.input_state.is_key_pressed(KeyCode::Space) { transform.offset(Vector3::new(0.0, 1.0, 0.0)); } } } }
Event-based approach
The more advanced approach is to use keyboard events directly. This may seem harder to maintain than the simple
approach with functions like is_key_down
, but in reality it is slightly more verbose. The main advantage is
that this approach allows you to carefully select which entity will receive an event.
Keyboard input events can be handled by listening to WindowEvent::KeyboardInput
, for example you can check for A, D
keys and save their state in some variables in your script. These variables will tell the script that an entity, to
which the script was assigned, should move in a certain direction. This could be expressed like so:
#![allow(unused)] fn main() { #[derive(Clone, Debug, Reflect, Visit, TypeUuidProvider, ComponentProvider)] #[type_uuid(id = "abbad54c-e267-4d7e-a3cd-e125a7e87ff0")] #[visit(optional)] pub struct Player { move_left: bool, move_right: bool, } impl ScriptTrait for Player { fn on_os_event(&mut self, event: &Event<()>, _ctx: &mut ScriptContext) { // Listen to keyboard events, that comes to the main window. if let Event::WindowEvent { event: WindowEvent::KeyboardInput { event, .. }, .. } = event { let pressed = event.state == ElementState::Pressed; if let PhysicalKey::Code(code) = event.physical_key { // Check which key was pressed and remember this state for further usage. match code { KeyCode::KeyA => { self.move_left = pressed; } KeyCode::KeyD => { self.move_right = pressed; } _ => (), } } } } fn on_update(&mut self, ctx: &mut ScriptContext) { let node = &mut ctx.scene.graph[ctx.handle]; let transform = node.local_transform_mut(); if self.move_left { transform.offset(Vector3::new(-1.0, 0.0, 0.0)); } if self.move_right { transform.offset(Vector3::new(1.0, 0.0, 0.0)); } } } }
The main method here is on_os_event
, which listens for keyboard events and modifies script variables accordingly.
These two variables are then used in the on_update
method to move the entity, to which the script is assigned to.