Add player controls and shields (#4)

This commit is contained in:
Jay Oster 2019-10-08 00:35:53 -07:00 committed by GitHub
parent d7fc1eca3c
commit d0a16f9a71
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 102 additions and 10 deletions

View file

@ -29,9 +29,11 @@ fn main() -> Result<(), Error> {
let mut fb = Pixels::new(224, 256, surface_texture)?;
let mut invaders = World::new();
let mut last = Instant::now();
let mut controls = Controls::default();
event_loop.run(move |event, _, control_flow| match event {
event::Event::WindowEvent { event, .. } => match event {
// Close events
event::WindowEvent::KeyboardInput {
input:
event::KeyboardInput {
@ -42,7 +44,41 @@ fn main() -> Result<(), Error> {
..
}
| event::WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
// Keyboard controls
event::WindowEvent::KeyboardInput {
input:
event::KeyboardInput {
virtual_keycode: Some(virtual_code),
state: event::ElementState::Pressed,
..
},
..
} => match virtual_code {
event::VirtualKeyCode::Left => controls.direction = Direction::Left,
event::VirtualKeyCode::Right => controls.direction = Direction::Right,
event::VirtualKeyCode::Space => controls.fire = true,
_ => (),
},
event::WindowEvent::KeyboardInput {
input:
event::KeyboardInput {
virtual_keycode: Some(virtual_code),
state: event::ElementState::Released,
..
},
..
} => match virtual_code {
event::VirtualKeyCode::Left => controls.direction = Direction::Still,
event::VirtualKeyCode::Right => controls.direction = Direction::Still,
event::VirtualKeyCode::Space => controls.fire = false,
_ => (),
},
// Redraw the screen
event::WindowEvent::RedrawRequested => fb.render(invaders.draw()),
_ => (),
},
event::Event::EventsCleared => {
@ -51,13 +87,8 @@ fn main() -> Result<(), Error> {
let dt = now.duration_since(last);
last = now;
// TODO: Keyboard and controller input.
let controls = Controls {
direction: Direction::Still,
fire: false,
};
invaders.update(dt, controls);
// Update the game logic and request redraw
invaders.update(dt, &controls);
window.request_redraw();
}
_ => (),

View file

@ -1,4 +1,5 @@
/// Player control inputs.
#[derive(Debug)]
pub struct Controls {
/// Move the player.
pub direction: Direction,
@ -7,6 +8,7 @@ pub struct Controls {
}
/// The player can only move left or right, but can also be stationary.
#[derive(Debug)]
pub enum Direction {
/// Do not move the player.
Still,
@ -15,3 +17,18 @@ pub enum Direction {
/// Move to the right.
Right,
}
impl Default for Controls {
fn default() -> Controls {
Controls {
direction: Direction::default(),
fire: false,
}
}
}
impl Default for Direction {
fn default() -> Direction {
Direction::Still
}
}

View file

@ -36,6 +36,7 @@ pub struct World {
assets: Assets,
screen: Vec<u8>,
timing: Duration,
frame_count: usize,
}
/// A tiny position vector
@ -84,6 +85,7 @@ struct Bounds {
struct Player {
sprite: SpriteRef,
pos: Point,
last_update: usize,
}
/// The shield entity.
@ -124,6 +126,7 @@ impl World {
let player = Player {
sprite: SpriteRef::new(&assets, Player1),
pos: Point::new(80, 216),
last_update: 0,
};
let shields = (0..4)
.map(|i| Shield {
@ -146,6 +149,7 @@ impl World {
assets,
screen,
timing: Duration::default(),
frame_count: 0,
}
}
@ -155,7 +159,7 @@ impl World {
///
/// * `dt`: The time delta since last update.
/// * `controls`: The player inputs.
pub fn update(&mut self, dt: Duration, _controls: Controls) {
pub fn update(&mut self, dt: Duration, controls: &Controls) {
let one_frame = Duration::new(0, 16_666_667);
// Advance the timer by the delta time
@ -163,11 +167,14 @@ impl World {
// Step the invaders one by one
while self.timing >= one_frame {
self.frame_count += 1;
self.timing -= one_frame;
self.step_invaders();
}
// TODO: Handle controls to move the player
// Handle player movement and animation
self.step_player(controls);
// TODO: Handle lasers and bullets
// Movements can be multiplied by the delta-time frame count, instead of looping
}
@ -186,6 +193,14 @@ impl World {
}
}
// Draw the shields
for shield in &self.shields {
blit(&mut self.screen, &shield.pos, &shield.sprite);
}
// Draw the player
blit(&mut self.screen, &self.player.pos, &self.player.sprite);
&self.screen
}
@ -204,6 +219,34 @@ impl World {
invader.sprite.animate(&self.assets);
}
fn step_player(&mut self, controls: &Controls) {
let animate_player = match controls.direction {
Direction::Left => {
if self.player.pos.x > 0 {
self.player.pos.x -= 1;
true
} else {
false
}
}
Direction::Right => {
if self.player.pos.x < 224 - 16 {
self.player.pos.x += 1;
true
} else {
false
}
}
_ => false,
};
if animate_player && self.frame_count - self.player.last_update >= 3 {
self.player.last_update = self.frame_count;
self.player.sprite.animate(&self.assets);
}
}
/// Clear the screen
fn clear(&mut self) {
for (i, byte) in self.screen.iter_mut().enumerate() {
@ -281,6 +324,7 @@ fn make_invader_grid(assets: &Assets) -> Vec<Vec<Option<Invader>>> {
const BLIPJOY_OFFSET: Point = Point::new(3, 4);
const FERRIS_OFFSET: Point = Point::new(3, 5);
const CTHULHU_OFFSET: Point = Point::new(1, 3);
(0..1)
.map(|y| {
@ -310,7 +354,7 @@ fn make_invader_grid(assets: &Assets) -> Vec<Vec<Option<Invader>>> {
.map(|x| {
Some(Invader {
sprite: SpriteRef::new(assets, Cthulhu1),
pos: START + BLIPJOY_OFFSET + Point::new(x, y) * GRID,
pos: START + CTHULHU_OFFSET + Point::new(x, y) * GRID,
score: 10,
})
})