- added a basic pong game
- added a better timer system for event updates
This commit is contained in:
@@ -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(())
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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<String>) -> 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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<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];
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
+82
-17
@@ -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<String>) -> 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<Frame, RenderError> {
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user