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) } }