Added R key to reset game (#350)

* Added R key to reset game

* Invaders, Shield, Player module processing

* Improve the processing of Shield and Player modules
This commit is contained in:
imizao 2023-03-27 14:59:20 +08:00 committed by GitHub
parent 3d8c7bd0c9
commit d85091847a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 118 additions and 52 deletions

View file

@ -18,6 +18,10 @@ cargo run --release --package invaders
<kbd>Pause</kbd> <kbd>P</kbd>: Pause <kbd>Pause</kbd> <kbd>P</kbd>: Pause
<kbd>R</kbd>: Reset Game
<kbd>escape</kbd>: Quit
## GamePad Controls ## GamePad Controls
`D-Pad 🡰` `D-Pad 🡲`: Move tank `D-Pad 🡰` `D-Pad 🡲`: Move tank

View file

@ -15,7 +15,9 @@ use crate::collision::Collision;
pub use crate::controls::{Controls, Direction}; pub use crate::controls::{Controls, Direction};
use crate::geo::Point; use crate::geo::Point;
use crate::loader::{load_assets, Assets}; use crate::loader::{load_assets, Assets};
use crate::sprites::{blit, Animation, Drawable, Frame, Sprite, SpriteRef}; use crate::player::Player;
use crate::shield::Shield;
use crate::sprites::{blit, Animation, Drawable, Frame, SpriteRef};
use core::time::Duration; use core::time::Duration;
use randomize::PCG32; use randomize::PCG32;
@ -24,6 +26,8 @@ mod controls;
mod debug; mod debug;
mod geo; mod geo;
mod loader; mod loader;
mod player;
mod shield;
mod sprites; mod sprites;
/// The screen width is constant (units are in pixels) /// The screen width is constant (units are in pixels)
@ -96,22 +100,6 @@ struct Bounds {
bottom_row: usize, bottom_row: usize,
} }
/// The player entity.
#[derive(Debug)]
struct Player {
sprite: SpriteRef,
pos: Point,
dt: Duration,
}
/// The shield entity.
#[derive(Debug)]
struct Shield {
// Shield sprite is not referenced because we want to deform it when it gets shot
sprite: Sprite,
pos: Point,
}
/// The laser entity. /// The laser entity.
#[derive(Debug)] #[derive(Debug)]
struct Laser { struct Laser {
@ -184,31 +172,16 @@ impl World {
/// let world = World::new(seed, false); /// let world = World::new(seed, false);
/// ``` /// ```
pub fn new(seed: (u64, u64), debug: bool) -> World { pub fn new(seed: (u64, u64), debug: bool) -> World {
use Frame::*;
// Load assets first // Load assets first
let assets = load_assets(); let assets = load_assets();
// TODO: Create invaders one-at-a-time // TODO: Create invaders one-at-a-time
let invaders = Invaders { let invaders = Invaders::new(&assets);
grid: make_invader_grid(&assets),
stepper: Point::new(COLS - 1, 0),
direction: Direction::Right,
descend: false,
bounds: Bounds::default(),
};
let lasers = Vec::new(); let lasers = Vec::new();
let shields = (0..4) let shields = (0..4)
.map(|i| Shield { .map(|i| Shield::new(&assets, Point::new(i * 45 + 32, 192)))
sprite: Sprite::new(&assets, Shield1),
pos: Point::new(i * 45 + 32, 192),
})
.collect(); .collect();
let player = Player { let player = Player::new(&assets);
sprite: SpriteRef::new(&assets, Player1, Duration::from_millis(100)),
pos: PLAYER_START,
dt: Duration::default(),
};
let bullet = None; let bullet = None;
let collision = Collision::default(); let collision = Collision::default();
let _score = 0; let _score = 0;
@ -459,6 +432,34 @@ impl World {
}); });
} }
} }
pub fn reset_game(&mut self) {
// Recreate the alien
self.invaders = Invaders::new(&self.assets);
// Empty laser
self.lasers.clear();
// Recreate the shield
self.shields = (0..4)
.map(|i| Shield::new(&self.assets, Point::new(i * 45 + 32, 192)))
.collect();
// Reset player position
self.player.pos = PLAYER_START;
// Remove bullet
self.bullet = None;
// Reset collision state
self.collision.clear();
// Reset game score
self._score = 0;
// Set gameover to false
self.gameover = false;
}
} }
/// Create a default `World` with a static PRNG seed. /// Create a default `World` with a static PRNG seed.
@ -471,6 +472,22 @@ impl Default for World {
} }
impl Invaders { impl Invaders {
// New
pub fn new(assets: &Assets) -> Self {
let grid = make_invader_grid(assets);
let stepper = Point::new(COLS - 1, 0);
let direction = Direction::Right;
let descend = false;
let bounds = Bounds::default();
Invaders {
grid,
stepper,
direction,
descend,
bounds,
}
}
/// Compute the bounding box for the Invader fleet. /// Compute the bounding box for the Invader fleet.
/// ///
/// # Returns /// # Returns
@ -501,23 +518,15 @@ impl Invaders {
// Scan through the entire grid // Scan through the entire grid
for (y, row) in self.grid.iter().enumerate() { for (y, row) in self.grid.iter().enumerate() {
for (x, col) in row.iter().enumerate() { row.iter()
if col.is_some() { .enumerate()
// Build a boundary box of invaders in the grid .filter(|(_, col)| col.is_some())
if top > y { .for_each(|(x, _)| {
top = y; top = top.min(y);
} bottom = bottom.max(y);
if bottom < y { left = left.min(x);
bottom = y; right = right.max(x);
} });
if left > x {
left = x;
}
if right < x {
right = x;
}
}
}
} }
if top > bottom || left > right { if top > bottom || left > right {

View file

@ -0,0 +1,24 @@
use crate::geo::Point;
use crate::loader::Assets;
use crate::sprites::{Frame, SpriteRef};
use core::time::Duration;
// Player positioning
const PLAYER_START: Point = Point::new(80, 216);
/// The player entity.
#[derive(Debug)]
pub(crate) struct Player {
pub sprite: SpriteRef,
pub pos: Point,
pub dt: Duration,
}
impl Player {
pub fn new(assets: &Assets) -> Self {
let sprite = SpriteRef::new(assets, Frame::Player1, Duration::from_millis(100));
let pos = PLAYER_START;
let dt = Duration::default();
Player { sprite, pos, dt }
}
}

View file

@ -0,0 +1,20 @@
use crate::geo::Point;
use crate::loader::Assets;
use crate::sprites::{Frame, Sprite};
/// The shield entity.
#[derive(Debug)]
pub(crate) struct Shield {
// Shield sprite is not referenced because we want to deform it when it gets shot
pub sprite: Sprite,
pub pos: Point,
}
impl Shield {
// New
pub fn new(assets: &Assets, pos: Point) -> Self {
let sprite = Sprite::new(assets, Frame::Shield1);
Shield { sprite, pos }
}
}

View file

@ -95,6 +95,10 @@ impl Game {
Controls { direction, fire } Controls { direction, fire }
}; };
} }
fn reset_game(&mut self) {
self.world.reset_game();
}
} }
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
@ -165,6 +169,11 @@ fn main() -> Result<(), Error> {
return; return;
} }
// Reset game
if g.game.input.key_pressed(VirtualKeyCode::R) {
g.game.reset_game();
}
// Resize the window // Resize the window
if let Some(size) = g.game.input.window_resized() { if let Some(size) = g.game.input.window_resized() {
if let Err(err) = g.game.pixels.resize_surface(size.width, size.height) { if let Err(err) = g.game.pixels.resize_surface(size.width, size.height) {