From b0566120fd4a404355b6e6e1d75b472bbe3f57fe Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tomas=20Wenstr=C3=B6m?= Date: Tue, 12 Jan 2021 18:40:31 +0100 Subject: [PATCH] Added a basic gamestate with a controlled mario --- src/common.rs | 13 +++- src/core/app.rs | 48 +++++++-------- src/core/controller.rs | 30 ++++++--- src/core/game.rs | 164 +++++++++++++++++++++++++++++++++++++++++++++++++ src/core/mod.rs | 1 + src/main.rs | 4 +- 6 files changed, 225 insertions(+), 35 deletions(-) create mode 100644 src/core/game.rs diff --git a/src/common.rs b/src/common.rs index 442b11c..52b7324 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,5 +1,7 @@ use std::ops::{Add, AddAssign, Mul}; +pub type Nanoseconds = u64; + #[macro_export] macro_rules! point { ( $x:expr, $y:expr ) => { @@ -7,7 +9,7 @@ macro_rules! point { }; } -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Default, Copy, Clone, PartialEq)] pub struct Point2D { pub x: T, pub y: T, @@ -37,6 +39,15 @@ impl AddAssign for Point2D { } } +impl From<(T, T)> for Point2D { + fn from(item: (T, T)) -> Self { + Point2D { + x: item.0, + y: item.1, + } + } +} + #[macro_export] macro_rules! rect { ( $x:expr, $y:expr ) => { diff --git a/src/core/app.rs b/src/core/app.rs index 8c07417..62d7507 100644 --- a/src/core/app.rs +++ b/src/core/app.rs @@ -1,5 +1,5 @@ use boll::*; -use common::{Point2D, Rect}; +use common::{Nanoseconds, Point2D, Rect}; use core::controller::ControllerManager; use point; // defined in common, but loaded from main... use rand::Rng; @@ -15,8 +15,6 @@ use sprites::SpriteManager; use std::f32::consts::PI; use time::PreciseTime; -pub type Nanoseconds = u64; - const FPS: u32 = 60; const NS_PER_FRAME: u32 = 1_000_000_000 / FPS; @@ -47,7 +45,7 @@ impl AppBuilder { let context = sdl2::init().unwrap(); sdl2::image::init(sdl2::image::InitFlag::PNG)?; let video = context.video()?; - self.print_video_display_modes(&video); + //self.print_video_display_modes(&video); let window = video .window( @@ -86,6 +84,7 @@ impl AppBuilder { }) } + #[allow(dead_code)] fn print_video_display_modes(&self, video: &VideoSubsystem) { println!("video subsystem: {:?}", video); println!("current_video_driver: {:?}", video.current_video_driver()); @@ -131,7 +130,7 @@ pub struct App { event_pump: EventPump, sprites: SpriteManager, state: Box, - ctrl_man: ControllerManager, + pub ctrl_man: ControllerManager, } impl App { @@ -147,10 +146,12 @@ impl App { } pub fn start(&mut self) { - let mut frame_count: u64 = 0; - let mut fps_time = PreciseTime::now(); + // let mut frame_count: u64 = 0; + // let mut fps_time = PreciseTime::now(); let mut last_time = PreciseTime::now(); + self.state.enter(&mut self.ctrl_man); + 'running: loop { if let Err(_) = self.handle_events() { break 'running; @@ -163,14 +164,14 @@ impl App { self.render(); - frame_count += 1; - if frame_count == FPS as u64 { - let duration = fps_time.to(PreciseTime::now()).num_nanoseconds().unwrap() as f64 - / 1_000_000_000.0; - // println!("fps: {}", frame_count as f64 / duration); - frame_count = 0; - fps_time = PreciseTime::now(); - } + // frame_count += 1; + // if frame_count == FPS as u64 { + // let duration = fps_time.to(PreciseTime::now()).num_nanoseconds().unwrap() as f64 + // / 1_000_000_000.0; + // // println!("fps: {}", frame_count as f64 / duration); + // frame_count = 0; + // fps_time = PreciseTime::now(); + // } } self.state.leave(); @@ -180,10 +181,6 @@ impl App { for event in self.event_pump.poll_iter() { self.ctrl_man.handle_event(&event); match event { - Event::ControllerButtonDown { .. } => { - let c = self.ctrl_man.controllers[0].clone(); - c.borrow().rumble(1.0, 300); - } Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), @@ -246,7 +243,7 @@ impl App { } => { println!("window focus lost") } - _ => self.state.on_event(event), + _ => self.state.handle_event(event), } } Ok(()) @@ -261,10 +258,11 @@ impl App { } pub trait AppState { + fn enter(&mut self, ctrl_man: &mut ControllerManager); + fn leave(&mut self); fn update(&mut self, dt: Nanoseconds); fn render(&mut self, canvas: &mut Canvas, sprites: &mut SpriteManager); - fn leave(&self); - fn on_event(&mut self, event: Event); + fn handle_event(&mut self, event: Event); } type Bollar = Vec>; @@ -313,6 +311,8 @@ impl ActiveState { } impl AppState for ActiveState { + fn enter(&mut self, ctrl_man: &mut ControllerManager) {} + fn update(&mut self, dt: Nanoseconds) { for b in &mut self.bolls { b.update(); @@ -430,11 +430,11 @@ impl AppState for ActiveState { } } - fn leave(&self) { + fn leave(&mut self) { println!("number of bolls: {}", self.bolls.len()); } - fn on_event(&mut self, event: Event) { + fn handle_event(&mut self, event: Event) { match event { Event::KeyDown { keycode: Some(Keycode::KpPlus), diff --git a/src/core/controller.rs b/src/core/controller.rs index f565070..fb56465 100644 --- a/src/core/controller.rs +++ b/src/core/controller.rs @@ -1,31 +1,39 @@ +use std::collections::HashMap; use std::cell::RefCell; use sdl2::haptic::Haptic; use sdl2::HapticSubsystem; -use sdl2::GameControllerSubsystem; +pub use sdl2::GameControllerSubsystem; use sdl2::event::Event; use sdl2::controller::GameController; use std::rc::Rc; //#[derive(Debug)] pub struct ControllerManager { - ctrl: GameControllerSubsystem, + pub ctrl: GameControllerSubsystem, haptic: Rc, - pub controllers: Vec>>, + pub controllers: HashMap>>, } //#[derive(Debug)] pub struct Controller { - id: u32, pub ctrl: GameController, haptic: Option>>, } impl ControllerManager { pub fn new(ctrl: GameControllerSubsystem, haptic: HapticSubsystem) -> Self { - ControllerManager { + let mut c = ControllerManager { ctrl, haptic: Rc::new(haptic), - controllers: vec![], + controllers: HashMap::new(), + }; + c.init(); + c + } + + fn init(&mut self) { + for i in 0..self.ctrl.num_joysticks().unwrap() { + self.add_device(i); } } @@ -56,7 +64,11 @@ impl ControllerManager { Err(_) => None }; - let detached = self.controllers.iter().find(|c| !c.borrow().ctrl.attached()); + if self.controllers.contains_key(&id) { + return; + } + + let detached = self.controllers.values().find(|c| !c.borrow().ctrl.attached()); match detached { Some(c) => { let mut c = c.borrow_mut(); @@ -64,8 +76,8 @@ impl ControllerManager { c.haptic = haptic.map(|h| Rc::new(RefCell::new(h))); } None => { - let c = Rc::new(RefCell::new(Controller {id, ctrl, haptic: haptic.map(|h| Rc::new(RefCell::new(h)))})); - self.controllers.push(c); + let c = Rc::new(RefCell::new(Controller {ctrl, haptic: haptic.map(|h| Rc::new(RefCell::new(h)))})); + self.controllers.insert(id, c); } }; } diff --git a/src/core/game.rs b/src/core/game.rs new file mode 100644 index 0000000..d9af79e --- /dev/null +++ b/src/core/game.rs @@ -0,0 +1,164 @@ +use sdl2::controller::{Axis, Button}; +use core::controller::ControllerManager; +use std::cell::RefCell; +use std::rc::Rc; +use core::controller::Controller; +use common::Point2D; +use sdl2::rect::Rect; +use common::Nanoseconds; +use sdl2::event::Event; +use sprites::SpriteManager; +use sdl2::render::Canvas; +use sdl2::video::Window; +use AppState; +use point; + +////////// GAMESTATE /////////////////////////////////////////////////////////// + +#[derive(Default)] +pub struct GameState { + world: World, +} + +impl GameState { + pub fn new() -> Self { + GameState { + world: World::new(), + } + } +} + +impl AppState for GameState { + fn enter(&mut self, ctrl_man: &mut ControllerManager) { + if let Some(ctrl) = ctrl_man.controllers.get(&0) { + self.world.add(Box::new(Character::new(ctrl.clone()))); + } + } + + fn leave(&mut self) {} + + fn update(&mut self, dt: Nanoseconds) { + self.world.update(dt); + } + + fn render(&mut self, canvas: &mut Canvas, sprites: &mut SpriteManager) { + self.world.render(canvas, sprites); + } + + fn handle_event(&mut self, _event: Event) {} +} + +////////// WORLD /////////////////////////////////////////////////////////////// + +#[derive(Default)] +pub struct World { + level: Level, + objects: Vec>, +} + +impl World { + pub fn new() -> Self { + World { + level: Level { + gravity: point!(0.0, 0.1), + ground: 600.0, + }, + ..Default::default() + } + } + + pub fn update(&mut self, dt: Nanoseconds) { + for o in &mut self.objects { + o.update(&self.level, dt); + } + } + + pub fn render(&mut self, canvas: &mut Canvas, sprites: &mut SpriteManager) { + self.level.render(canvas, sprites); + for o in &mut self.objects { + o.render(canvas, sprites); + } + } + + pub fn add(&mut self, object: Box) { + self.objects.push(object); + } +} + +////////// LEVEL /////////////////////////////////////////////////////////////// + +#[derive(Default)] +pub struct Level { + gravity: Point2D, + ground: f64, // just to have something +} + +impl Level { + pub fn render(&mut self, canvas: &mut Canvas, _sprites: &mut SpriteManager) { + let w = canvas.viewport().width() as i32; + for i in 1..11 { + let y = (i * i - 1) as i32 + self.ground as i32; + canvas.set_draw_color((255 - i * 20, 255 - i * 20, 0)); + canvas.draw_line((0, y), (w, y)).unwrap(); + } + } +} + +////////// OBJECT ////////////////////////////////////////////////////////////// + +pub trait Object { + fn update(&mut self, lvl: &Level, dt: Nanoseconds); + fn render(&mut self, canvas: &mut Canvas, _sprites: &mut SpriteManager); +} + +pub trait Physical {} +pub trait Drawable {} + +////////// CHARACTER /////////////////////////////////////////////////////////// + +pub struct Character { + ctrl: Rc>, + pos: Point2D, + vel: Point2D, +} + +impl Character { + pub fn new(ctrl: Rc>) -> Self { + Character { + ctrl, + pos: point!(100.0, 100.0), + vel: point!(0.0, 0.0), + } + } +} + +impl Object for Character { + fn update(&mut self, lvl: &Level, _dt: Nanoseconds) { + self.vel += lvl.gravity; + self.pos = self.pos + self.vel; + + let ctrl = &self.ctrl.borrow().ctrl; + + if self.pos.y >= lvl.ground { + self.pos.y = lvl.ground; + self.vel.y = 0.0; + self.vel.x *= 0.9; + + if ctrl.button(Button::A) { + self.vel.y = -5.0; + } + } + + match ctrl.axis(Axis::LeftX) as f64 / 32768.0 { + v if v < -0.9 => { self.vel.x -= 0.5 } + v if v > 0.9 => { self.vel.x += 0.5 } + _ => {} + } + } + + fn render(&mut self, canvas: &mut Canvas, sprites: &mut SpriteManager) { + let block = sprites.get("mario"); + let size = 32; + canvas.copy(block, None, Rect::new(self.pos.x as i32, self.pos.y as i32 - size as i32, size, size)).unwrap(); + } +} diff --git a/src/core/mod.rs b/src/core/mod.rs index 140bac4..9bcbe0c 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,2 +1,3 @@ pub mod app; pub mod controller; +pub mod game; diff --git a/src/main.rs b/src/main.rs index 26ceadb..9195583 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ extern crate rand; extern crate sdl2; extern crate time; +use core::game::GameState; use core::app::*; mod core; @@ -17,7 +18,8 @@ fn main() { println!("starting..."); let mut app = App::new() .with_resolution(SCREEN_WIDTH, SCREEN_HEIGHT) - .with_state(Box::new(ActiveState::new((SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32)))) +// .with_state(Box::new(ActiveState::new((SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32)))) + .with_state(Box::new(GameState::new())) .with_title("SDL test") .build() .unwrap(); -- 2.11.0