Mouse Input

Mouse input is usually used to control a camera rotation, to pick objects in game world, etc. Let's take a look at the most common use cases.

Mouse Motion

The following example shows how to use raw mouse events to rotate an object. It could also be used to rotate a camera in your game (with slight modifications).

#![allow(unused)]
fn main() {
#[derive(Clone, Debug, Reflect, Visit, TypeUuidProvider, ComponentProvider)]
#[type_uuid(id = "abbad54c-e267-4d7e-a3cd-e125a7e87ff0")]
#[visit(optional)]
pub struct Player {
    yaw: f32,
    pitch: f32,
}

impl ScriptTrait for Player {
    fn on_os_event(&mut self, event: &Event<()>, _ctx: &mut ScriptContext) {
        // We'll listen to MouseMotion raw device event to rotate an object. It provides
        // offsets only.
        if let Event::DeviceEvent {
            event: DeviceEvent::MouseMotion {
                delta: (dx, dy), ..
            },
            ..
        } = event
        {
            self.pitch = (self.pitch + *dy as f32)
                .clamp(-std::f32::consts::FRAC_PI_2, std::f32::consts::FRAC_PI_2);
            self.yaw += *dx as f32;
        }
    }

    fn on_update(&mut self, ctx: &mut ScriptContext) {
        let node = &mut ctx.scene.graph[ctx.handle];
        let transform = node.local_transform_mut();
        transform.set_rotation(
            UnitQuaternion::from_axis_angle(&Vector3::x_axis(), self.pitch)
                * UnitQuaternion::from_axis_angle(&Vector3::y_axis(), self.yaw),
        );
    }
}
}

This example consists of two main parts - on_os_event and on_update methods. The first one is called when some event comes to the main window, and we need to check if this event is DeviceEvent::MouseMotion. After that, we're taking relative offsets (dx, dy) and modifying the pitch, yaw variables accordingly. on_update method is called every frame and it is used to apply pitch and yaw values to the scene node the script is assigned to.

Mouse Buttons

The following example shows how to handle events from mouse buttons.

#![allow(unused)]
fn main() {
#[derive(Clone, Debug, Reflect, Visit, TypeUuidProvider, ComponentProvider)]
#[type_uuid(id = "abbad54c-e267-4d7e-a3cd-e125a7e87ff1")]
#[visit(optional)]
pub struct Clicker {
    counter: i32,
}

impl ScriptTrait for Clicker {
    fn on_os_event(&mut self, event: &Event<()>, _ctx: &mut ScriptContext) {
        if let Event::WindowEvent {
            event: WindowEvent::MouseInput { button, state, .. },
            ..
        } = event
        {
            if *state == ElementState::Pressed {
                match *button {
                    MouseButton::Left => {
                        self.counter -= 1;
                    }
                    MouseButton::Right => {
                        self.counter += 1;
                    }
                    _ => (),
                }
            }
        }
    }
}
}

At first, we're checking for WindowEvent::MouseInput and creating respective bindings to its internals (button, state) and then all we need to do, is to check if the button was pressed and if so, which one.