-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
264 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
newline_style = "Unix" | ||
# The "Default" setting has a heuristic which splits lines too aggresively. | ||
use_small_heuristics = "Max" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use sdl2::rect::{Point, Rect}; | ||
use specs::prelude::*; | ||
use specs_derive::Component; | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
pub enum Direction { | ||
Up, | ||
Down, | ||
Left, | ||
Right, | ||
} | ||
|
||
#[derive(Component, Debug, Default)] | ||
#[storage(NullStorage)] | ||
pub struct KeyboardControlled; | ||
|
||
#[derive(Component, Debug)] | ||
#[storage(VecStorage)] | ||
pub struct Position(pub Point); | ||
|
||
#[derive(Component, Debug)] | ||
#[storage(VecStorage)] | ||
pub struct Velocity { | ||
pub speed: i32, | ||
pub direction: Direction, | ||
} | ||
|
||
#[derive(Component, Debug)] | ||
#[storage(VecStorage)] | ||
pub struct Sprite { | ||
pub spritesheet: usize, | ||
pub region: Rect, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
use specs::prelude::*; | ||
|
||
use crate::components::*; | ||
|
||
use super::MovementCommand; | ||
|
||
const PLAYER_MOVEMENT_SPEED: i32 = 20; | ||
|
||
pub struct Keyboard; | ||
|
||
impl<'a> System<'a> for Keyboard { | ||
type SystemData = ( | ||
ReadExpect<'a, Option<MovementCommand>>, | ||
ReadStorage<'a, KeyboardControlled>, | ||
WriteStorage<'a, Velocity>, | ||
); | ||
|
||
fn run(&mut self, mut data: Self::SystemData) { | ||
let movement_command = match &*data.0 { | ||
Some(movement_command) => movement_command, | ||
None => return, // no change | ||
}; | ||
|
||
for (_, vel) in (&data.1, &mut data.2).join() { | ||
match movement_command { | ||
&MovementCommand::Move(direction) => { | ||
vel.speed = PLAYER_MOVEMENT_SPEED; | ||
vel.direction = direction; | ||
} | ||
MovementCommand::Stop => vel.speed = 0, | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,123 @@ | ||
fn main() { | ||
println!("Hello, world!"); | ||
mod components; | ||
mod keyboard; | ||
mod physics; | ||
mod renderer; | ||
|
||
use clap::{crate_description, crate_name, crate_version, App}; | ||
|
||
use sdl2::event::Event; | ||
use sdl2::image::{self, InitFlag, LoadTexture}; | ||
use sdl2::keyboard::Keycode; | ||
use sdl2::pixels::Color; | ||
use sdl2::rect::{Point, Rect}; | ||
use specs::prelude::*; | ||
use std::time::Duration; | ||
|
||
use crate::components::*; | ||
|
||
pub enum MovementCommand { | ||
Stop, | ||
Move(Direction), | ||
} | ||
|
||
fn main() -> Result<(), String> { | ||
App::new(crate_name!()).version(crate_version!()).about(crate_description!()); | ||
|
||
let sdl_context = sdl2::init()?; | ||
let video_subsystem = sdl_context.video()?; | ||
let _image_context = image::init(InitFlag::PNG)?; | ||
let window = video_subsystem | ||
.window("game tutorial", 800, 600) | ||
.position_centered() | ||
.build() | ||
.expect("could not initialize video subsystem"); | ||
|
||
let mut canvas = window.into_canvas().build().expect("could not make a canvas"); | ||
|
||
let texture_creator = canvas.texture_creator(); | ||
|
||
let mut dispatcher = DispatcherBuilder::new() | ||
.with(keyboard::Keyboard, "Keyboard", &[]) | ||
.with(physics::Physics, "Physics", &["Keyboard"]) | ||
.build(); | ||
|
||
let mut world = World::new(); | ||
dispatcher.setup(&mut world); | ||
renderer::SystemData::setup(&mut world); | ||
|
||
let movement_command: Option<MovementCommand> = None; | ||
world.insert(movement_command); | ||
|
||
let textures = [texture_creator.load_texture("assets/neko.png")?]; | ||
|
||
let spritesheet = 0; | ||
let player_top_left_frame = Rect::new(0, 0, 45, 45); | ||
let (frame_width, frame_height) = player_top_left_frame.size(); | ||
|
||
let sprite = Sprite { | ||
spritesheet, | ||
region: Rect::new( | ||
player_top_left_frame.x(), | ||
player_top_left_frame.y(), | ||
frame_width, | ||
frame_height, | ||
), | ||
}; | ||
|
||
world | ||
.create_entity() | ||
.with(KeyboardControlled) | ||
.with(Position(Point::new(0, 0))) | ||
.with(Velocity { speed: 0, direction: Direction::Right }) | ||
.with(sprite) | ||
.build(); | ||
|
||
let mut event_pump = sdl_context.event_pump()?; | ||
let mut i = 0; | ||
'running: loop { | ||
let mut movement_command = None; | ||
|
||
// Handle events | ||
for event in event_pump.poll_iter() { | ||
match event { | ||
Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { | ||
break 'running; | ||
} | ||
Event::KeyDown { keycode: Some(Keycode::Left), repeat: false, .. } => { | ||
movement_command = Some(MovementCommand::Move(Direction::Left)); | ||
} | ||
Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => { | ||
movement_command = Some(MovementCommand::Move(Direction::Right)); | ||
} | ||
Event::KeyDown { keycode: Some(Keycode::Up), repeat: false, .. } => { | ||
movement_command = Some(MovementCommand::Move(Direction::Up)); | ||
} | ||
Event::KeyDown { keycode: Some(Keycode::Down), repeat: false, .. } => { | ||
movement_command = Some(MovementCommand::Move(Direction::Down)); | ||
} | ||
Event::KeyUp { keycode: Some(Keycode::Left), repeat: false, .. } | ||
| Event::KeyUp { keycode: Some(Keycode::Right), repeat: false, .. } | ||
| Event::KeyUp { keycode: Some(Keycode::Up), repeat: false, .. } | ||
| Event::KeyUp { keycode: Some(Keycode::Down), repeat: false, .. } => { | ||
movement_command = Some(MovementCommand::Stop); | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
*world.write_resource() = movement_command; | ||
|
||
// Update | ||
i = (i + 1) % 255; | ||
dispatcher.dispatch(&mut world); | ||
world.maintain(); | ||
|
||
// Render | ||
renderer::render(&mut canvas, Color::RGB(i, 64, 255 - i), &textures, world.system_data())?; | ||
|
||
// Time management! | ||
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 20)); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
use specs::prelude::*; | ||
|
||
use crate::components::*; | ||
|
||
pub struct Physics; | ||
|
||
impl<'a> System<'a> for Physics { | ||
type SystemData = (WriteStorage<'a, Position>, ReadStorage<'a, Velocity>); | ||
|
||
fn run(&mut self, mut data: Self::SystemData) { | ||
use self::Direction::*; | ||
for (pos, vel) in (&mut data.0, &data.1).join() { | ||
match vel.direction { | ||
Left => { | ||
pos.0 = pos.0.offset(-vel.speed, 0); | ||
} | ||
Right => { | ||
pos.0 = pos.0.offset(vel.speed, 0); | ||
} | ||
Up => { | ||
pos.0 = pos.0.offset(0, -vel.speed); | ||
} | ||
Down => { | ||
pos.0 = pos.0.offset(0, vel.speed); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
use sdl2::pixels::Color; | ||
use sdl2::rect::{Point, Rect}; | ||
use sdl2::render::{Texture, WindowCanvas}; | ||
use specs::prelude::*; | ||
|
||
use crate::components::*; | ||
|
||
// Type alias for the data needed by the renderer | ||
pub type SystemData<'a> = (ReadStorage<'a, Position>, ReadStorage<'a, Sprite>); | ||
|
||
pub fn render( | ||
canvas: &mut WindowCanvas, | ||
background: Color, | ||
textures: &[Texture], | ||
data: SystemData, | ||
) -> Result<(), String> { | ||
canvas.set_draw_color(background); | ||
canvas.clear(); | ||
|
||
let (width, height) = canvas.output_size()?; | ||
|
||
for (pos, sprite) in (&data.0, &data.1).join() { | ||
let current_frame = sprite.region; | ||
|
||
// Treat the center of the screen as the (0, 0) coordinate | ||
let screen_position = pos.0 + Point::new(width as i32 / 2, height as i32 / 2); | ||
let screen_rect = | ||
Rect::from_center(screen_position, current_frame.width(), current_frame.height()); | ||
canvas.copy(&textures[sprite.spritesheet], current_frame, screen_rect)?; | ||
} | ||
|
||
canvas.present(); | ||
|
||
Ok(()) | ||
} |