From 1d23de2c919f8b9106c9d703076935464079c8aa Mon Sep 17 00:00:00 2001 From: Joe Clay <27cupsofcoffee@gmail.com> Date: Thu, 28 Mar 2024 18:08:26 +0000 Subject: [PATCH] Fix some docs issues --- docs/faq.md | 8 ++++---- docs/tutorial/01-creating-a-project.md | 22 +++++++++++----------- docs/tutorial/02-adding-the-paddles.md | 26 +++++++++++++------------- docs/tutorial/03-adding-a-ball.md | 4 ++-- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index aca1707..8c75bab 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -14,7 +14,7 @@ It's possible to have your project automatically compile SDL2 from source as par ```toml [dependencies.tetra] -version = "0.7" +version = "0.8" features = ["sdl2_bundled"] ``` @@ -26,7 +26,7 @@ If you want to avoid your users having to install SDL2 themselves (or you having ```toml [dependencies.tetra] -version = "0.7" +version = "0.8" features = ["sdl2_static_link"] ``` @@ -50,11 +50,11 @@ Yes - since 0.5.8, `Mesh` has constructors for basic shapes and there is a `Geom Note that primitive shape drawing currently isn't batched, so drawing too many generated shapes at once may be slow. -If that's all too complicated and you just want to draw simple rectangles, you could also [create a solid colored `Texture`](https://docs.rs/tetra/0.7.0/tetra/graphics/struct.Texture.html#method.from_data) and then draw that. If you create a 1x1 solid white texture, you can use the `scale` and `color` `DrawParams` to draw multiple rectangles of varying sizes/colors/transparencies in a single draw call. +If that's all too complicated and you just want to draw simple rectangles, you could also [create a solid colored `Texture`](https://docs.rs/tetra/0.8/tetra/graphics/struct.Texture.html#method.from_data) and then draw that. If you create a 1x1 solid white texture, you can use the `scale` and `color` `DrawParams` to draw multiple rectangles of varying sizes/colors/transparencies in a single draw call. ### Does Tetra support high-DPI rendering? -Tetra added basic support for high-DPI rendering in 0.5.4, which can be enabled via [`ContextBuilder::high_dpi`](https://docs.rs/tetra/0.7/tetra/struct.ContextBuilder.html#method.high_dpi). You may also need some platform-specific configuration/packaging - see the docs for `ContextBuilder::high_dpi` for more info. +Tetra added basic support for high-DPI rendering in 0.5.4, which can be enabled via [`ContextBuilder::high_dpi`](https://docs.rs/tetra/0.8/tetra/struct.ContextBuilder.html#method.high_dpi). You may also need some platform-specific configuration/packaging - see the docs for `ContextBuilder::high_dpi` for more info. ## Performance diff --git a/docs/tutorial/01-creating-a-project.md b/docs/tutorial/01-creating-a-project.md index 325bdca..a3e8925 100644 --- a/docs/tutorial/01-creating-a-project.md +++ b/docs/tutorial/01-creating-a-project.md @@ -19,7 +19,7 @@ Next, add Tetra as a dependency in the newly-generated `Cargo.toml`: ```toml [dependencies] -tetra = "0.7" +tetra = "0.8" ``` > [!WARNING] @@ -38,9 +38,9 @@ With that, we're ready to start developing our game! Let's take a closer look at ## Creating a Context -[`Context`](https://docs.rs/tetra/0.7/tetra/struct.Context.html) is a struct that holds all of the 'global' state managed by the framework, such as window settings and connections to the graphics/audio/input hardware. Any function in Tetra's API that requires access to this state will take a reference to a `Context` as the first parameter, so you won't get very far without one! +[`Context`](https://docs.rs/tetra/0.8/tetra/struct.Context.html) is a struct that holds all of the 'global' state managed by the framework, such as window settings and connections to the graphics/audio/input hardware. Any function in Tetra's API that requires access to this state will take a reference to a `Context` as the first parameter, so you won't get very far without one! -To build our game's `Context`, we can use the descriptively-named [`ContextBuilder`](https://docs.rs/tetra/0.7/tetra/struct.ContextBuilder.html) struct: +To build our game's `Context`, we can use the descriptively-named [`ContextBuilder`](https://docs.rs/tetra/0.8/tetra/struct.ContextBuilder.html) struct: ```rust fn main() { @@ -52,8 +52,8 @@ fn main() { This creates a `Context` that is configured to display a window with the title 'Pong', sized at 640 by 480 pixels, which will automatically close when the player presses the escape key. -> [!INFO] -> To see what other options can be set on a `Context`, and what the default settings are, take a look at the API documentation for [`ContextBuilder`](https://docs.rs/tetra/0.7/tetra/struct.ContextBuilder.html). +> [!NOTE] +> To see what other options can be set on a `Context`, and what the default settings are, take a look at the API documentation for [`ContextBuilder`](https://docs.rs/tetra/0.8/tetra/struct.ContextBuilder.html). If you `cargo run` your project from the command line now, you may be confused, as nothing will appear to happen. This is because we're not actually starting a game loop yet - `main` just returns straight away after the `Context` is created! @@ -61,9 +61,9 @@ To fix this, we'll need to implement `State`. ## Defining Some State -[`State`](https://docs.rs/tetra/0.7/tetra/trait.State.html) is a trait exposed by Tetra, which is implemented for the type that stores your game's state. It exposes various methods that will be called during the game loop, and you can override these in order to define your game's behaviour. +[`State`](https://docs.rs/tetra/0.8/tetra/trait.State.html) is a trait exposed by Tetra, which is implemented for the type that stores your game's state. It exposes various methods that will be called during the game loop, and you can override these in order to define your game's behaviour. -> [!INFO] +> [!NOTE] > This trait fulfils a similar purpose to the `Game` base class in XNA, or the `ApplicationListener` interface in LibGDX. For now, we don't need to store data or override any of the default behaviour, so we can just use an empty struct and implementation: @@ -76,7 +76,7 @@ impl State for GameState {} ## Running the Game Loop -Now that we have a `State`, we're ready to start the game loop! To do this, call the [`run`](https://docs.rs/tetra/0.7/tetra/struct.Context.html#method.run) method on `Context`, passing in a closure that constructs your `State` struct: +Now that we have a `State`, we're ready to start the game loop! To do this, call the [`run`](https://docs.rs/tetra/0.8/tetra/struct.Context.html#method.run) method on `Context`, passing in a closure that constructs your `State` struct: ```rust fn main() -> tetra::Result { @@ -89,13 +89,13 @@ fn main() -> tetra::Result { There's a few things you should pay attention to here: -- The return type of `main` has been changed to [`tetra::Result`](https://docs.rs/tetra/0.7/tetra/error/type.Result.html). +- The return type of `main` has been changed to [`tetra::Result`](https://docs.rs/tetra/0.8/tetra/error/type.Result.html). - A [`?` operator](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator) has been added to the end of `build`. - There is no semi-colon after `run`, so its output will be returned from `main`. `build` will return an error if the context fails to be constructed, and `run` will return any errors you throw during the game loop. By using the `?` operator, we can propagate these errors up and out of `main`. Rust will then automatically print out the error message to the terminal, which is handy when debugging. -> [!INFO] +> [!NOTE] > Returning `Result` from `main` is nice for prototyping, but doesn't give you much control over how the error gets reported. If you want to customize this, you can always `match` on the result of `build` and/or `run`. You may also notice that the closure takes a parameter, which we're currently ignoring - we'll look at what that's for next chapter. @@ -106,7 +106,7 @@ If you run `cargo run` from your terminal now, you should finally see a window Our goal for this chapter was to set up our project, and we've done that! A black window isn't very interesting, though, so let's finish by changing the background color to something a bit more inspiring. -To do this, we'll implement one of the `State` trait methods. [`draw`](https://docs.rs/tetra/0.7/tetra/trait.State.html#method.draw) is called by Tetra whenever it is time for the engine to draw a new frame. We can call [`tetra::graphics::clear`](https://docs.rs/tetra/0.7/tetra/graphics/fn.clear.html) inside this method to clear the window to a plain color: +To do this, we'll implement one of the `State` trait methods. [`draw`](https://docs.rs/tetra/0.8/tetra/trait.State.html#method.draw) is called by Tetra whenever it is time for the engine to draw a new frame. We can call [`tetra::graphics::clear`](https://docs.rs/tetra/0.8/tetra/graphics/fn.clear.html) inside this method to clear the window to a plain color: ```rust impl State for GameState { diff --git a/docs/tutorial/02-adding-the-paddles.md b/docs/tutorial/02-adding-the-paddles.md index 5c40f33..8b45133 100644 --- a/docs/tutorial/02-adding-the-paddles.md +++ b/docs/tutorial/02-adding-the-paddles.md @@ -19,10 +19,10 @@ Create a folder called `resources` in your project directory, and save this imag ![Player 1 sprite](./images/player1.png) -> [!INFO] +> [!NOTE] > The naming of this folder isn't something that's enforced by Tetra - structure your projects however you'd like! -To add this image to our game, we can use our first new type of the chapter: [`Texture`](https://docs.rs/tetra/0.7/tetra/graphics/struct.Texture.html). This represents a piece of image data that has been loaded into graphics memory. +To add this image to our game, we can use our first new type of the chapter: [`Texture`](https://docs.rs/tetra/0.8/tetra/graphics/struct.Texture.html). This represents a piece of image data that has been loaded into graphics memory. Since we want our texture to stay loaded until the game closes, let's add it as a field in our `GameState` struct: @@ -32,7 +32,7 @@ struct GameState { } ``` -We can then use [`Texture::new`](https://docs.rs/tetra/0.7/tetra/graphics/struct.Texture.html#method.new) to load the sprite and populate that field: +We can then use [`Texture::new`](https://docs.rs/tetra/0.8/tetra/graphics/struct.Texture.html#method.new) to load the sprite and populate that field: ```rust fn main() -> tetra::Result { @@ -50,7 +50,7 @@ Notice that we're now using the previously unnamed parameter that's passed to th Try running the game now - if all is well, it should start up just like it did last chapter. If you get an error message, check that you've entered the image's path correctly! -> [!INFO] +> [!NOTE] > A `Texture` is effectively just an ID number under the hood. This means that they are very lightweight and cheap to clone - don't tie yourself in knots trying to pass references to them around your application! > > The same is true for quite a few other types in Tetra - check the API documentation for more info. @@ -106,7 +106,7 @@ fn main() -> tetra::Result { } ``` -> [!INFO] +> [!NOTE] > The `i32` casts look a bit silly, but for most of the places we'll be using the constants, it'll be easier to have them as floating point numbers. With that bit of housekeeping out of the way, let's finally draw something! @@ -129,10 +129,10 @@ fn draw(&mut self, ctx: &mut Context) -> tetra::Result { This will draw the texture to the screen at position `16.0, 16.0`. -> [!INFO] -> If you look at the docs for [`Texture::draw`](https://docs.rs/tetra/0.7/tetra/graphics/struct.Texture.html#method.draw), you'll notice that the type of the second parameter is actually `Into`, not `Vec2`. +> [!NOTE] +> If you look at the docs for [`Texture::draw`](https://docs.rs/tetra/0.8/tetra/graphics/struct.Texture.html#method.draw), you'll notice that the type of the second parameter is actually `Into`, not `Vec2`. > -> When you pass in a `Vec2`, it is automatically converted into a [`DrawParams`](https://docs.rs/tetra/0.7/tetra/graphics/struct.DrawParams.html) struct with the `position` parameter set. If you want to change other parameters, such as the rotation, color or scale, you can construct your own `DrawParams` instead, using `DrawParams::new`. +> When you pass in a `Vec2`, it is automatically converted into a [`DrawParams`](https://docs.rs/tetra/0.8/tetra/graphics/struct.DrawParams.html) struct with the `position` parameter set. If you want to change other parameters, such as the rotation, color or scale, you can construct your own `DrawParams` instead, using `DrawParams::new`. ## Reacting to Input @@ -187,14 +187,14 @@ While we _could_ do this in our `draw` method, this is a bad idea for several re - Mixing up our game logic and our rendering logic isn't great seperation of concerns. - The `draw` method does not get called at a consistent rate - the timing can fluctuate depending on the speed of the system the game is being run on, leading to subtle differences in behaviour. This is fine for drawing, but definitely not for physics! -Instead, it's time for us to add another method to our [`State`](https://docs.rs/tetra/0.7/tetra/trait.State.html) implementation. The [`update`](https://docs.rs/tetra/0.7/tetra/trait.State.html#method.update) method is called 60 times a second, regardless of how fast the game as a whole is running. This means that even if rendering slows to a crawl, you can still be confident that the code in that method is deterministic. +Instead, it's time for us to add another method to our [`State`](https://docs.rs/tetra/0.8/tetra/trait.State.html) implementation. The [`update`](https://docs.rs/tetra/0.8/tetra/trait.State.html#method.update) method is called 60 times a second, regardless of how fast the game as a whole is running. This means that even if rendering slows to a crawl, you can still be confident that the code in that method is deterministic. -> [!INFO] +> [!NOTE] > This 'fixed-rate update, variable-rate rendering' style of game loop is best explained by Glenn Fiedler's classic '[Fix Your Timestep](https://gafferongames.com/post/fix_your_timestep/)' blog post. If you've used the `FixedUpdate` method in Unity, this should feel pretty familiar! > -> If you want to change the rate at which updates happen, or switch to a more traditional 'lockstep' game loop, you can do this via the [`timestep` parameter on `ContextBuilder`](https://docs.rs/tetra/0.7/tetra/struct.ContextBuilder.html#method.timestep). +> If you want to change the rate at which updates happen, or switch to a more traditional 'lockstep' game loop, you can do this via the [`timestep` parameter on `ContextBuilder`](https://docs.rs/tetra/0.8/tetra/struct.ContextBuilder.html#method.timestep). -Inside the `update` method, we can use the functions exposed by the [`input`](https://docs.rs/tetra/0.7/tetra/input/index.html) module in order to check the state of the keyboard: +Inside the `update` method, we can use the functions exposed by the [`input`](https://docs.rs/tetra/0.8/tetra/input/index.html) module in order to check the state of the keyboard: ```rust // Inside `impl State for GameState`: @@ -237,7 +237,7 @@ impl Entity { } ``` -> [!INFO] +> [!NOTE] > It's worth mentioning at this point: this isn't the only way of structuring a game in Rust! > > The language lends itself very well to 'data-driven' design patterns, such as [entity component systems](https://en.wikipedia.org/wiki/Entity_component_system), and you'll definitely want to investigate these concepts if you start writing a bigger game. For now though, let's keep things as simple as possible! diff --git a/docs/tutorial/03-adding-a-ball.md b/docs/tutorial/03-adding-a-ball.md index b4f57f7..dc1c88a 100644 --- a/docs/tutorial/03-adding-a-ball.md +++ b/docs/tutorial/03-adding-a-ball.md @@ -157,7 +157,7 @@ if paddle_hit.is_some() { } ``` -> [!INFO] +> [!NOTE] > Storing the identity of the paddle that got hit is redundant right now, but we'll use it later! > [!WARNING] @@ -210,7 +210,7 @@ if let Some(paddle) = paddle_hit { } ``` -> [!INFO] +> [!NOTE] > I'll admit, it's a little bit wasteful to calculate the X center as well, but I'm aiming for code clarity over maximum efficiency. Besides, it's a Pong clone, not Crysis! Now the player has some agency over where the ball goes - too much agency, as it turns out, as they can just send it flying off the top of the screen! A little bit more code at the end of `update` will fix that: