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
//! This is a prototype game engine, focussed on abstracting away all rendering logic and focussing purely on the game logic. //! //! # Example //! //! ```no_run //! use cgmath::{Matrix4, Point3, Rad, Vector3}; //! use crystal_engine::{GameState, ModelHandle, Window, event::VirtualKeyCode}; //! //! fn main() { //! // Create a new instance of your game and run it //! let window = Window::<Game>::new(800., 600.).unwrap(); //! window.run(); //! } //! //! pub struct Game { //! // Your game state is stored here //! model: ModelHandle, //! } //! //! impl crystal_engine::Game for Game { //! fn init(state: &mut GameState) -> Self { //! // Load an object. This will automatically be rendered every frame //! // as long as the returned ModelHandle is not dropped. //! //! // Note that "new_obj_model" is only available when using the "format-obj" feature //! // for more information and different model formats, see the documentation of "GameState" //!# #[cfg(feature = "format-obj")] //! let model = state.new_obj_model("assets/some_object.obj") //! .with_position((0.0, -3.0, 0.0)) //! .with_scale(0.3) //! .build() //! .unwrap(); //! //!# #[cfg(not(feature = "format-obj"))] //!# let model: ModelHandle = unsafe { std::mem::zeroed() }; //! //! // Update the camera by manipulating the state's field //! state.camera = Matrix4::look_at( //! Point3::new(0.3, 0.3, 1.0), //! Point3::new(0.0, 0.0, 0.0), //! Vector3::new(0.0, -1.0, 0.0), //! ); //! //! Self { model } //! } //! //! fn keydown(&mut self, state: &mut GameState, key: VirtualKeyCode) { //! // Exit the game when the user hits escape //! if key == VirtualKeyCode::Escape { //! state.terminate_game(); //! } //! } //! //! fn update(&mut self, state: &mut GameState) { //! self.model.modify(|data| { //! // Rotate either left or right, based on what the user has pressed //! if state.keyboard.is_pressed(VirtualKeyCode::A) { //! data.rotation.y -= Rad(0.05); //! } //! if state.keyboard.is_pressed(VirtualKeyCode::D) { //! data.rotation.y += Rad(0.05); //! } //! }); //! } //! } //! ``` #![warn(missing_docs)] #![allow(clippy::needless_doctest_main)] #![allow(clippy::borrowed_box)] // There are two incorrect suggestions for this lint: https://github.com/rust-lang/rust-clippy/issues/3971 mod error; mod game_state; mod gui; mod internal; mod model; mod render; pub use self::{ game_state::GameState, gui::GuiElement, model::{ModelBuilder, ModelData, ModelHandle}, render::{ lights::{DirectionalLight, LightColor, PointLight, PointLightAttenuation}, window::Window, }, }; pub use rusttype::Font; /// Contains the states that are used in [GameState]. These are in a seperate module so we don't pollute the base module documentation. pub mod state { pub use crate::{ error::*, game_state::KeyboardState, gui::{ GuiElementBuilder, GuiElementCanvasBuilder, GuiElementData, GuiElementTextureBuilder, }, render::lights::{FixedVec, LightState}, }; } /// Re-exported module of `winit`, with some additional structs that are useful pub mod event { pub use winit::{dpi::PhysicalPosition, event::*}; } /// The entry point of the game implementation. /// /// In your game you will have to implement this trait for your own Game object. See the main module documentation for an example. pub trait Game { /// Create a new instance of the game. This will be called exactly once, whenever the game window is created. fn init(state: &mut GameState) -> Self; /// Update the game. This will be called every frame. Use this to implement your game logic. fn update(&mut self, state: &mut GameState); /// Checks if the game can shut down. This is called when a player tries to close the window by clicking X or pressing alt+f4 fn can_shutdown(&mut self, _state: &mut GameState) -> bool { true } /// Triggered when a winit event is received. fn event(&mut self, _state: &mut GameState, _event: &event::WindowEvent) {} /// Triggered when a key is pressed. /// /// Note that the [GameState.keyboard](struct.GameState.html#structfield.keyboard) is updated *before* this method is called. /// This means that `state.keyboard.is_pressed(key)` will always return `true`. fn keydown(&mut self, _state: &mut GameState, _key: event::VirtualKeyCode) {} /// Triggered when a key is released. /// /// Note that the [GameState.keyboard](struct.GameState.html#structfield.keyboard) is updated *before* this method is called. /// This means that `state.keyboard.is_pressed(key)` will always return `false`. fn keyup(&mut self, _state: &mut GameState, _key: event::VirtualKeyCode) {} }