diff --git a/src/system/std/frame.rs b/src/system/std/frame.rs index 0325bea..1437ca5 100644 --- a/src/system/std/frame.rs +++ b/src/system/std/frame.rs @@ -137,7 +137,10 @@ impl Frame { } pub fn write(&mut self, position: Position, char: ColouredChar) -> Result<(), RenderError> { if position.x >= self.dimensions.x || position.y >= self.dimensions.y { - return Err(RenderError::OutOfBounds(true, true)); + return Err(RenderError::OutOfBounds( + position.x >= self.dimensions.x, + position.y >= self.dimensions.y, + )); } self.frame[position.y][position.x] = char; Ok(()) diff --git a/src/system/std/io.rs b/src/system/std/io.rs index 692d0da..1a592ee 100644 --- a/src/system/std/io.rs +++ b/src/system/std/io.rs @@ -52,12 +52,12 @@ pub enum Screen { /// DEPRECATED - STOP USING THIS SOON impl Screen { /// mode can be set for the kernel using this method - pub fn set_mode(&self) -> Result<(), RenderError> { - Ok(match self { - Screen::Terminal => RENDERER.lock().terminal_mode(), - Screen::Application => RENDERER.lock().application_mode(), - }) - } + // pub fn set_mode(&self) -> Result<(), RenderError> { + // Ok(match self { + // Screen::Terminal => RENDERER.lock().terminal_mode(), + // Screen::Application => RENDERER.lock().application_mode(), + // }) + // } /// returns the current display mode pub fn get_mode() -> Screen { diff --git a/src/system/std/time.rs b/src/system/std/time.rs index 4bbb2c6..3b5e35d 100644 --- a/src/system/std/time.rs +++ b/src/system/std/time.rs @@ -1,6 +1,9 @@ +use cmos_rtc::Time; use crate::println; use super::super::kernel::interrupts::GLOBALTIMER; use x86_64::instructions::interrupts; +use crate::system::kernel::interrupts::InterruptIndex; + pub fn wait(seconds: f64) { let mut start = 0; interrupts::without_interrupts(||{ @@ -22,4 +25,39 @@ pub fn timer() { interrupts::without_interrupts(||{ println!("{}", GLOBALTIMER.lock().val); }); +} + +pub struct Timer { + duration: f64, + end: f64 +} + +impl Timer { + pub(crate) fn new(seconds: f64) -> Self { + let mut start = 0; + interrupts::without_interrupts(||{ + start = GLOBALTIMER.lock().val; + }); + + Timer { + duration: seconds, + end: start as f64 + seconds * 16.0 + } + } + + pub(crate) fn is_done(&self) -> bool { + let mut done = false; + interrupts::without_interrupts(||{ + done = GLOBALTIMER.lock().val as f64 > self.end; + }); + done + } + + pub(crate) fn reset(&mut self) { + let mut start = 0; + interrupts::without_interrupts(||{ + start = GLOBALTIMER.lock().val; + }); + self.end = start as f64 + self.duration * 16.0 + } } \ No newline at end of file diff --git a/src/user/bin/asteroids.rs b/src/user/bin/asteroids.rs index e863c06..95add4c 100644 --- a/src/user/bin/asteroids.rs +++ b/src/user/bin/asteroids.rs @@ -1,7 +1,7 @@ use crate::std::application::Error; use crate::std::application::Error::ApplicationError; use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError}; -use crate::std::io::{Color, ColorCode, KeyStroke, Screen, Stdin}; +use crate::std::io::{Color, ColorCode, Display, KeyStroke, Screen, Stdin}; use crate::std::random::Random; use crate::system::std::application::Application; use crate::user::lib::libgui::cg_core::{CgComponent, Widget}; @@ -53,7 +53,7 @@ impl Application for Game { } } async fn run(&mut self, args: Vec) -> Result<(), Error> { - Screen::Application.set_mode().unwrap(); + let d = Display::borrow(); let mut container_data = CgContainer::new(Position::new(0, 0), Dimensions::new(80, 25), true); @@ -224,8 +224,6 @@ impl Game { } } - Screen::Terminal.set_mode().unwrap(); - Ok(()) } } diff --git a/src/user/bin/grapher.rs b/src/user/bin/grapher.rs index 08ee7cc..0e54f2b 100644 --- a/src/user/bin/grapher.rs +++ b/src/user/bin/grapher.rs @@ -6,7 +6,7 @@ use core::any::Any; use async_trait::async_trait; use crate::std::application::{Application, Error}; use crate::std::frame::{Frame, Position, Dimensions, ColouredChar, RenderError}; -use crate::std::io::{KeyStroke, Screen, Stdin}; +use crate::std::io::{Display, KeyStroke, Screen, Stdin}; use crate::user::lib::libgui::{ cg_core::{CgComponent}, @@ -49,7 +49,7 @@ impl Application for Grapher { } } async fn run(&mut self, args: Vec) -> Result<(), Error> { - Screen::Application.set_mode().map_err(|_| Error::ApplicationError(String::from("failed to set application mode")))?; + let d = Display::borrow(); self.frame.frame = vec![vec![ColouredChar::new(' '); self.frame.dimensions.x]; self.frame.dimensions.y]; @@ -68,7 +68,6 @@ impl Application for Grapher { } } - Screen::Terminal.set_mode().map_err(|_| Error::ApplicationError(String::from("failed to set terminal mode")))?; return Ok(()); } else { @@ -145,7 +144,6 @@ impl Application for Grapher { } } - Screen::Terminal.set_mode().map_err(|_| Error::ApplicationError(String::from("failed to set application mode")))?; Ok(()) } } diff --git a/src/user/bin/pong.rs b/src/user/bin/pong.rs index 916e473..c96159c 100644 --- a/src/user/bin/pong.rs +++ b/src/user/bin/pong.rs @@ -5,8 +5,9 @@ use core::any::Any; use async_trait::async_trait; use crate::std::application::{Application, Error}; use crate::std; -use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError}; -use crate::std::io::{Display, KeyStroke, Stdin}; +use crate::std::frame::{BUFFER_HEIGHT, BUFFER_WIDTH, ColorCode, ColouredChar, Dimensions, Frame, Position, RenderError}; +use crate::std::io::{Color, Display, KeyStroke, Stdin}; +use crate::std::time::Timer; use crate::user::lib::libgui::cg_core::CgComponent; pub(crate) struct Game { @@ -28,28 +29,44 @@ impl Application for Game { async fn run(&mut self, _: Vec) -> Result<(), Error> { let d = Display::borrow(); + let mut update_time = Timer::new(0.1); + + let mut updated; loop { - std::time::wait(0.01); + updated = false; if let Some(key) = Stdin::try_keystroke() { match key { KeyStroke::Char('w') => { - self.player1.pos.y -= 1; + self.player1.move_player(-1); + updated = true; }, KeyStroke::Char('s') => { - self.player1.pos.y += 1; + self.player1.move_player(1); + updated = true; }, KeyStroke::Up => { - self.player2.pos.y -= 1; + self.player2.move_player(-1); + updated = true; }, KeyStroke::Down => { - self.player2.pos.y += 1; - } + self.player2.move_player(1); + updated = true; + }, + KeyStroke::Char('`') => break, _ => {} } } - if let Ok(frame) = self.render() { - frame.write_to_screen().unwrap(); + if update_time.is_done() { + updated = true; + self.ball.update(&mut self.player1, &mut self.player2); + update_time.reset() + } + + if updated { + if let Ok(frame) = self.render() { + frame.write_to_screen().unwrap(); + } } // self.ball.update(&self.player1, &self.player2); } @@ -60,10 +77,12 @@ impl Application for Game { impl CgComponent for Game { fn render(&self) -> Result { let mut frame = Frame::new(Dimensions::new(0, 0), Dimensions::new(80, 25))?; - - frame.write(self.player1.pos, ColouredChar::new('@')).unwrap(); - frame.write(self.player2.pos, ColouredChar::new('@')).unwrap(); - frame.write(self.ball.pos, ColouredChar::new('@')).unwrap(); + + for y in (0..5) { + frame.write(Position::new(self.player1.pos.x, self.player1.pos.y + y -2), ColouredChar::coloured('▓', ColorCode::new(Color::Cyan, Color::Black))).unwrap(); + frame.write(Position::new(self.player2.pos.x, self.player2.pos.y + y -2), ColouredChar::coloured('▓', ColorCode::new(Color::Cyan, Color::Black))).unwrap(); + } + frame.write(self.ball.pos, ColouredChar::coloured('O', ColorCode::new(Color::Green, Color::Black))).unwrap(); Ok(frame) } @@ -78,10 +97,21 @@ struct Player { score: i32, } + impl Player { fn new(x: usize) -> Self { Player { pos: Position::new(x, 12), score: 0 } } + + // valid for |y| = 1 + fn move_player(&mut self, y: i32) { + if self.pos.y < 3 && y < 0 { + return; + } else if self.pos.y >= BUFFER_HEIGHT - 3 && y > 0 { + return; + } + self.pos.y = (self.pos.y as i32 + y) as usize; + } } struct Ball { @@ -92,10 +122,45 @@ struct Ball { impl Ball { fn new() -> Self { - Ball { pos: Position::new(40, 12), vx: 1, vy: 0 } + Ball { pos: Position::new(40, 12), vx: 1, vy: 1 } } - fn update(&mut self, player1: &Player, player2: &Player) { - self.pos.x = (self.pos.x as i32 + self.vx) as usize; + fn update(&mut self, player1: &mut Player, player2: &mut Player) { + let pos_next = Position::new( // invert x direction on collision with player + (self.pos.x as i32 + self.vx) as usize, + (self.pos.y as i32 + self.vy) as usize + ); + for i in 0..5 { + if player1.pos.y + i == pos_next.y && player1.pos.x == pos_next.x { + self.vx = -self.vx; + break; + } else if player2.pos.y + i == pos_next.y && player2.pos.x == pos_next.x { + self.vx = -self.vx; + break; + } + }; + + if pos_next.y < 0 || pos_next.y >= BUFFER_HEIGHT { // if the move is outside the screen, then invert the direction + self.vy = -self.vy; + } + + if pos_next.x < 0 { + player2.score += 1; + self.pos = Position::new(40, 12); + self.vx = 1; + self.vy = 1; + } + + if pos_next.x >= BUFFER_WIDTH { + player1.score += 1; + self.pos = Position::new(40, 12); + self.vx = -1; + self.vy = 1; + } + + self.pos = Position::new( + (self.pos.x as i32 + self.vx) as usize, + (self.pos.y as i32 + self.vy) as usize + ) } } diff --git a/src/user/bin/shell.rs b/src/user/bin/shell.rs index faeaef2..7dfe8ed 100644 --- a/src/user/bin/shell.rs +++ b/src/user/bin/shell.rs @@ -16,6 +16,7 @@ use crate::std::{ Color, write, Screen, Stdin, Serial, KeyStroke }, }; +use crate::std::io::Display; use crate::user::{ lib::libgui::{ @@ -181,19 +182,12 @@ async fn exec() -> Result<(), Error> { // not sure why this code was here but leaving it in case weird bugs happen so i remember to add it back if so //interrupts::without_interrupts(|| {}); } - "switch" => { - match Screen::get_mode() { - Screen::Terminal => Screen::Application.set_mode().unwrap(), - Screen::Application => Screen::Terminal.set_mode().unwrap(), - }; - } "time" => { timer(); } "test_features" => { - Screen::Application.set_mode().unwrap(); + let d = Display::borrow(); setup_ui().await; - Screen::Terminal.set_mode().unwrap(); } _ => { return Err(Error::UnknownCommand(