bevy_mouse_tracking_plugin 0.3.1

A plugin for effortless mouse tracking in the bevy game engine.
Documentation

bevy_mouse_tracking_plugin

CI bevy_mouse_tracking on crates.io bevy_mouse_tracking docs

Tracking the mouse in bevy is kind of annoying. You gotta use Events, and EventReaders, and even then, they only get called when the mouse actually moves.

This crate aims to make this as easy as possible, by providing a static resource that tracks the mouse position every frame.

This crate also supports more complex use cases such as multiple cameras, which are discussed further down.

Basics

First, add the plugin to your app:

use bevy::prelude::*;
use bevy_mouse_tracking_plugin::MousePosPlugin;

App::new()
    .add_plugins(DefaultPlugins)
    .add_plugin(MousePosPlugin::SingleCamera);

Now, you can access the resource in your Systems:

use bevy_mouse_tracking_plugin::MousePos;
fn dbg_mouse(mouse: Res<MousePos>) {
    eprintln!("{}", *mouse);
}

...and don't forget to add the system to your app:

    .add_plugin(MousePosPlugin::SingleCamera)
    .add_system(dbg_mouse);

This will print the screen-space location of the mouse on every frame.

However, we can do better than just screen-space: we support automatic transformation to world-space coordinates via the [MousePosWorld] resource.

use bevy_mouse_tracking_plugin::MousePosWorld;
fn dbg_world(mouse: Res<MousePosWorld>) {
    eprintln!("{}", *mouse);
}

This will print the world-space location of the mouse on every frame.
Note that this is only supported for two-dimensional, orthographic camera, but pull requests for 3D support are welcome!

Multiple cameras

You may notice that if you try to use this plugin in an app that has multiple cameras, it crashes!


App::new()
    .add_plugins(DefaultPlugins)
    .add_plugin(MousePosPlugin::SingleCamera)
    .add_startup_system(setup)
    .run();

fn setup(mut commands: Commands) {
    commands.spawn_bundle(Camera2dBundle::default());
    commands.spawn_bundle(Camera3dBundle::default());
}

This panics with the following output:

thread 'main' panicked at 'cannot identify main camera -- consider adding the MainCamera component to one of the cameras', src\mouse_pos.rs:207:55

This is because the plugin doesn't know which of the two cameras to use when figuring out the values of the [MousePos] and [MousePosWorld] resources. Let's take the panic message's advice.

    commands.spawn_bundle(Camera2dBundle::default())
        .insert(MainCamera); // added this line
    commands.spawn_bundle(Camera3dBundle::default());

Queries

If you want to get mouse tracking information relative to each camera individually, simply query for a [MousePos] or [MousePosWorld] as a component instead of as a resource.


App::new()
    // plugins omitted...
    .add_system(dbg_for_each);

fn dbg_for_each(mouse_pos: Query<&MousePosWorld>) {
    for pos in mouse_pos.iter() {
        // This prints the mouse position twice per frame:
        // once relative to the UI camera, and once relative to the physical camera.
        eprintln!("{}", *pos);
    }
}

No main camera

Let's say you have multiple cameras in your app, and you want to treat them all equally, without declaring any one of them as the main camera.
Change the plugin to this:

App::new()
    .add_plugins(DefaultPlugins)
    .add_plugin(MousePosPlugin::MultiCamera) // SingleCamera -> MultiCamera
    .add_startup_system(setup)
    // ...

Now, you can add as many cameras as you want, without having to worry about marking any of them as the main camera.
Note that [MousePos] and [MousePosWorld] will no longer be accessible as global resources -- you can only access them by Querying camera entities.

Opt-out of tracking for cameras

If you wish to have a camera be excluded from mouse tracking for whatever reason, you may give it the [ExcludeMouseTracking] component.

    commands.spawn_bundle(Camera2dBundle::default())
        .insert(ExcludeMouseTracking);

This camera will not have a [MousePos] or a [MousePosWorld], as it is completely excluded from mouse tracking.

One reason to do this is because this crate does not currently support cameras with projections other than Bevy's OrthographicProjection. If you use such a camera, even if you don't use it for tracking mouse position, you will find that it panics:

thread 'main' panicked at 'only orthographic cameras are supported -- consider adding an ExcludeMouseTracking component: QueryDoesNotMatch(5v0)', src\mouse_pos.rs:159:50

To get around this, you may choose to have the camera opt-out.

    commands.spawn_bundle(Camera3dBundle {
        projection: Projection::from(PerspectiveProjection::default()),
        ..default()
    }).insert(ExcludeMouseTracking);

Mouse motion

This crate supports a resource that tracks mouse motion, via [MouseMotionPlugin]. The motion can be accessed from any system in a [MouseMotion] resource.

Crate name

As a final aside: the name of this crate is intentionally verbose. This is because I didn't want to steal a crate name, especially since it is very likely that this crate will eventually be made redundant by future updates to bevy.
I recommend renaming the crate in your Cargo.toml:

[dependencies]
mouse_tracking = { package = "bevy_mouse_tracking_plugin", version = "..." }

License: MIT