good_web_game/
event.rs

1use crate::context::Context;
2
3#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
4use crate::input::gamepad::GamepadId;
5pub use crate::input::keyboard::KeyMods;
6pub use crate::input::MouseButton;
7use crate::GameError;
8#[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
9use gilrs::{Axis, Button};
10pub use miniquad::{graphics::GraphicsContext, KeyCode, TouchPhase};
11
12/// Used in [`EventHandler`](trait.EventHandler.html)
13/// to specify where an error originated
14#[derive(Debug, Copy, Clone, Eq, PartialEq)]
15pub enum ErrorOrigin {
16    /// error originated in `update()`
17    Update,
18    /// error originated in `draw()`
19    Draw,
20}
21
22/// A trait defining event callbacks.  This is your primary interface with
23/// `ggez`'s event loop.  Implement this trait for a type and
24/// override at least the [`update()`](#tymethod.update) and
25/// [`draw()`](#tymethod.draw) methods, then pass it to
26/// [`event::run()`](fn.run.html) to run the game's mainloop.
27///
28/// The default event handlers do nothing, apart from
29/// [`key_down_event()`](#tymethod.key_down_event), which will by
30/// default exit the game if the escape key is pressed.  Just
31/// override the methods you want to use.
32pub trait EventHandler<E = GameError>
33where
34    E: std::error::Error,
35{
36    /// Called upon each logic update to the game.
37    /// This should be where the game's logic takes place.
38    fn update(&mut self, _ctx: &mut Context, _quad_ctx: &mut GraphicsContext) -> Result<(), E>;
39    /// Called to do the drawing of your game.
40    /// You probably want to start this with
41    /// [`graphics::clear()`](../graphics/fn.clear.html) and end it
42    /// with [`graphics::present()`](../graphics/fn.present.html).
43    fn draw(&mut self, _ctx: &mut Context, _quad_ctx: &mut GraphicsContext) -> Result<(), E>;
44    /// Called when the user resizes the window, or when it is resized
45    /// via [`graphics::set_drawable_size()`](../graphics/fn.set_drawable_size.html).
46    fn resize_event(
47        &mut self,
48        _ctx: &mut Context,
49        _quad_ctx: &mut GraphicsContext,
50        _width: f32,
51        _height: f32,
52    ) {
53    }
54    /// The mouse was moved; it provides both absolute x and y coordinates in the window,
55    /// and relative x and y coordinates compared to its last position.
56    fn mouse_motion_event(
57        &mut self,
58        _ctx: &mut Context,
59        _quad_ctx: &mut GraphicsContext,
60        _x: f32,
61        _y: f32,
62        _dx: f32,
63        _dy: f32,
64    ) {
65    }
66    fn touch_event(
67        &mut self,
68        ctx: &mut Context,
69        _quad_ctx: &mut GraphicsContext,
70        phase: TouchPhase,
71        _id: u64,
72        x: f32,
73        y: f32,
74    ) {
75        ctx.mouse_context.input_handler.handle_mouse_move(x, y);
76        // TODO: this is ugly code duplication; I'll fix it later when getting rid of the `InputHandler`
77        let old_pos = crate::mouse::last_position(ctx);
78        let dx = x - old_pos.x;
79        let dy = y - old_pos.y;
80        // update the frame delta value
81        let old_delta = crate::mouse::delta(ctx);
82        ctx.mouse_context
83            .set_delta((old_delta.x + dx, old_delta.y + dy).into());
84        ctx.mouse_context.set_last_position((x, y).into());
85        match phase {
86            TouchPhase::Started => {
87                ctx.mouse_context
88                    .input_handler
89                    .handle_mouse_down(miniquad::MouseButton::Left);
90                self.mouse_button_down_event(ctx, _quad_ctx, MouseButton::Left, x, y);
91            }
92            TouchPhase::Moved => {
93                self.mouse_motion_event(ctx, _quad_ctx, x, y, dx, dy);
94            }
95            TouchPhase::Ended | TouchPhase::Cancelled => {
96                ctx.mouse_context
97                    .input_handler
98                    .handle_mouse_up(miniquad::MouseButton::Left);
99                self.mouse_button_up_event(ctx, _quad_ctx, MouseButton::Left, x, y);
100            }
101        }
102    }
103    /// The mousewheel was scrolled, vertically (y, positive away from and negative toward the user)
104    /// or horizontally (x, positive to the right and negative to the left).
105    fn mouse_wheel_event(
106        &mut self,
107        _ctx: &mut Context,
108        _quad_ctx: &mut GraphicsContext,
109        _x: f32,
110        _y: f32,
111    ) {
112    }
113    /// A mouse button was pressed.
114    fn mouse_button_down_event(
115        &mut self,
116        _ctx: &mut Context,
117        _quad_ctx: &mut GraphicsContext,
118        _button: MouseButton,
119        _x: f32,
120        _y: f32,
121    ) {
122    }
123    /// A mouse button was released.
124    fn mouse_button_up_event(
125        &mut self,
126        _ctx: &mut Context,
127        _quad_ctx: &mut GraphicsContext,
128        _button: MouseButton,
129        _x: f32,
130        _y: f32,
131    ) {
132    }
133
134    /// A keyboard button was pressed.
135    ///
136    /// The default implementation of this will call `ggez::event::quit()`
137    /// when the escape key is pressed.  If you override this with
138    /// your own event handler you have to re-implment that
139    /// functionality yourself.
140    fn key_down_event(
141        &mut self,
142        ctx: &mut Context,
143        _quad_ctx: &mut GraphicsContext,
144        keycode: KeyCode,
145        _keymods: KeyMods,
146        _repeat: bool,
147    ) {
148        if keycode == KeyCode::Escape {
149            quit(ctx);
150        }
151    }
152
153    /// A keyboard button was released.
154    fn key_up_event(
155        &mut self,
156        _ctx: &mut Context,
157        _quad_ctx: &mut GraphicsContext,
158        _keycode: KeyCode,
159        _keymods: KeyMods,
160    ) {
161    }
162
163    /// A unicode character was received, usually from keyboard input.
164    /// This is the intended way of facilitating text input.
165    fn text_input_event(
166        &mut self,
167        _ctx: &mut Context,
168        _quad_ctx: &mut GraphicsContext,
169        _character: char,
170    ) {
171    }
172
173    #[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
174    /// A gamepad button was pressed; `id` identifies which gamepad.
175    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
176    /// the gamepad.
177    fn gamepad_button_down_event(
178        &mut self,
179        _ctx: &mut Context,
180        _quad_ctx: &mut GraphicsContext,
181        _btn: Button,
182        _id: GamepadId,
183    ) {
184    }
185
186    #[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
187    /// A gamepad button was released; `id` identifies which gamepad.
188    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
189    /// the gamepad.
190    fn gamepad_button_up_event(
191        &mut self,
192        _ctx: &mut Context,
193        _quad_ctx: &mut GraphicsContext,
194        _btn: Button,
195        _id: GamepadId,
196    ) {
197    }
198
199    #[cfg(not(any(target_arch = "wasm32", target_os = "ios", target_os = "android",)))]
200    /// A gamepad axis moved; `id` identifies which gamepad.
201    /// Use [`input::gamepad()`](../input/fn.gamepad.html) to get more info about
202    /// the gamepad.
203    fn gamepad_axis_event(
204        &mut self,
205        _ctx: &mut Context,
206        _quad_ctx: &mut GraphicsContext,
207        _axis: Axis,
208        _value: f32,
209        _id: GamepadId,
210    ) {
211    }
212
213    /// Something went wrong, causing a `GameError`.
214    /// If this returns true, the error was fatal, so the event loop ends, aborting the game.
215    fn on_error(
216        &mut self,
217        _ctx: &mut Context,
218        _quad_ctx: &mut GraphicsContext,
219        _origin: ErrorOrigin,
220        _e: E,
221    ) -> bool {
222        true
223    }
224}
225
226/// Terminates the [`ggez::event::run()`](fn.run.html) loop by setting
227/// [`Context.continuing`](struct.Context.html#structfield.continuing)
228/// to `false`.
229///
230/// NOTE: Doesn't end the application on Wasm, as that's not really possible,
231/// but stops the `update` function from running.
232pub fn quit(ctx: &mut Context) {
233    ctx.continuing = false;
234}