- 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
+2 -4
View File
@@ -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(())
}
}
+2 -4
View File
@@ -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
View File
@@ -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
)
}
}
+2 -8
View File
@@ -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(