Add player controls and shields (#4)
This commit is contained in:
parent
d7fc1eca3c
commit
d0a16f9a71
|
@ -29,9 +29,11 @@ fn main() -> Result<(), Error> {
|
||||||
let mut fb = Pixels::new(224, 256, surface_texture)?;
|
let mut fb = Pixels::new(224, 256, surface_texture)?;
|
||||||
let mut invaders = World::new();
|
let mut invaders = World::new();
|
||||||
let mut last = Instant::now();
|
let mut last = Instant::now();
|
||||||
|
let mut controls = Controls::default();
|
||||||
|
|
||||||
event_loop.run(move |event, _, control_flow| match event {
|
event_loop.run(move |event, _, control_flow| match event {
|
||||||
event::Event::WindowEvent { event, .. } => match event {
|
event::Event::WindowEvent { event, .. } => match event {
|
||||||
|
// Close events
|
||||||
event::WindowEvent::KeyboardInput {
|
event::WindowEvent::KeyboardInput {
|
||||||
input:
|
input:
|
||||||
event::KeyboardInput {
|
event::KeyboardInput {
|
||||||
|
@ -42,7 +44,41 @@ fn main() -> Result<(), Error> {
|
||||||
..
|
..
|
||||||
}
|
}
|
||||||
| event::WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
| 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::WindowEvent::RedrawRequested => fb.render(invaders.draw()),
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
event::Event::EventsCleared => {
|
event::Event::EventsCleared => {
|
||||||
|
@ -51,13 +87,8 @@ fn main() -> Result<(), Error> {
|
||||||
let dt = now.duration_since(last);
|
let dt = now.duration_since(last);
|
||||||
last = now;
|
last = now;
|
||||||
|
|
||||||
// TODO: Keyboard and controller input.
|
// Update the game logic and request redraw
|
||||||
let controls = Controls {
|
invaders.update(dt, &controls);
|
||||||
direction: Direction::Still,
|
|
||||||
fire: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
invaders.update(dt, controls);
|
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/// Player control inputs.
|
/// Player control inputs.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Controls {
|
pub struct Controls {
|
||||||
/// Move the player.
|
/// Move the player.
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
|
@ -7,6 +8,7 @@ pub struct Controls {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The player can only move left or right, but can also be stationary.
|
/// The player can only move left or right, but can also be stationary.
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
/// Do not move the player.
|
/// Do not move the player.
|
||||||
Still,
|
Still,
|
||||||
|
@ -15,3 +17,18 @@ pub enum Direction {
|
||||||
/// Move to the right.
|
/// Move to the right.
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Controls {
|
||||||
|
fn default() -> Controls {
|
||||||
|
Controls {
|
||||||
|
direction: Direction::default(),
|
||||||
|
fire: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Direction {
|
||||||
|
fn default() -> Direction {
|
||||||
|
Direction::Still
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ pub struct World {
|
||||||
assets: Assets,
|
assets: Assets,
|
||||||
screen: Vec<u8>,
|
screen: Vec<u8>,
|
||||||
timing: Duration,
|
timing: Duration,
|
||||||
|
frame_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A tiny position vector
|
/// A tiny position vector
|
||||||
|
@ -84,6 +85,7 @@ struct Bounds {
|
||||||
struct Player {
|
struct Player {
|
||||||
sprite: SpriteRef,
|
sprite: SpriteRef,
|
||||||
pos: Point,
|
pos: Point,
|
||||||
|
last_update: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The shield entity.
|
/// The shield entity.
|
||||||
|
@ -124,6 +126,7 @@ impl World {
|
||||||
let player = Player {
|
let player = Player {
|
||||||
sprite: SpriteRef::new(&assets, Player1),
|
sprite: SpriteRef::new(&assets, Player1),
|
||||||
pos: Point::new(80, 216),
|
pos: Point::new(80, 216),
|
||||||
|
last_update: 0,
|
||||||
};
|
};
|
||||||
let shields = (0..4)
|
let shields = (0..4)
|
||||||
.map(|i| Shield {
|
.map(|i| Shield {
|
||||||
|
@ -146,6 +149,7 @@ impl World {
|
||||||
assets,
|
assets,
|
||||||
screen,
|
screen,
|
||||||
timing: Duration::default(),
|
timing: Duration::default(),
|
||||||
|
frame_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +159,7 @@ impl World {
|
||||||
///
|
///
|
||||||
/// * `dt`: The time delta since last update.
|
/// * `dt`: The time delta since last update.
|
||||||
/// * `controls`: The player inputs.
|
/// * `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);
|
let one_frame = Duration::new(0, 16_666_667);
|
||||||
|
|
||||||
// Advance the timer by the delta time
|
// Advance the timer by the delta time
|
||||||
|
@ -163,11 +167,14 @@ impl World {
|
||||||
|
|
||||||
// Step the invaders one by one
|
// Step the invaders one by one
|
||||||
while self.timing >= one_frame {
|
while self.timing >= one_frame {
|
||||||
|
self.frame_count += 1;
|
||||||
self.timing -= one_frame;
|
self.timing -= one_frame;
|
||||||
self.step_invaders();
|
self.step_invaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle controls to move the player
|
// Handle player movement and animation
|
||||||
|
self.step_player(controls);
|
||||||
|
|
||||||
// TODO: Handle lasers and bullets
|
// TODO: Handle lasers and bullets
|
||||||
// Movements can be multiplied by the delta-time frame count, instead of looping
|
// 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
|
&self.screen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +219,34 @@ impl World {
|
||||||
invader.sprite.animate(&self.assets);
|
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
|
/// Clear the screen
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
for (i, byte) in self.screen.iter_mut().enumerate() {
|
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 BLIPJOY_OFFSET: Point = Point::new(3, 4);
|
||||||
const FERRIS_OFFSET: Point = Point::new(3, 5);
|
const FERRIS_OFFSET: Point = Point::new(3, 5);
|
||||||
|
const CTHULHU_OFFSET: Point = Point::new(1, 3);
|
||||||
|
|
||||||
(0..1)
|
(0..1)
|
||||||
.map(|y| {
|
.map(|y| {
|
||||||
|
@ -310,7 +354,7 @@ fn make_invader_grid(assets: &Assets) -> Vec<Vec<Option<Invader>>> {
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
Some(Invader {
|
Some(Invader {
|
||||||
sprite: SpriteRef::new(assets, Cthulhu1),
|
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,
|
score: 10,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue