made a game
made a snake game and rewrote some rendering stuff again
This commit is contained in:
@@ -1,24 +1,24 @@
|
||||
use async_trait::async_trait;
|
||||
use rand::prelude::*;
|
||||
|
||||
use super::{
|
||||
engine::{eventcheck, Choice, Event},
|
||||
entity::{Entity, Enemy, EntityObject},
|
||||
engine::{Choice, Event, eventcheck},
|
||||
entity::{Enemy, Entity, EntityObject},
|
||||
player::Player,
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, string::{String, ToString}, vec::Vec, format, borrow::ToOwned};
|
||||
use alloc::{borrow::ToOwned, format, string::{String, ToString}, vec::Vec, boxed::Box};
|
||||
|
||||
use crate::{
|
||||
std::application::{
|
||||
Application,
|
||||
Error,
|
||||
},
|
||||
use crate::{
|
||||
std::{
|
||||
io::{self, println, serial_println, FRAMEGEN, Element},
|
||||
random,
|
||||
io::{self, println, serial_println},
|
||||
frame::FRAMEGEN,
|
||||
random,
|
||||
},
|
||||
std::application::{
|
||||
Application,
|
||||
Error,
|
||||
},
|
||||
};
|
||||
use crate::system::std::frame::Element;
|
||||
|
||||
|
||||
pub struct GameLoop;
|
||||
@@ -91,7 +91,7 @@ impl Application for GameLoop {
|
||||
for row in fr {
|
||||
let mut r = String::new();
|
||||
for col in row {
|
||||
r.push(col);
|
||||
r.push(col.character as char);
|
||||
}
|
||||
string.push_str(&r);
|
||||
string.push('\n')
|
||||
|
||||
@@ -8,21 +8,21 @@ use crate::{std::os::OS, std::io::{Color, write, Screen}, println, std::applicat
|
||||
}, std};
|
||||
|
||||
const CRYSTAL_LOGO: &str =
|
||||
" $$$$$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$\\
|
||||
$$ __$$\\ $$ | $$ $$ __$$\\$$ __$$\\
|
||||
$$ / \\__|$$$$$$\\ $$\\ $$\\ $$$$$$$\\$$$$$$\\ $$$$$$\\ $$ $$ / $$ $$ / \\__|
|
||||
$$ | $$ __$$\\$$ | $$ $$ _____\\_$$ _| \\____$$\\$$ $$ | $$ \\$$$$$$\\
|
||||
$$ | $$ | \\__$$ | $$ \\$$$$$$\\ $$ | $$$$$$$ $$ $$ | $$ |\\____$$\\
|
||||
$$ | $$\\$$ | $$ | $$ |\\____$$\\ $$ |$$\\$$ __$$ $$ $$ | $$ $$\\ $$ |
|
||||
\\$$$$$$ $$ | \\$$$$$$$ $$$$$$$ | \\$$$$ \\$$$$$$$ $$ |$$$$$$ \\$$$$$$ |
|
||||
\\______/\\__| \\____$$ \\_______/ \\$$$$$$\\_______\\__|\\______/ \\______/
|
||||
$$\\ $$ | $$ __$$\\
|
||||
\\$$$$$$ | $$\\ $$\\__/ $$ |
|
||||
\\______/ \\$$\\ $$ $$$$$$ |
|
||||
\\$$\\$$ $$ ____/
|
||||
\\$$$ /$$ |
|
||||
\\$ / $$$$$$$$\\
|
||||
\\_/ \\________| ";
|
||||
"\n $$$$$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$\\
|
||||
$$ __$$\\ $$ | $$ $$ __$$\\$$ __$$\\
|
||||
$$ / \\__|$$$$$$\\ $$\\ $$\\ $$$$$$$\\$$$$$$\\ $$$$$$\\ $$ $$ / $$ $$ / \\__|
|
||||
$$ | $$ __$$\\$$ | $$ $$ _____\\_$$ _| \\____$$\\$$ $$ | $$ \\$$$$$$\\
|
||||
$$ | $$ | \\__$$ | $$ \\$$$$$$\\ $$ | $$$$$$$ $$ $$ | $$ |\\____$$\\
|
||||
$$ | $$\\$$ | $$ | $$ |\\____$$\\ $$ |$$\\$$ __$$ $$ $$ | $$ $$\\ $$ |
|
||||
\\$$$$$$ $$ | \\$$$$$$$ $$$$$$$ | \\$$$$ \\$$$$$$$ $$ |$$$$$$ \\$$$$$$ |
|
||||
\\______/\\__| \\____$$ \\_______/ \\$$$$$$\\_______\\__|\\______/ \\______/
|
||||
$$\\ $$ | $$ __$$\\
|
||||
\\$$$$$$ | $$\\ $$\\__/ $$ |
|
||||
\\______/ \\$$\\ $$ $$$$$$ |
|
||||
\\$$\\$$ $$ ____/
|
||||
\\$$$ /$$ |
|
||||
\\$ / $$$$$$$$\\
|
||||
\\_/ \\________| ";
|
||||
|
||||
const ZXQ5_LOGO: &str = "
|
||||
|
||||
@@ -59,10 +59,10 @@ impl Application for CrystalFetch {
|
||||
[ Author » FantasyPvP / ZXQ5", os, version);
|
||||
|
||||
// write to output
|
||||
let spacer = "\n".repeat(24 - logo_string.lines().count() - 4 - info_string.lines().count());
|
||||
let spacer = "\n".repeat(25 - logo_string.lines().count() - 4 - info_string.lines().count());
|
||||
// write values to console
|
||||
write(format_args!("{}", logo_string), (Color::Cyan, Color::Black));
|
||||
println!("\n\n");
|
||||
println!("\n");
|
||||
println!("{}", info_string);
|
||||
println!("{}", spacer);
|
||||
|
||||
|
||||
@@ -7,3 +7,4 @@ pub mod shell;
|
||||
pub mod tasks;
|
||||
mod gigachad_detector;
|
||||
mod shellrewrite;
|
||||
mod snake;
|
||||
|
||||
@@ -125,13 +125,13 @@ async fn exec() -> Result<(), Error> {
|
||||
"switch" => {
|
||||
Screen::switch();
|
||||
}
|
||||
"snake" => {
|
||||
let mut game = snake::Game::new();
|
||||
game.run(Vec::new()).await;
|
||||
}
|
||||
"gigachad?" => {
|
||||
let mut gigachad_detector = GigachadDetector::new();
|
||||
gigachad_detector.run(args).await?;
|
||||
}
|
||||
"filesystem" => {
|
||||
use crate::std::io;
|
||||
io::mkfs();
|
||||
}
|
||||
"test_features" => {
|
||||
use crate::std::random::Random;
|
||||
|
||||
+117
-51
@@ -4,11 +4,7 @@ use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use x86_64::instructions::interrupts;
|
||||
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use alloc::{boxed::Box, string::{String, ToString}, vec, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
kernel::tasks::{executor::Executor, Task},
|
||||
@@ -16,6 +12,8 @@ use crate::{
|
||||
std::io::{print, println, Stdin, Screen},
|
||||
user::bin::*,
|
||||
};
|
||||
use crate::std::io::{Color, write};
|
||||
use crate::user::bin::gigachad_detector::GigachadDetector;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -34,59 +32,127 @@ use super::*;
|
||||
/// starts the shell
|
||||
/// this function should be directly called by main.rs or by an init system
|
||||
|
||||
fn new_function() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub fn userspace() -> Result<(), String> {
|
||||
let mut executor = Executor::new();
|
||||
|
||||
//
|
||||
// executor.spawn(Task::new(new_function()));
|
||||
// loop {
|
||||
// executor.try_run()
|
||||
// }
|
||||
fn run_task(task_name: String, args: Vec<String>) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// struct Shell {}
|
||||
//
|
||||
// impl Application for Shell {
|
||||
// fn new() -> Shell {
|
||||
// Shell {}
|
||||
// }
|
||||
// async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
pub async fn userspace() -> Result<(), String> {
|
||||
let mut executor = Executor::new();
|
||||
|
||||
let mut shell = Shell::new();
|
||||
shell.run(vec![]).await.unwrap();
|
||||
|
||||
|
||||
|
||||
fn parse_args(command: String) -> Result<(String, Vec<String>), String> {
|
||||
let mut args: Vec<String> = Vec::new();
|
||||
|
||||
for arg in command.split(" ").collect::<Vec<&str>>() {
|
||||
match arg {
|
||||
"" => {}
|
||||
x => args.push(x.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
let cmd: String;
|
||||
if args.len() > 0 {
|
||||
cmd = args[0].clone();
|
||||
args.remove(0);
|
||||
} else {
|
||||
return Err("command was empty.".to_string());
|
||||
};
|
||||
|
||||
Ok((cmd, args))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct Shell {
|
||||
history: Vec<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Application for Shell {
|
||||
fn new() -> Shell {
|
||||
Shell {
|
||||
history: Vec::new(),
|
||||
}
|
||||
}
|
||||
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
|
||||
loop {
|
||||
self.prompt();
|
||||
let input = Stdin::readline().await;
|
||||
let (cmd, args) = self.parse_args(input).unwrap();
|
||||
self.run_cmd(cmd, args).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Shell {
|
||||
fn prompt(&mut self) {
|
||||
write(format_args!("\n Crystal> "), (Color::Cyan, Color::Black));
|
||||
}
|
||||
|
||||
// fn exec<R, T: Fn() -> R>(command: T) -> Result<R, Error> { // this command runs when a shell command is executed
|
||||
// Ok(command())
|
||||
// }
|
||||
async fn run_cmd(&mut self, cmd: String, args: Vec<String>) -> Result<(), Error> {
|
||||
match cmd.as_str() {
|
||||
"calculate" | "calc" | "solve" => {
|
||||
let mut cmd = calc::Calculator::new();
|
||||
cmd.run(args).await?;
|
||||
}
|
||||
"rickroll" => {
|
||||
let mut cmd = rickroll::Rickroll::new();
|
||||
cmd.run(args).await?;
|
||||
}
|
||||
"crystalfetch" => {
|
||||
let mut cmd = crystalfetch::CrystalFetch::new();
|
||||
cmd.run(args).await?;
|
||||
}
|
||||
"tasks" => {
|
||||
let mut cmd = tasks::Tasks::new();
|
||||
cmd.run(args).await?;
|
||||
}
|
||||
"play" => {
|
||||
let mut gameloop = crystal_rpg::init::GameLoop::new();
|
||||
gameloop.run(args).await?;
|
||||
}
|
||||
"echo" => {
|
||||
println!(
|
||||
"Crystal: '{}'",
|
||||
" ".join(args)
|
||||
)
|
||||
}
|
||||
"clear" => {
|
||||
Screen::clear();
|
||||
}
|
||||
"print" => {
|
||||
use crate::std::os::OS;
|
||||
let x: String = OS.lock().version.clone();
|
||||
println!("{}", x);
|
||||
}
|
||||
"snake" => {
|
||||
let mut game = snake::Game::new();
|
||||
game.run(Vec::new()).await?;
|
||||
}
|
||||
"gigachad?" => {
|
||||
let mut gigachad_detector = GigachadDetector::new();
|
||||
gigachad_detector.run(args).await?;
|
||||
}
|
||||
"test_features" => {
|
||||
use crate::std::random::Random;
|
||||
println!("{}", Random::int(0, 10));
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnknownCommand(
|
||||
"command not yet implemented".to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn parse_args(&self, command: String) -> Result<(String, Vec<String>), String> {
|
||||
let mut args: Vec<String> = Vec::new();
|
||||
|
||||
for arg in command.split(" ").collect::<Vec<&str>>() {
|
||||
match arg {
|
||||
"" => {}
|
||||
x => args.push(x.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
let cmd: String;
|
||||
if args.len() > 0 {
|
||||
cmd = args[0].clone();
|
||||
args.remove(0);
|
||||
}
|
||||
else {
|
||||
return Err("command was empty.".to_string());
|
||||
};
|
||||
|
||||
Ok((cmd, args))
|
||||
}
|
||||
}
|
||||
|
||||
//fn run_binary(binary: dyn Application) -> Result<Vec<String>, String> {
|
||||
// binary.run();
|
||||
// Ok(Vec::<String::new()>)
|
||||
//}
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
use alloc::string::String;
|
||||
use alloc::{format, vec, vec::Vec, boxed::Box};
|
||||
use async_trait::async_trait;
|
||||
use crate::std::io::{Color, Screen};
|
||||
use crate::kernel::tasks::keyboard::KEYBOARD;
|
||||
use crossbeam_queue::SegQueue;
|
||||
use crate::kernel::render::{ColorCode, ScreenChar};
|
||||
use crate::std::application::{Application, Error};
|
||||
use crate::std::random::Random;
|
||||
use crate::system::std::frame::ColouredElement;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
struct Point {
|
||||
x: i8,
|
||||
y: i8,
|
||||
}
|
||||
|
||||
pub struct Game {
|
||||
snake: SegQueue<Point>,
|
||||
head: Point,
|
||||
poi: Point,
|
||||
score: u8
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Application for Game {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
snake: SegQueue::new(),
|
||||
head: Point { x: 5, y: 5 },
|
||||
poi: Point { x: 0, y: 0 },
|
||||
score: 0
|
||||
}
|
||||
}
|
||||
|
||||
async fn run(&mut self, _: Vec<String>) -> Result<(), Error> {
|
||||
Screen::application_mode();
|
||||
|
||||
(0..=2).for_each(|x| {
|
||||
self.snake.push(Point { x, y: 5 });
|
||||
});
|
||||
self.head = Point { x: 2, y: 5 };
|
||||
self.new_poi();
|
||||
|
||||
'gameloop: loop {
|
||||
let chr = KEYBOARD.lock().get_keystroke().await;
|
||||
match chr {
|
||||
'w' => self.head.y -= 1,
|
||||
'a' => self.head.x -= 1,
|
||||
's' => self.head.y += 1,
|
||||
'd' => self.head.x += 1,
|
||||
'x' => break,
|
||||
_ => continue,
|
||||
}
|
||||
self.snake.push(Point { x: self.head.x, y: self.head.y }); // new head added
|
||||
|
||||
if self.head == self.poi {
|
||||
self.new_poi();
|
||||
self.score += 1
|
||||
} else {
|
||||
self.snake.pop().unwrap(); // tail removed if score does not increase
|
||||
}
|
||||
|
||||
if self.lose_condition() {
|
||||
self.render_end_screen().map_err(|_| Error::ApplicationError(String::from("failed to render game over screen")))?;
|
||||
while let chr = KEYBOARD.lock().get_keystroke().await {
|
||||
match chr {
|
||||
'x' => break 'gameloop,
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let clone = self.clone_snake();
|
||||
self.render(clone).map_err(|_| Error::ApplicationError(String::from("failed to render game screen")))?;
|
||||
};
|
||||
|
||||
Screen::terminal_mode();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Game {
|
||||
fn new_poi(&mut self) {
|
||||
self.poi = Point { x: Random::int(3, 76) as i8, y: Random::int(3, 21) as i8 }
|
||||
}
|
||||
|
||||
fn render(&mut self, snake: Vec<Point>) -> Result<(), ()> {
|
||||
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
|
||||
snake.into_iter().for_each(|p| {
|
||||
frame[p.y as usize][p.x as usize] = ScreenChar::new('@' as u8, ColorCode::new(Color::Cyan, Color::Black));
|
||||
});
|
||||
|
||||
frame[self.poi.y as usize][self.poi.x as usize] = ScreenChar::new('o' as u8, ColorCode::new(Color::Red, Color::Black));
|
||||
let literal = format!("snake go brr score: {}", self.score);
|
||||
let msg = Game::centre_text(80, literal);
|
||||
frame[1] = msg.chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::LightGreen, Color::Black))).collect();
|
||||
|
||||
let mut elem = ColouredElement::generate(frame, (80, 25));
|
||||
elem.render((0,0))
|
||||
}
|
||||
|
||||
fn lose_condition(&mut self) -> bool {
|
||||
let cloned = self.clone_snake();
|
||||
let snake_overlaps = (1..cloned.len()).any(|i| cloned[i..].contains(&cloned[i - 1])); // checks if any part of the snake overlaps itself
|
||||
let out_of_bounds = cloned.iter().filter(|p| p.x < 0 || p.y < 0 || p.x > 79 || p.y > 24).count() > 0; // checks if the snake goes out of bounds
|
||||
|
||||
snake_overlaps || out_of_bounds
|
||||
}
|
||||
|
||||
fn centre_text(dims: usize, text: String) -> String { // centres text in a string of whitespace of a given length
|
||||
let max_pad = dims / 2;
|
||||
let mut msg = String::new();
|
||||
msg.push_str(" ".repeat(max_pad - round_up(text.len() as f64 / 2.0)).as_str());
|
||||
msg.push_str(text.as_str());
|
||||
msg.push_str(" ".repeat(max_pad - round_down(text.len() as f64 / 2.0 + 0.51)).as_str());
|
||||
msg
|
||||
}
|
||||
|
||||
fn render_end_screen(&mut self) -> Result<(), ()> {
|
||||
let mut frame = vec![vec![ScreenChar::null(); 80]; 25];
|
||||
|
||||
frame[10] = Game::centre_text(80, String::from("u lost")).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::Red, Color::Black))).collect();
|
||||
frame[12] = Game::centre_text(80, String::from(format!("ur score was {}", self.score))).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::LightGreen, Color::Black))).collect();
|
||||
frame[14] = Game::centre_text(80, String::from("L bozo")).chars().map(|c| ScreenChar::new(c as u8, ColorCode::new(Color::Red, Color::Black))).collect();
|
||||
|
||||
|
||||
let mut elem = ColouredElement::generate(frame, (80, 25));
|
||||
elem.render((0,0))
|
||||
}
|
||||
|
||||
fn clone_snake(&mut self) -> Vec<Point> {
|
||||
let mut cloned= Vec::new();
|
||||
let mut snake = SegQueue::new();
|
||||
while !self.snake.is_empty() {
|
||||
let item = self.snake.pop().unwrap();
|
||||
cloned.push(item.clone());
|
||||
snake.push(item);
|
||||
}
|
||||
self.snake = snake;
|
||||
cloned
|
||||
}
|
||||
}
|
||||
|
||||
fn round_up(n: f64) -> usize {
|
||||
(n + 0.99) as usize
|
||||
}
|
||||
fn round_down(n: f64) -> usize {
|
||||
n as usize
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER};
|
||||
use crate::std::io::Frame;
|
||||
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER, ScreenChar};
|
||||
use crate::system::std::frame::Frame;
|
||||
use crate::{print, println};
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
@@ -154,7 +154,7 @@ impl Element for IndicatorBar {
|
||||
// rendered.
|
||||
|
||||
pub fn render_frame(elements: Vec<Container>) {
|
||||
let mut buffer: Frame = [[' '; BUFFER_WIDTH]; BUFFER_HEIGHT];
|
||||
let mut buffer: Frame = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
|
||||
|
||||
for frame in elements.iter() {
|
||||
let f = frame.render();
|
||||
@@ -162,8 +162,8 @@ pub fn render_frame(elements: Vec<Container>) {
|
||||
for (i, row) in f.0.iter().enumerate() {
|
||||
for (j, chr) in row.iter().enumerate() {
|
||||
let mut current = &buffer[i + f.1.y][j + f.1.x];
|
||||
let newchar = overlap_check(*current, *chr);
|
||||
buffer[i + f.1.y][j + f.1.x] = newchar;
|
||||
let newchar = overlap_check(current.character as char, *chr);
|
||||
buffer[i + f.1.y][j + f.1.x] = ScreenChar::white(newchar as u8);
|
||||
|
||||
//print!("{}", buffer[i+frame.position.1][j+frame.position.0]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user