- added a basic pong game

- added a better timer system for event updates
This commit is contained in:
FantasyPvP
2024-03-22 23:52:45 +00:00
parent d5d9e031d5
commit c4067fabc8
7 changed files with 136 additions and 40 deletions
+4 -1
View File
@@ -137,7 +137,10 @@ impl Frame {
} }
pub fn write(&mut self, position: Position, char: ColouredChar) -> Result<(), RenderError> { pub fn write(&mut self, position: Position, char: ColouredChar) -> Result<(), RenderError> {
if position.x >= self.dimensions.x || position.y >= self.dimensions.y { 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; self.frame[position.y][position.x] = char;
Ok(()) Ok(())
+6 -6
View File
@@ -52,12 +52,12 @@ pub enum Screen {
/// DEPRECATED - STOP USING THIS SOON /// DEPRECATED - STOP USING THIS SOON
impl Screen { impl Screen {
/// mode can be set for the kernel using this method /// mode can be set for the kernel using this method
pub fn set_mode(&self) -> Result<(), RenderError> { // pub fn set_mode(&self) -> Result<(), RenderError> {
Ok(match self { // Ok(match self {
Screen::Terminal => RENDERER.lock().terminal_mode(), // Screen::Terminal => RENDERER.lock().terminal_mode(),
Screen::Application => RENDERER.lock().application_mode(), // Screen::Application => RENDERER.lock().application_mode(),
}) // })
} // }
/// returns the current display mode /// returns the current display mode
pub fn get_mode() -> Screen { pub fn get_mode() -> Screen {
+38
View File
@@ -1,6 +1,9 @@
use cmos_rtc::Time;
use crate::println; use crate::println;
use super::super::kernel::interrupts::GLOBALTIMER; use super::super::kernel::interrupts::GLOBALTIMER;
use x86_64::instructions::interrupts; use x86_64::instructions::interrupts;
use crate::system::kernel::interrupts::InterruptIndex;
pub fn wait(seconds: f64) { pub fn wait(seconds: f64) {
let mut start = 0; let mut start = 0;
interrupts::without_interrupts(||{ interrupts::without_interrupts(||{
@@ -22,4 +25,39 @@ pub fn timer() {
interrupts::without_interrupts(||{ interrupts::without_interrupts(||{
println!("{}", GLOBALTIMER.lock().val); 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
}
} }
+2 -4
View File
@@ -1,7 +1,7 @@
use crate::std::application::Error; use crate::std::application::Error;
use crate::std::application::Error::ApplicationError; use crate::std::application::Error::ApplicationError;
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError}; 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::std::random::Random;
use crate::system::std::application::Application; use crate::system::std::application::Application;
use crate::user::lib::libgui::cg_core::{CgComponent, Widget}; use crate::user::lib::libgui::cg_core::{CgComponent, Widget};
@@ -53,7 +53,7 @@ impl Application for Game {
} }
} }
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> { async fn run(&mut self, args: Vec<String>) -> Result<(), Error> {
Screen::Application.set_mode().unwrap(); let d = Display::borrow();
let mut container_data = let mut container_data =
CgContainer::new(Position::new(0, 0), Dimensions::new(80, 25), true); CgContainer::new(Position::new(0, 0), Dimensions::new(80, 25), true);
@@ -224,8 +224,6 @@ impl Game {
} }
} }
Screen::Terminal.set_mode().unwrap();
Ok(()) Ok(())
} }
} }
+2 -4
View File
@@ -6,7 +6,7 @@ use core::any::Any;
use async_trait::async_trait; use async_trait::async_trait;
use crate::std::application::{Application, Error}; use crate::std::application::{Application, Error};
use crate::std::frame::{Frame, Position, Dimensions, ColouredChar, RenderError}; 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::{ use crate::user::lib::libgui::{
cg_core::{CgComponent}, cg_core::{CgComponent},
@@ -49,7 +49,7 @@ impl Application for Grapher {
} }
} }
async fn run(&mut self, args: Vec<String>) -> Result<(), Error> { async fn run(&mut self, args: Vec<String>) -> 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]; 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(()); return Ok(());
} }
else { 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(()) Ok(())
} }
} }
+82 -17
View File
@@ -5,8 +5,9 @@ use core::any::Any;
use async_trait::async_trait; use async_trait::async_trait;
use crate::std::application::{Application, Error}; use crate::std::application::{Application, Error};
use crate::std; use crate::std;
use crate::std::frame::{ColouredChar, Dimensions, Frame, Position, RenderError}; use crate::std::frame::{BUFFER_HEIGHT, BUFFER_WIDTH, ColorCode, ColouredChar, Dimensions, Frame, Position, RenderError};
use crate::std::io::{Display, KeyStroke, Stdin}; use crate::std::io::{Color, Display, KeyStroke, Stdin};
use crate::std::time::Timer;
use crate::user::lib::libgui::cg_core::CgComponent; use crate::user::lib::libgui::cg_core::CgComponent;
pub(crate) struct Game { pub(crate) struct Game {
@@ -28,28 +29,44 @@ impl Application for Game {
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> { async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
let d = Display::borrow(); let d = Display::borrow();
let mut update_time = Timer::new(0.1);
let mut updated;
loop { loop {
std::time::wait(0.01); updated = false;
if let Some(key) = Stdin::try_keystroke() { if let Some(key) = Stdin::try_keystroke() {
match key { match key {
KeyStroke::Char('w') => { KeyStroke::Char('w') => {
self.player1.pos.y -= 1; self.player1.move_player(-1);
updated = true;
}, },
KeyStroke::Char('s') => { KeyStroke::Char('s') => {
self.player1.pos.y += 1; self.player1.move_player(1);
updated = true;
}, },
KeyStroke::Up => { KeyStroke::Up => {
self.player2.pos.y -= 1; self.player2.move_player(-1);
updated = true;
}, },
KeyStroke::Down => { KeyStroke::Down => {
self.player2.pos.y += 1; self.player2.move_player(1);
} updated = true;
},
KeyStroke::Char('`') => break,
_ => {} _ => {}
} }
} }
if let Ok(frame) = self.render() { if update_time.is_done() {
frame.write_to_screen().unwrap(); 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); // self.ball.update(&self.player1, &self.player2);
} }
@@ -60,10 +77,12 @@ impl Application for Game {
impl CgComponent for Game { impl CgComponent for Game {
fn render(&self) -> Result<Frame, RenderError> { fn render(&self) -> Result<Frame, RenderError> {
let mut frame = Frame::new(Dimensions::new(0, 0), Dimensions::new(80, 25))?; let mut frame = Frame::new(Dimensions::new(0, 0), Dimensions::new(80, 25))?;
frame.write(self.player1.pos, ColouredChar::new('@')).unwrap(); for y in (0..5) {
frame.write(self.player2.pos, ColouredChar::new('@')).unwrap(); 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(self.ball.pos, ColouredChar::new('@')).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) Ok(frame)
} }
@@ -78,10 +97,21 @@ struct Player {
score: i32, score: i32,
} }
impl Player { impl Player {
fn new(x: usize) -> Self { fn new(x: usize) -> Self {
Player { pos: Position::new(x, 12), score: 0 } 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 { struct Ball {
@@ -92,10 +122,45 @@ struct Ball {
impl Ball { impl Ball {
fn new() -> Self { 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) { fn update(&mut self, player1: &mut Player, player2: &mut Player) {
self.pos.x = (self.pos.x as i32 + self.vx) as usize; 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
)
} }
} }
+2 -8
View File
@@ -16,6 +16,7 @@ use crate::std::{
Color, write, Screen, Stdin, Serial, KeyStroke Color, write, Screen, Stdin, Serial, KeyStroke
}, },
}; };
use crate::std::io::Display;
use crate::user::{ use crate::user::{
lib::libgui::{ 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 // 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(|| {}); //interrupts::without_interrupts(|| {});
} }
"switch" => {
match Screen::get_mode() {
Screen::Terminal => Screen::Application.set_mode().unwrap(),
Screen::Application => Screen::Terminal.set_mode().unwrap(),
};
}
"time" => { "time" => {
timer(); timer();
} }
"test_features" => { "test_features" => {
Screen::Application.set_mode().unwrap(); let d = Display::borrow();
setup_ui().await; setup_ui().await;
Screen::Terminal.set_mode().unwrap();
} }
_ => { _ => {
return Err(Error::UnknownCommand( return Err(Error::UnknownCommand(