1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
mod r#loop;

pub(crate) use r#loop::Loop;

use crate::graphics::{CursorIcon, Frame, Window, WindowSettings};
use crate::input::{keyboard, Input};
use crate::load::{LoadingScreen, Task};
use crate::{Debug, Result, Timer};

/// The entrypoint of the engine. It describes your game logic.
///
/// Implementors of this trait should hold the game state and any assets
/// necessary for drawing.
///
/// Coffee forces you to decouple your game state from your input state. While
/// this might seem limiting at first, it helps you to keep mutability at bay
/// and forces you to think about the architecture of your game.
pub trait Game {
    /// The input data of your game.
    ///
    /// The built-in [`KeyboardAndMouse`] type can be a good starting point. It
    /// allows you to query the state of the keyboard and the mouse.
    ///
    /// You can also build your custom input type using the [`Input`] trait.
    ///
    /// If your game does not deal with user input, use `()`.
    ///
    /// [`KeyboardAndMouse`]: input/struct.KeyboardAndMouse.html
    /// [`Input`]: input/trait.Input.html
    type Input: Input;

    /// The loading screen that will be used when your game starts.
    ///
    /// The built-in [`ProgressBar`] loading screen is a good choice to get
    /// started. It shows a simple progress bar.
    ///
    /// You can also build your own loading screen type using the
    /// [`LoadingScreen`] trait.
    ///
    /// If you do not want your game to have a loading screen, use `()`.
    ///
    /// [`ProgressBar`]: load/loading_screen/struct.ProgressBar.html
    /// [`LoadingScreen`]: load/loading_screen/trait.LoadingScreen.html
    type LoadingScreen: LoadingScreen;

    /// Defines how many times the [`update`] function should be called per
    /// second.
    ///
    /// By default, it is set to `60`.
    ///
    /// [`update`]: #method.update
    const TICKS_PER_SECOND: u16 = 60;

    /// Defines the key that will be used to toggle the [`debug`] view. Set it to
    /// `None` if you want to disable it.
    ///
    /// By default, it is set to `F12`.
    ///
    /// [`debug`]: #method.debug
    const DEBUG_KEY: Option<keyboard::KeyCode> = Some(keyboard::KeyCode::F12);

    /// Loads the [`Game`].
    ///
    /// Use the [`load`] module to load your assets here.
    ///
    /// [`Game`]: trait.Game.html
    /// [`load`]: load/index.html
    fn load(window: &Window) -> Task<Self>
    where
        Self: Sized;

    /// Draws the [`Game`].
    ///
    /// Check out the [`graphics`] module to learn more about rendering in
    /// Coffee.
    ///
    /// This function will be called once per frame.
    ///
    /// [`Game`]: trait.Game.html
    /// [`graphics`]: graphics/index.html
    /// [`update`]: #method.update
    fn draw(&mut self, frame: &mut Frame<'_>, timer: &Timer);

    /// Consumes [`Input`] to let users interact with the [`Game`].
    ///
    /// Right before an [`update`], input events will be processed and this
    /// function will be called. This reduces latency when multiple updates need
    /// to happen during a single frame.
    ///
    /// If no [`update`] is needed during a frame, it will still be called once,
    /// right after processing input events and before drawing. This allows you
    /// to keep your view updated every frame in order to offer a smooth user
    /// experience independently of the [`TICKS_PER_SECOND`] setting.
    ///
    /// You can access the [`Window`]. For instance, you may want to toggle
    /// fullscreen mode based on some input, or maybe access the [`Gpu`]
    /// to prepare some assets before rendering.
    ///
    /// By default, it does nothing.
    ///
    /// [`Input`]: #associatedtype.Input
    /// [`Game`]: trait.Game.html
    /// [`update`]: #method.update
    /// [`TICKS_PER_SECOND`]: #associatedconstant.TICKS_PER_SECOND
    /// [`Window`]: graphics/struct.Window.html
    /// [`Gpu`]: graphics/struct.Gpu.html
    fn interact(&mut self, _input: &mut Self::Input, _window: &mut Window) {}

    /// Updates the [`Game`].
    ///
    /// All your game logic should live here.
    ///
    /// The [`TICKS_PER_SECOND`] constant defines how many times this function
    /// will be called per second. This function may be called multiple times
    /// per frame if it is necessary.
    ///
    /// Notice that you are also allowed to access [`Window`] data. This can be
    /// useful if your [`Game`] needs to know how much of the world is visible.
    ///
    /// By default, it does nothing.
    ///
    /// [`Game`]: trait.Game.html
    /// [`TICKS_PER_SECOND`]: #associatedconstant.TICKS_PER_SECOND
    /// [`Window`]: graphics/struct.Window.html
    fn update(&mut self, _window: &Window) {}

    /// Defines the cursor icon of the window.
    ///
    /// By default, it returns platform-dependent default cursor.
    fn cursor_icon(&self) -> CursorIcon {
        CursorIcon::Default
    }

    /// Displays debug information.
    ///
    /// This method is called after [`draw`] once per frame when debug has been
    /// toggled using the [`DEBUG_KEY`]. Anything you draw here will be on top.
    ///
    /// Debug code is only called when compiling with `debug_assertions` _or_
    /// the `debug` feature enabled.
    ///
    /// By default, it shows [`Debug`], which displays a brief summary about
    /// game performance in the top left corner.
    ///
    /// [`draw`]: #tymethod.draw
    /// [`DEBUG_KEY`]: #associatedconstant.DEBUG_KEY
    /// [`Debug`]: struct.Debug.html
    fn debug(
        &self,
        _input: &Self::Input,
        frame: &mut Frame<'_>,
        debug: &mut Debug,
    ) {
        debug.draw(frame);
    }

    /// Handles a close request from the operating system to the game window.
    ///
    /// This function should return true to allow the game loop to end,
    /// otherwise false.
    ///
    /// By default, it does nothing and returns true.
    fn on_close_request(&mut self) -> bool {
        true
    }

    /// Returns whether the game is finished or not.
    ///
    /// If this function returns true, the game will be closed gracefully.
    ///
    /// By default, it always returns false.
    fn is_finished(&self) -> bool {
        false
    }

    /// Runs the [`Game`] with the given [`WindowSettings`].
    ///
    /// You probably want to call this in your `main` function to run your game!
    ///
    /// [`Game`]: trait.Game.html
    /// [`WindowSettings`]: graphics/struct.WindowSettings.html
    fn run(window_settings: WindowSettings) -> Result<()>
    where
        Self: 'static + Sized,
    {
        <r#loop::Default as Loop<Self>>::run(window_settings)
    }
}