From 67c293238d1ac84cef64c338bb19f5afcf31d1e9 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 20:20:44 +0100 Subject: [PATCH 01/11] Replace the joinedtogether build with a template build --- book/src/SUMMARY.md | 2 +- book/src/introduction/introduction.md | 3 ++- book/src/setup/building.md | 25 +++++++++++-------------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index be3bdd75..e6699916 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -7,7 +7,7 @@ - [Linux setup](./setup/linux.md) - [Windows setup]() - [Mac OS setup]() - - [Building the game](./setup/building.md) + - [Building the template](./setup/building.md) - [Learn agb part I - pong](./pong/01_introduction.md) - [The Gba struct](./pong/02_the_gba_struct.md) - [Sprites](./pong/03_sprites.md) diff --git a/book/src/introduction/introduction.md b/book/src/introduction/introduction.md index ec14a26e..4529d83e 100644 --- a/book/src/introduction/introduction.md +++ b/book/src/introduction/introduction.md @@ -26,4 +26,5 @@ It is super rewarding being able to play a game you made yourself on a piece of * [agb's crates.io page](https://crates.io/crates/agb) * [agb's documentation](https://docs.rs/agb) which is useful if you need a quick reference * [Awesome Game Boy Advance development](https://github.com/gbdev/awesome-gbadev) contains links to popular libraries, emulators and the super friendly gbadev discord -* [Example game](https://lostimmortal.itch.io/the-hat-chooses-the-wizard) written using agb as part of the 2021 GMTK game jam. \ No newline at end of file +* [Example game](https://lostimmortal.itch.io/the-hat-chooses-the-wizard) written using agb as part of the 2021 GMTK game jam. +* [More example games](https://github.com/agbrs/agb/releases/latest) built using agb. See them in `examples.zip` attached to the latest release. \ No newline at end of file diff --git a/book/src/setup/building.md b/book/src/setup/building.md index 2ce23aec..4b96811e 100644 --- a/book/src/setup/building.md +++ b/book/src/setup/building.md @@ -1,34 +1,31 @@ -# Building the game +# Building the template -By the end of this section, you should be able to build and run an example game made using agb! -**This section is optional.** -If you just want to get straight into building your own games, you don't need to do this. -However, we recommended doing this section to prove that your setup works. +By the end of this section, you should be able to build and run the **agb** template. # 1. Get the source code -The source code can be fetched using `git clone https://github.com/agbrs/joinedtogether.git`. +The source code can be fetched using `git clone https://github.com/agbrs/template.git`. -# 2. Build the game +# 2. Build the template -Build a copy of the game using `cargo build --release`. -This could take quite a while, but eventually you'll end up with a copy of the game in `target/thumbv4t-none-eabi/release/joinedtogether` or `target/thumbv4t-none-eabi/release/joinedtogether.elf` depending on platform. +Build a copy of the template using `cargo build --release`. +This could take quite a while, but eventually you'll end up with a copy of the template in `target/thumbv4t-none-eabi/release/template` or `target/thumbv4t-none-eabi/release/template.elf` depending on platform. This can be run directly by some emulators, but we need to run an extra step in order to convert the elf file into a '.gba' file. ```sh -arm-none-eabi-objcopy -O binary target/thumbv4t-none-eabi/release/joinedtogether joinedtogether.gba -gbafix joinedtogether.gba +arm-none-eabi-objcopy -O binary target/thumbv4t-none-eabi/release/template template.gba +gbafix template.gba ``` or ```sh -arm-none-eabi-objcopy -O binary target/thumbv4t-none-eabi/release/joinedtogether.elf joinedtogether.gba -gbafix joinedtogether.gba +arm-none-eabi-objcopy -O binary target/thumbv4t-none-eabi/release/template.elf template.gba +gbafix template.gba ``` And then load the resulting file in your emulator of choice. That's all there is to it! -If you have `mgba-qt` in your path, then you can launch the game directly using `cargo run --release` \ No newline at end of file +If you have `mgba-qt` in your path, then you can launch the template directly using `cargo run --release`. \ No newline at end of file From eeffd80e50c615e5203cff110bd451eeef1446fe Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 20:27:51 +0100 Subject: [PATCH 02/11] Format the code better --- book/src/pong/03_sprites.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/book/src/pong/03_sprites.md b/book/src/pong/03_sprites.md index 77df0726..db0a4a2d 100644 --- a/book/src/pong/03_sprites.md +++ b/book/src/pong/03_sprites.md @@ -52,7 +52,8 @@ The third until the fifth is the ball, with various squashed states. The aseprite file defines tags for these sprites, being "Paddle End", "Paddle Mid", and "Ball". ```rust -use agb::{include_aseprite, +use agb::{ + include_aseprite, display::object::{Graphics, Tag} }; From 2705c58a72bd8abf97daf35cb20daf9d85108b23 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 20:41:07 +0100 Subject: [PATCH 03/11] Small tweaks to the wording and add a comment about hblank --- book/src/pong/03_sprites.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/book/src/pong/03_sprites.md b/book/src/pong/03_sprites.md index db0a4a2d..12401f9f 100644 --- a/book/src/pong/03_sprites.md +++ b/book/src/pong/03_sprites.md @@ -27,7 +27,8 @@ For our pong game, all the sprites will be 16x16 pixels to make things a bit sim Sprites are stored in the Game Boy Advance in a special area of video memory called the 'Object Attribute Memory' (OAM). This has space for the 'attributes' of the sprites (things like whether or not they are visible, the location, which tile to use etc) but it does not store the actual pixel data. -The pixel data is stored in a different part of video RAM (VRAM) and the OAM only stores which tiles to use from this area. +The pixel data is stored in a video RAM (VRAM). +Because of this split, it is possible to have multiple sprites refer to the same tiles in video RAM which saves space and allows for more objects on screen at once then repeating them would otherwise allow. Since RAM is in short supply, and at the time was quite expensive, the tile data is stored as indexed palette data. So rather than storing the full colour data for each pixel in the tile, the Game Boy Advance instead stores a 'palette' of colours and the tiles which make up the sprites are stored as indexes to the palette. @@ -75,7 +76,7 @@ Using the `Gba` struct we get the [`ObjectController` struct](https://docs.rs/ag ```rust #[agb::entry] fn main(gba: mut agb::Gba) -> ! { - // Get the OAM manager + // Get the object manager let object = gba.display.object.get(); // Create an object with the ball sprite @@ -84,8 +85,9 @@ fn main(gba: mut agb::Gba) -> ! { // Place this at some point on the screen, (50, 50) for example ball.set_x(50).set_y(50).show(); - // Now commit the object controller so this change is reflected on the screen, - // this should normally be done in vblank but it'll work just fine here for now + // Now commit the object controller so this change is reflected on the screen. + // This isn't how we will do this in the final version of the code, but will do + // for this example. object.commit(); loop {} @@ -96,11 +98,16 @@ If you run this you should now see the ball for this pong game somewhere in the # Making the sprite move -As mentioned before, you should `.commit()` your sprites only during `vblank` which is the (very short) period of time nothing is being rendered to screen. -`agb` provides a convenience function for waiting until this happens called `agb::display::busy_wait_for_vblank()`. +The GBA renders to the screen one pixel at a time a line at a time from left to right. +After it has finished rendering to each pixel of the screen, it briefly pauses rendering before starting again. +This period of no drawing is called `vblank`, which stands for the 'vertical blanking interval'. +There is also a 'horizontal blanking interval', but that is outside of the scope of this book. + +You should `.commit()` your sprites only during this `vblank` phase, because otherwise you may end up moving a sprite during the rendering which could cause tearing of your objects[^hblank]. +`agb` provides a convenience function for waiting until the right moment called `agb::display::busy_wait_for_vblank()`. You shouldn't use this is a real game (we'll do it properly later on), but for now we can use this to wait for the correct time to `commit` our sprites to memory. -Making the sprite move 1 pixel every frame (so approximately 60 pixels per second) can be done as follows: +Making the sprite move 1 pixel every frame (so 60 pixels per second) can be done as follows: ```rust // replace the call to object.commit() with the following: @@ -136,4 +143,7 @@ loop { # What we did -In this section, we covered why sprites are important, how to create and manage them using the `ObjectController` in `agb` and make a ball bounce around the screen. \ No newline at end of file +In this section, we covered why sprites are important, how to create and manage them using the `ObjectController` in `agb` and make a ball bounce around the screen. + +[^hblank]: Timing this can give you some really cool effects allowing you to push the hardware. + However, `agb` does not by default provide the timing accuracy needed to fully take advantage of this, erring on the side of making it easier to make games rather than squeezing every last drop of performance from the console. \ No newline at end of file From e666ebbd05338aa1d3b4e745a983dfdcc7e20fd5 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 20:52:11 +0100 Subject: [PATCH 04/11] Start section on controls --- book/src/SUMMARY.md | 1 + book/src/pong/04_controls.md | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 book/src/pong/04_controls.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index e6699916..41b154d2 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -11,3 +11,4 @@ - [Learn agb part I - pong](./pong/01_introduction.md) - [The Gba struct](./pong/02_the_gba_struct.md) - [Sprites](./pong/03_sprites.md) + - [Controls](./pong/04_controls.md) diff --git a/book/src/pong/04_controls.md b/book/src/pong/04_controls.md new file mode 100644 index 00000000..d4a146c1 --- /dev/null +++ b/book/src/pong/04_controls.md @@ -0,0 +1,23 @@ +# Controls + +In this section, we'll make the ball that we displayed in the last section move by pressing the D-Pad. + +# The GBA controls + +The GBA has 10 buttons we can read the state of, and this is the only way a player can directly control the game. +They are the 4 directions on the D-Pad, A, B, Start, Select, and the L and R triggers. + +# Reading the button state + +There are two ways to capture the button state in **agb**, interrupts and polling. +In most games, you will want to use polling, so that is what we will use now. +Interrupts will be covered in a later chapter. + +To add button control to our game, we will need a [ButtonController](https://docs.rs/agb/latest/agb/input/struct.ButtonController.html). +Add this near the top of your main function: + +```rust + let mut input = agb::input::ButtonController::new(); +``` + +The button controller is not part of the `Gba` struct because it only allows for reading and not writing so does not need to be controlled by the borrow checker. \ No newline at end of file From dfa70f43358ac927896197287aebd8594e21c45f Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 21:20:59 +0100 Subject: [PATCH 05/11] Add a bunch of docs for input --- agb/src/input.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/agb/src/input.rs b/agb/src/input.rs index c36866e4..8cc5fc87 100644 --- a/agb/src/input.rs +++ b/agb/src/input.rs @@ -2,10 +2,30 @@ use crate::fixnum::Vector2D; use bitflags::bitflags; use core::convert::From; +/// Tri-state enum. Allows for -1, 0 and +1. +/// Useful if checking if the D-Pad is pointing left, right, or unpressed. +/// +/// Note that [Tri] can be converted directly to a signed integer, so can easily be used to update positions of things in games +/// +/// # Examples +/// ```rust,no_run +/// # #![no_std] +/// use agb::input::Tri; +/// +/// # fn main() { +/// let x = 5; +/// let tri = Tri::Positive; // e.g. from button_controller.x_tri() +/// +/// assert_eq!(x + tri as i32, 6); +/// # } +/// ``` #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] pub enum Tri { + /// Right or down Positive = 1, + /// Unpressed Zero = 0, + /// Left or up Negative = -1, } @@ -18,16 +38,27 @@ impl From<(bool, bool)> for Tri { } bitflags! { + /// Represents a button on the GBA pub struct Button: u32 { + /// The A button const A = 1 << 0; + /// The B button const B = 1 << 1; + /// The SELECT button const SELECT = 1 << 2; + /// The START button const START = 1 << 3; + /// The RIGHT button on the D-Pad const RIGHT = 1 << 4; + /// The LFET button on the D-Pad const LEFT = 1 << 5; + /// The UP button on the D-Pad const UP = 1 << 6; + /// The DOWN button on the D-Pad const DOWN = 1 << 7; + /// The R button on the D-Pad const R = 1 << 8; + /// The L button on the D-Pad const L = 1 << 9; } } @@ -36,6 +67,28 @@ const BUTTON_INPUT: *mut u16 = (0x04000130) as *mut u16; // const BUTTON_INTURRUPT: *mut u16 = (0x04000132) as *mut u16; +/// Helper to make it easy to get the current state of the GBA's buttons. +/// +/// # Example +/// +/// ```rust,no_run +/// # #![no_std] +/// use agb::input::{ButtonController, Tri}; +/// +/// # fn main() { +/// let mut input = ButtonController::new(); +/// +/// loop { +/// input.update(); // call update every loop +/// +/// match input.x_tri() { +/// Tri::Negative => { /* left is being pressed */ } +/// Tri::Positive => { /* right is being pressed */ } +/// Tri::Zero => { /* Neither left nor right (or both) are pressed */ } +/// } +/// } +/// # } +/// ``` pub struct ButtonController { previous: u16, current: u16, @@ -48,6 +101,8 @@ impl Default for ButtonController { } impl ButtonController { + /// Create a new ButtonController. + /// This is the preferred way to create it. #[must_use] pub fn new() -> Self { let pressed = !unsafe { BUTTON_INPUT.read_volatile() }; @@ -57,11 +112,16 @@ impl ButtonController { } } + /// Updates the state of the button controller. + /// You should call this every frame (either at the start or the end) to ensure that you have the latest state of each button press. + /// Calls to any method won't change until you call this. pub fn update(&mut self) { self.previous = self.current; self.current = !unsafe { BUTTON_INPUT.read_volatile() }; } + /// Returns [Tri::Positive] if right is pressed, [Tri::Negative] if left is pressed and [Tri::Zero] if neither or both are pressed. + /// This is the normal behaviour you'll want if you're using orthogonal inputs. #[must_use] pub fn x_tri(&self) -> Tri { let left = self.is_pressed(Button::LEFT); @@ -70,6 +130,8 @@ impl ButtonController { (left, right).into() } + /// Returns [Tri::Positive] if down is pressed, [Tri::Negative] if up is pressed and [Tri::Zero] if neither or both are pressed. + /// This is the normal behaviour you'll want if you're using orthogonal inputs. #[must_use] pub fn y_tri(&self) -> Tri { let up = self.is_pressed(Button::UP); @@ -78,6 +140,7 @@ impl ButtonController { (up, down).into() } + /// Returns true if all the buttons specified in `keys` are pressed. #[must_use] pub fn vector(&self) -> Vector2D where @@ -121,11 +184,32 @@ impl ButtonController { (currently_pressed & keys) != 0 } + /// Returns true if all the buttons specified in `keys` are not pressed. Equivalent to `!is_pressed(keys)`. #[must_use] pub fn is_released(&self, keys: Button) -> bool { !self.is_pressed(keys) } + /// Returns true if all the buttons specified in `keys` went from not pressed to pressed in the last frame. + /// Very useful for menu navigation or selection if you want the players actions to only happen for one frame. + /// + /// # Example + /// ```no_run,rust + /// # #![no_std] + /// use agb::input::{Button, ButtonController}; + /// + /// # fn main() { + /// let mut button_controller = ButtonController::new(); + /// + /// loop { + /// button_controller.update(); + /// + /// if button_controller.is_just_pressed(Button::A) { + /// // A button was just pressed, maybe select the currently selected item + /// } + /// } + /// # } + /// ``` #[must_use] pub fn is_just_pressed(&self, keys: Button) -> bool { let current = u32::from(self.current); @@ -134,6 +218,8 @@ impl ButtonController { ((current & keys) != 0) && ((previous & keys) == 0) } + /// Returns true if all the buttons specified in `keys` went from pressed to not pressed in the last frame. + /// Very useful for menu navigation or selection if you want players actions to only happen for one frame. #[must_use] pub fn is_just_released(&self, keys: Button) -> bool { let current = u32::from(self.current); From c58899eb9931cba6bb9dcc6e8dccf3c9f2894864 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 21:31:05 +0100 Subject: [PATCH 06/11] Add a second half to the controls section --- book/src/pong/04_controls.md | 63 ++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/book/src/pong/04_controls.md b/book/src/pong/04_controls.md index d4a146c1..aecb5624 100644 --- a/book/src/pong/04_controls.md +++ b/book/src/pong/04_controls.md @@ -17,7 +17,66 @@ To add button control to our game, we will need a [ButtonController](https://doc Add this near the top of your main function: ```rust - let mut input = agb::input::ButtonController::new(); +let mut input = agb::input::ButtonController::new(); ``` -The button controller is not part of the `Gba` struct because it only allows for reading and not writing so does not need to be controlled by the borrow checker. \ No newline at end of file +The button controller is not part of the `Gba` struct because it only allows for reading and not writing so does not need to be controlled by the borrow checker. + +Replace the inner loop with the following: + +```rust +let mut ball_x = 50; +let mut ball_y = 50; + +// now we initialise the x and y velocities to 0 rather than 1 +let mut x_velocity = 0; +let mut y_velocity = 0; + +loop { + ball_x = (ball_x + x_velocity).clamp(0, agb::display::WIDTH - 16); + ball_y = (ball_y + y_velocity).clamp(0, agb::display::HEIGHT - 16); + + // x_tri and y_tri describe with -1, 0 and 1 which way the d-pad + // buttons are being pressed + x_velocity = input.x_tri() as i32; + y_velocity = input.y_try() as i32; + + ball.set_x(ball_x as u16).set_y(ball_y as u16); + + agb::display::busy_wait_for_vblank(); + object.commit(); + + // We must call input.update() every frame otherwise it won't update based + // on the actual button press state. + input.update(); +} +``` + +Here we use the `x_tri()` and `y_tri()` methods. +They return instances of the [`Tri`](https://docs.rs/agb/latest/agb/input/enum.Tri.html) enum which describes which buttons are being pressed, and are very helpful in situations like these where you want to move something in a cardinal direction based on which buttons are pressed. + +# Detecting individual button presses + +If you want to detect if any button is pressed, you can use the `is_pressed` method on `ButtonController`. +For example, we can do the following: + +```rust +use agb::input::Button; + +if input.is_pressed(Button::A) { + // the A button is pressed +} +``` + +`ButtonController` also provides the `is_just_pressed` method. +This will return true for 1 frame, the one where the player actually pressed the button. +From that point on, it'll return false again until the player presses it again. + +# What we did + +We added very basic button control to our bouncing ball example. +In the next step, we'll cover meta-sprites and actually add a bat to our game of pong. + +# Exercise + +Make it so the ball moves twice as fast if you're pressing the `A` button while moving it arond. \ No newline at end of file From c57013aafde6aec5283f37f9de1abd720e622a75 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 21:32:11 +0100 Subject: [PATCH 07/11] Add deny(missing_docs) to input --- agb/src/input.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/agb/src/input.rs b/agb/src/input.rs index 8cc5fc87..c5c4f47e 100644 --- a/agb/src/input.rs +++ b/agb/src/input.rs @@ -1,3 +1,4 @@ +#![deny(missing_docs)] use crate::fixnum::Vector2D; use bitflags::bitflags; use core::convert::From; @@ -80,7 +81,7 @@ const BUTTON_INPUT: *mut u16 = (0x04000130) as *mut u16; /// /// loop { /// input.update(); // call update every loop -/// +/// /// match input.x_tri() { /// Tri::Negative => { /* left is being pressed */ } /// Tri::Positive => { /* right is being pressed */ } @@ -150,6 +151,9 @@ impl ButtonController { } #[must_use] + /// Returns [Tri::Positive] if left was just pressed, [Tri::Negative] if right was just pressed and [Tri::Zero] if neither or both are just pressed. + /// + /// Also returns [Tri::Zero] after the call to [update()] if the button is still held. pub fn just_pressed_x_tri(&self) -> Tri { let left = self.is_just_pressed(Button::LEFT); let right = self.is_just_pressed(Button::RIGHT); @@ -158,6 +162,9 @@ impl ButtonController { } #[must_use] + /// Returns [Tri::Positive] if down was just pressed, [Tri::Negative] if up was just pressed and [Tri::Zero] if neither or both are just pressed. + /// + /// Also returns [Tri::Zero] after the call to [update()] if the button is still held. pub fn just_pressed_y_tri(&self) -> Tri { let up = self.is_just_pressed(Button::UP); let down = self.is_just_pressed(Button::DOWN); @@ -166,6 +173,7 @@ impl ButtonController { } #[must_use] + /// Returns a vector which represents the direction the button was just pressed in. pub fn just_pressed_vector(&self) -> Vector2D where T: From + crate::fixnum::FixedWidthUnsignedInteger, @@ -178,6 +186,7 @@ impl ButtonController { } #[must_use] + /// Returns `true` if the provided keys are all pressed, and `false` if not. pub fn is_pressed(&self, keys: Button) -> bool { let currently_pressed = u32::from(self.current); let keys = keys.bits(); From 3a24fca5b1e1a581cafbe47471028319c7a72042 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 21:40:02 +0100 Subject: [PATCH 08/11] Fix spelling mistakes in the controls section in the book --- book/src/pong/04_controls.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/pong/04_controls.md b/book/src/pong/04_controls.md index aecb5624..d62f2cd2 100644 --- a/book/src/pong/04_controls.md +++ b/book/src/pong/04_controls.md @@ -79,4 +79,4 @@ In the next step, we'll cover meta-sprites and actually add a bat to our game of # Exercise -Make it so the ball moves twice as fast if you're pressing the `A` button while moving it arond. \ No newline at end of file +Make it so the ball moves twice as fast if you're pressing the `A` button while moving it around. \ No newline at end of file From 9c99f25a567003a1f8bfbec4f06c74e68069c584 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Thu, 13 Oct 2022 21:40:32 +0100 Subject: [PATCH 09/11] Spell left correctly --- agb/src/input.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agb/src/input.rs b/agb/src/input.rs index c5c4f47e..9974df82 100644 --- a/agb/src/input.rs +++ b/agb/src/input.rs @@ -51,7 +51,7 @@ bitflags! { const START = 1 << 3; /// The RIGHT button on the D-Pad const RIGHT = 1 << 4; - /// The LFET button on the D-Pad + /// The LEFT button on the D-Pad const LEFT = 1 << 5; /// The UP button on the D-Pad const UP = 1 << 6; From e24ef69e0fcd59d8b3d1b48b1cc0f6f6b0fc1c89 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Mon, 31 Oct 2022 18:46:38 +0000 Subject: [PATCH 10/11] Should by y_tri --- book/src/pong/04_controls.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/pong/04_controls.md b/book/src/pong/04_controls.md index d62f2cd2..a324f5c7 100644 --- a/book/src/pong/04_controls.md +++ b/book/src/pong/04_controls.md @@ -39,7 +39,7 @@ loop { // x_tri and y_tri describe with -1, 0 and 1 which way the d-pad // buttons are being pressed x_velocity = input.x_tri() as i32; - y_velocity = input.y_try() as i32; + y_velocity = input.y_tri() as i32; ball.set_x(ball_x as u16).set_y(ball_y as u16); From 6319fd3a20f1b39165af64c76890ac24c9cb6626 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Tue, 1 Nov 2022 22:02:51 +0000 Subject: [PATCH 11/11] Fix doc errors and warnings --- agb/src/display/tiled/infinite_scrolled_map.rs | 2 +- agb/src/input.rs | 4 ++-- agb/src/lib.rs | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/agb/src/display/tiled/infinite_scrolled_map.rs b/agb/src/display/tiled/infinite_scrolled_map.rs index ed30997d..2747f6d6 100644 --- a/agb/src/display/tiled/infinite_scrolled_map.rs +++ b/agb/src/display/tiled/infinite_scrolled_map.rs @@ -14,7 +14,7 @@ use crate::{ /// The abstraction allows only for static tiles, but it is possible to animate the tiles if needed. /// /// When you create a new infinite scrolled map, you need to provide a background which it will render itself -/// onto and a function which takes a Vector2D position and returns which tile should be rendered there. +/// onto and a function which takes a `Vector2D` position and returns which tile should be rendered there. /// /// The passed function should handle being out of bounds, as the scrolled map does buffer around the edges slightly. /// diff --git a/agb/src/input.rs b/agb/src/input.rs index 9974df82..22b3e3dd 100644 --- a/agb/src/input.rs +++ b/agb/src/input.rs @@ -153,7 +153,7 @@ impl ButtonController { #[must_use] /// Returns [Tri::Positive] if left was just pressed, [Tri::Negative] if right was just pressed and [Tri::Zero] if neither or both are just pressed. /// - /// Also returns [Tri::Zero] after the call to [update()] if the button is still held. + /// Also returns [Tri::Zero] after the call to [`update()`](ButtonController::update()) if the button is still held. pub fn just_pressed_x_tri(&self) -> Tri { let left = self.is_just_pressed(Button::LEFT); let right = self.is_just_pressed(Button::RIGHT); @@ -164,7 +164,7 @@ impl ButtonController { #[must_use] /// Returns [Tri::Positive] if down was just pressed, [Tri::Negative] if up was just pressed and [Tri::Zero] if neither or both are just pressed. /// - /// Also returns [Tri::Zero] after the call to [update()] if the button is still held. + /// Also returns [Tri::Zero] after the call to [`update()`](ButtonController::update()) if the button is still held. pub fn just_pressed_y_tri(&self) -> Tri { let up = self.is_just_pressed(Button::UP); let down = self.is_just_pressed(Button::DOWN); diff --git a/agb/src/lib.rs b/agb/src/lib.rs index 1c0c587a..195edf9a 100644 --- a/agb/src/lib.rs +++ b/agb/src/lib.rs @@ -24,6 +24,7 @@ #![deny(clippy::cloned_instead_of_copied)] #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)] +#![deny(rustdoc::invalid_html_tags)] //! # agb //! `agb` is a library for making games on the Game Boy Advance using the Rust