Skip to content

Commit

Permalink
feat: Levels, maps & loading TOML config files
Browse files Browse the repository at this point in the history
We approach an actual game you can play every single day. It is wonderful. I have implemented a skeleton (as usual) of a level and map system to play on. Level configs can be stored in a toml file.
  • Loading branch information
mdwmage committed May 21, 2024
1 parent 56d2615 commit 74c2d38
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 12 deletions.
104 changes: 103 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ edition = "2021"

[dependencies]
macroquad = "0.4.5"
toml = "0.8.13"
serde = { version = "1.0.202", features = ["serde_derive"] }
9 changes: 9 additions & 0 deletions src/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@
// created on 02/04/24 by Michael Ward
//

use serde::Deserialize;

pub mod player;

pub trait Entity {
fn render(&self);
}

#[derive(Deserialize)]

pub enum Tile {
Water,
Log,
}
67 changes: 56 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,17 @@ async fn main() {
elements: vec![Box::new(&button), Box::new(&title)],
};

let mut main_level = Level::new("test_cfg.toml").await;

let mut master_state = Scene::init();

// Added in reverse order
master_state.push_mut(&mut main_level);
master_state.push_mut(&mut player);
master_state.push(&title_screen);
master_state.push_fn(0, test_hello);

loop {
clear_background(SKYBLUE);
clear_background(LIME);

master_state.tick();

Expand All @@ -71,6 +74,11 @@ fn window_conf() -> Conf {
}
}

enum RunCode {
Ok,
Err(&'static str),
}

/// Callable logic or draw data to be run on the game loop
trait Call {
/// Run data/logic that doesn't require modifying the related entity. Used for rendering.
Expand Down Expand Up @@ -98,34 +106,71 @@ impl<T: ?Sized + Call> Call for &'_ mut T {
/// Container for call objects.
/// Bundle and call all gameObjects at once
struct Scene<'s> {
pub function_stack: Vec<Box<dyn Call + 's>>, // Used to run/handle game logic
pub function_stack: Vec<Vec<fn() -> RunCode>>, // Used to run/handle game logic
pub entity_stack: Vec<Box<dyn Call + 's>>, // Used to handle entities
}

impl<'s> Scene<'s> {
/// Constructor.
/// Initializes with empty function stack
/// Initializes with empty entity stack & one function stack
fn init() -> Self {
Scene {
function_stack: vec![],
function_stack: vec![vec![]],
entity_stack: vec![],
}
}
/// Call all function logic
/// Calls all function & entity logic
fn tick(&mut self) {
for function in &mut self.function_stack {
function.call_mut();
function.call();
// Function Logic
let mut i = 0;
while i < self.function_stack.len() {
// Roll through stacks
let mut x = 0;
while x < self.function_stack[i].len() {
// Roll through functions
let val = self.function_stack[i][x]();
match val {
RunCode::Err(msg) => {
panic!("Function #{x} failed on Stack #{i} with message: {msg}")
}
_ => (),
}
x += 1;
}
i += 1;
}
// Entity Logic
for entity in &mut self.entity_stack {
entity.call_mut(); // Mutate stuff
entity.call(); // Use stuff
}
}

/// Push value as mutable reference
/// For player, maps & other gameObjects
fn push_mut<T: Call>(&mut self, item: &'s mut T) {
self.function_stack.push(Box::new(item));
self.entity_stack.push(Box::new(item));
}

/// Push value as reference
/// For UI and the like
fn push<T: Call>(&mut self, item: &'s T) {
self.function_stack.push(Box::new(item));
self.entity_stack.push(Box::new(item));
}

/// Push function to the function stack.
/// Requires stack to exist
fn push_fn(&mut self, stack: usize, value: fn() -> RunCode) {
self.function_stack[stack].push(value);
}

/// Creates new function stack.
fn new_stack(&mut self) {
self.function_stack.push(vec![]);
}
}

fn test_hello() -> RunCode {
println!("Hello, World!");
RunCode::Ok
}
36 changes: 36 additions & 0 deletions src/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,55 @@
// created on 02/04/24 by Michael Ward
//

use macroquad::color::WHITE;
use macroquad::texture::load_texture;

// Namespaces
use super::entities::*;
use super::ui;
use super::Call;
// ---

pub mod map;

/// Bundled Collection of UI elements
pub struct Menu<'m> {
pub elements: Vec<Box<dyn ui::Ui + 'm>>,
}

impl Call for Menu<'_> {
/// Render elements contained in menu
fn call(&self) {
for element in &self.elements {
element.render();
}
}
}

/// Bundled collection of game elements.
/// Used to map out level layout
pub struct Level {
player: player::Player,
map: map::Map,
}

impl Level {
pub async fn new(path: &str) -> Self {
Level {
player: player::Player::new(
0.0,
0.0,
load_texture("assets/miku.png").await.unwrap(),
WHITE,
),
map: map::parse_config(path),
}
}
}

impl Call for Level {
fn call_mut(&mut self) {
self.map.call();
self.player.call_mut();
}
}
Loading

0 comments on commit 74c2d38

Please sign in to comment.