Add delta time steps and a placeholder for control inputs
This commit is contained in:
parent
960bfb9b3f
commit
348533ee9a
|
@ -1,5 +1,7 @@
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use pixels::{Error, Pixels, SurfaceTexture};
|
use pixels::{Error, Pixels, SurfaceTexture};
|
||||||
use simple_invaders::{World, SCREEN_HEIGHT, SCREEN_WIDTH};
|
use simple_invaders::{Controls, Direction, World, SCREEN_HEIGHT, SCREEN_WIDTH};
|
||||||
use winit::event;
|
use winit::event;
|
||||||
use winit::event_loop::{ControlFlow, EventLoop};
|
use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
|
|
||||||
|
@ -26,6 +28,7 @@ fn main() -> Result<(), Error> {
|
||||||
let surface_texture = SurfaceTexture::new(width, height, &surface);
|
let surface_texture = SurfaceTexture::new(width, height, &surface);
|
||||||
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();
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -43,7 +46,18 @@ fn main() -> Result<(), Error> {
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
event::Event::EventsCleared => {
|
event::Event::EventsCleared => {
|
||||||
invaders.update();
|
// Get a new delta time.
|
||||||
|
let now = Instant::now();
|
||||||
|
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);
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
17
simple-invaders/src/controls.rs
Normal file
17
simple-invaders/src/controls.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
/// Player control inputs.
|
||||||
|
pub struct Controls {
|
||||||
|
/// Move the player.
|
||||||
|
pub direction: Direction,
|
||||||
|
/// Shoot the cannon.
|
||||||
|
pub fire: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The player can only move left or right, but can also be stationary.
|
||||||
|
pub enum Direction {
|
||||||
|
/// Do not move the player.
|
||||||
|
Still,
|
||||||
|
/// Move to the left.
|
||||||
|
Left,
|
||||||
|
/// Move to the right.
|
||||||
|
Right,
|
||||||
|
}
|
|
@ -1,9 +1,19 @@
|
||||||
mod loader;
|
//! A simple Space Invaders clone to demonstrate `pixels`.
|
||||||
mod sprites;
|
//!
|
||||||
|
//! This doesn't use anything fancy like a game engine, so you may not want to build a game like
|
||||||
|
//! this in practice. That said, the game is fully functional, and it should not be too difficult
|
||||||
|
//! to understand the code.
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub use controls::{Controls, Direction};
|
||||||
use loader::{load_assets, Assets};
|
use loader::{load_assets, Assets};
|
||||||
use sprites::{blit, Sprite, SpriteRef, Sprites};
|
use sprites::{blit, Sprite, SpriteRef, Sprites};
|
||||||
|
|
||||||
|
mod controls;
|
||||||
|
mod loader;
|
||||||
|
mod sprites;
|
||||||
|
|
||||||
/// The screen width is constant (units are in pixels)
|
/// The screen width is constant (units are in pixels)
|
||||||
pub const SCREEN_WIDTH: usize = 224;
|
pub const SCREEN_WIDTH: usize = 224;
|
||||||
/// The screen height is constant (units are in pixels)
|
/// The screen height is constant (units are in pixels)
|
||||||
|
@ -25,6 +35,7 @@ pub struct World {
|
||||||
score: u32,
|
score: u32,
|
||||||
assets: Assets,
|
assets: Assets,
|
||||||
screen: Vec<u8>,
|
screen: Vec<u8>,
|
||||||
|
timing: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A tiny position vector
|
/// A tiny position vector
|
||||||
|
@ -132,11 +143,47 @@ impl World {
|
||||||
score: 0,
|
score: 0,
|
||||||
assets,
|
assets,
|
||||||
screen,
|
screen,
|
||||||
|
timing: Duration::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the internal state.
|
/// Update the internal state.
|
||||||
pub fn update(&mut self) {
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `dt`: The time delta since last update.
|
||||||
|
/// * `controls`: The player inputs.
|
||||||
|
pub fn update(&mut self, dt: Duration, controls: Controls) {
|
||||||
|
let one_frame = Duration::from_secs_f64(1.0 / 60.0);
|
||||||
|
|
||||||
|
// Advance the timer by the delta time
|
||||||
|
self.timing += dt;
|
||||||
|
|
||||||
|
// Step the game logic by one frame at a time
|
||||||
|
while self.timing >= one_frame {
|
||||||
|
self.timing -= one_frame;
|
||||||
|
self.step(&controls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw the internal state to the screen.
|
||||||
|
pub fn draw(&mut self) -> &[u8] {
|
||||||
|
// Clear the screen
|
||||||
|
self.clear();
|
||||||
|
|
||||||
|
// Draw the invaders
|
||||||
|
for row in &self.invaders.grid {
|
||||||
|
for col in row {
|
||||||
|
if let Some(invader) = col {
|
||||||
|
blit(&mut self.screen, &invader.pos, &invader.sprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&self.screen
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step(&mut self, _controls: &Controls) {
|
||||||
// Find the next invader
|
// Find the next invader
|
||||||
let mut invader = None;
|
let mut invader = None;
|
||||||
while let None = invader {
|
while let None = invader {
|
||||||
|
@ -159,23 +206,6 @@ impl World {
|
||||||
invader.sprite.update_frame(frame);
|
invader.sprite.update_frame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the internal state to the screen.
|
|
||||||
pub fn draw(&mut self) -> &[u8] {
|
|
||||||
// Clear the screen
|
|
||||||
self.clear();
|
|
||||||
|
|
||||||
// Draw the invaders
|
|
||||||
for row in &self.invaders.grid {
|
|
||||||
for col in row {
|
|
||||||
if let Some(invader) = col {
|
|
||||||
blit(&mut self.screen, &invader.pos, &invader.sprite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&self.screen
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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() {
|
||||||
|
|
Loading…
Reference in a new issue