use crate::context::Context;
#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
use crate::input::gamepad::GamepadId;
pub use crate::input::keyboard::KeyMods;
pub use crate::input::MouseButton;
use crate::GameError;
#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
use gilrs::{Axis, Button};
pub use miniquad::{graphics::GraphicsContext, KeyCode, TouchPhase};
/// Used in [`EventHandler`](trait.EventHandler.html)
/// to specify where an error originated
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ErrorOrigin {
/// error originated in `update()`
Update,
/// error originated in `draw()`
Draw,
}
/// A trait defining event callbacks. This is your primary interface with
/// `ggez`'s event loop. Implement this trait for a type and
/// override at least the [`update()`](#tymethod.update) and
/// [`draw()`](#tymethod.draw) methods, then pass it to
/// [`event::run()`](fn.run.html) to run the game's mainloop.
///
/// The default event handlers do nothing, apart from
/// [`key_down_event()`](#tymethod.key_down_event), which will by
/// default exit the game if the escape key is pressed. Just
/// override the methods you want to use.
pub trait EventHandler<E = GameError>
where
E: std::error::Error,
{
/// Called upon each logic update to the game.
/// This should be where the game's logic takes place.
fn update(&mut self, _ctx: &mut Context, _quad_ctx: &mut GraphicsContext) -> Result<(), E>;
/// Called to do the drawing of your game.
/// You probably want to start this with
/// [`graphics::clear()`](../graphics/fn.clear.html) and end it
/// with [`graphics::present()`](../graphics/fn.present.html).
fn draw(&mut self, _ctx: &mut Context, _quad_ctx: &mut GraphicsContext) -> Result<(), E>;
/// Called when the user resizes the window, or when it is resized
/// via [`graphics::set_drawable_size()`](../graphics/fn.set_drawable_size.html).
fn resize_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_width: f32,
_height: f32,
) {
}
/// The mouse was moved; it provides both absolute x and y coordinates in the window,
/// and relative x and y coordinates compared to its last position.
fn mouse_motion_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_x: f32,
_y: f32,
_dx: f32,
_dy: f32,
) {
}
fn touch_event(
&mut self,
ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
phase: TouchPhase,
_id: u64,
x: f32,
y: f32,
) {
ctx.mouse_context.input_handler.handle_mouse_move(x, y);
// TODO: this is ugly code duplication; I'll fix it later when getting rid of the `InputHandler`
let old_pos = crate::mouse::last_position(ctx);
let dx = x - old_pos.x;
let dy = y - old_pos.y;
// update the frame delta value
let old_delta = crate::mouse::delta(ctx);
ctx.mouse_context
.set_delta((old_delta.x + dx, old_delta.y + dy).into());
ctx.mouse_context.set_last_position((x, y).into());
match phase {
TouchPhase::Started => {
ctx.mouse_context
.input_handler
.handle_mouse_down(miniquad::MouseButton::Left);
self.mouse_button_down_event(ctx, _quad_ctx, MouseButton::Left, x, y);
}
TouchPhase::Moved => {
self.mouse_motion_event(ctx, _quad_ctx, x, y, dx, dy);
}
TouchPhase::Ended | TouchPhase::Cancelled => {
ctx.mouse_context
.input_handler
.handle_mouse_up(miniquad::MouseButton::Left);
self.mouse_button_up_event(ctx, _quad_ctx, MouseButton::Left, x, y);
}
}
}
/// The mousewheel was scrolled, vertically (y, positive away from and negative toward the user)
/// or horizontally (x, positive to the right and negative to the left).
fn mouse_wheel_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_x: f32,
_y: f32,
) {
}
/// A mouse button was pressed.
fn mouse_button_down_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_button: MouseButton,
_x: f32,
_y: f32,
) {
}
/// A mouse button was released.
fn mouse_button_up_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_button: MouseButton,
_x: f32,
_y: f32,
) {
}
/// A keyboard button was pressed.
///
/// The default implementation of this will call `ggez::event::quit()`
/// when the escape key is pressed. If you override this with
/// your own event handler you have to re-implment that
/// functionality yourself.
fn key_down_event(
&mut self,
ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
keycode: KeyCode,
_keymods: KeyMods,
_repeat: bool,
) {
if keycode == KeyCode::Escape {
quit(ctx);
}
}
/// A keyboard button was released.
fn key_up_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_keycode: KeyCode,
_keymods: KeyMods,
) {
}
/// A unicode character was received, usually from keyboard input.
/// This is the intended way of facilitating text input.
fn text_input_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_character: char,
) {
}
#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
/// A gamepad button was pressed; `id` identifies which gamepad.
/// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
/// the gamepad.
fn gamepad_button_down_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_btn: Button,
_id: GamepadId,
) {
}
#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
/// A gamepad button was released; `id` identifies which gamepad.
/// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
/// the gamepad.
fn gamepad_button_up_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_btn: Button,
_id: GamepadId,
) {
}
#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
/// A gamepad axis moved; `id` identifies which gamepad.
/// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
/// the gamepad.
fn gamepad_axis_event(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_axis: Axis,
_value: f32,
_id: GamepadId,
) {
}
/// Something went wrong, causing a `GameError`.
/// If this returns true, the error was fatal, so the event loop ends, aborting the game.
fn on_error(
&mut self,
_ctx: &mut Context,
_quad_ctx: &mut GraphicsContext,
_origin: ErrorOrigin,
_e: E,
) -> bool {
true
}
}
/// Terminates the [`ggez::event::run()`](fn.run.html) loop by setting
/// [`Context.continuing`](struct.Context.html#structfield.continuing)
/// to `false`.
///
/// NOTE: Doesn't end the application on Wasm, as that's not really possible,
/// but stops the `update` function from running.
pub fn quit(ctx: &mut Context) {
ctx.continuing = false;
}