Fleshing out some resuable debugging systems and adding README docs

main
Elijah Voigt 4 months ago
parent 0c61d5d5d6
commit 3a9fdf1c05

3
.gitignore vendored

@ -0,0 +1,3 @@
/target
.direnv/*

5418
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,8 @@
[package]
name = "games"
version = "0.1.0"
edition = "2024"
[dependencies.bevy]
version = "0.16.1"
features = ["wayland", "dynamic_linking"]

@ -0,0 +1,40 @@
# Games by Elijah V.
This is a mono-repo I am working on containing many mini-games I am working on.
## Building a game
You can build games in this project with `cargo` provided by Rust:
```
$ cargo run --bin game-name-here
```
That builds and runs a lightly optimized (but still debug) build of the game.
For a fully optimized build add the `--release` flag:
```
$ cargo run --release --bin game-name-here
```
## Games in this project
All games can be found in the `src/bin/` folder.
There is a README in that folder with more info, and there should be a README in each subsequent game's folder with a rough design doc of that specific game.
## What about examples?
I also have some examples which are meant to test out specific code or mechanics.
The distinction is basically if it has a menu it's a game, if it just runs it's an example.
## Why a mono-repo?
For all of the reasons that mono-repos are good!
* Code can be re-used across multiple games easily.
* Code from one game can be easily referenced, copied, or forked.
* I can stare at my accomplishments in one place.
Mono-repos get a bad rap because they feel bloated, or can cause conflict when lots of people step on each other's toes.
I am a solo developer, so none of those are really problems for me.

@ -0,0 +1,13 @@
# Game Assets
This folder contains all assets across all games in the project.
## Project File + Output Files
All assets should be saved with a similarly named project file in addition to the output.
For example, if you are editing a file in Gimp:
* you should include `your-asset-name.xcf`
* as well as the resulting `your-asset-name.jpg`
This ensures if we need to make tweaks to an asset we have the "source" to do so.

@ -0,0 +1,13 @@
# Examples
As mentioned in the top level README, examples are used to exercise a specific feature or mechanic.
These are often used to isolate a problem and figure out a good solution before integrating it into a bigger game.
These are also almost always single file programs so you will see a bunch of `*.rs` files in this folder, each is a different example, not a module in one big example.
## Running examples
Something like this:
```
$ cargo run --example example-name-here
```

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1750506804,
"narHash": "sha256-VLFNc4egNjovYVxDGyBYTrvVCgDYgENp5bVi9fPTDYc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4206c4cb56751df534751b058295ea61357bbbaa",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

@ -1,86 +1,67 @@
{
description = "bevy flake";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
naersk.url = "github:nix-community/naersk";
rust-overlay.url = "github:oxalica/rust-overlay";
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
wild.url = "github:davidlattimore/wild";
};
outputs = { self, flake-utils, naersk, nixpkgs, rust-overlay, wild }:
flake-utils.lib.eachDefaultSystem (system:
outputs =
{
nixpkgs,
flake-utils,
...
}:
flake-utils.lib.eachDefaultSystem (
system:
let
systems = ["x86_64-linux"];
overlays = [
(import rust-overlay)
wild.overlays.default
];
wildStdenv = pkgs.useWildLinker pkgs.stdenv;
pkgs = (import nixpkgs) {
overlays = [ ];
pkgs = import nixpkgs {
inherit system overlays;
config.allowUnfree = true;
};
naersk' = pkgs.callPackage naersk { };
buildInputs = with pkgs; [
in
{
devShells.default =
with pkgs;
mkShell {
buildInputs =
[
pkg-config
# for Linux
# Audio (Linux only)
alsa-lib
# Cross Platform 3D Graphics API
vulkan-loader
# For debugging around vulkan
vulkan-tools
# Other dependencies
libudev-zero
xorg.libX11
xorg.libXcursor
xorg.libXi
xorg.libXrandr
libxkbcommon
wayland
alsa-lib
udev
pkg-config
# Fast linker
clang
lld
mold
binaryen
# Rustup
rustup
wayland # To use the wayland feature
];
nativeBuildInputs = with pkgs; [
LD_LIBRARY_PATH = lib.makeLibraryPath [
alsa-lib
libxkbcommon
(rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override {
extensions = [ "rust-src" "clippy" "rustc-codegen-cranelift-preview" ];
targets = [ "x86_64-unknown-linux-gnu" "wasm32-unknown-unknown" ];
}))
udev
vulkan-loader
wayland
xorg.libX11
xorg.libXcursor
xorg.libXi
];
all_deps = with pkgs; [
# cargo-expand
nixpkgs-fmt
cmake
wasm-pack
wasm-bindgen-cli
trunk
simple-http-server
zip
unzip
mdcat
rust-analyzer
] ++ buildInputs ++ nativeBuildInputs;
in
rec {
# For `nix build` & `nix run`:
defaultPackage = packages.bevy_template { stdenv = wildStdenv; };
packages = rec {
bevy_template = naersk'.buildPackage {
src = ./.;
nativeBuildInputs = nativeBuildInputs;
buildInputs = buildInputs;
postInstall = ''
cp -r assets $out/bin/
'';
# Disables dynamic linking when building with Nix
cargoBuildOptions = x: x ++ [ "--no-default-features" ];
};
};
# For `nix develop`:
devShell = pkgs.mkShell.override { stdenv = wildStdenv; } {
nativeBuildInputs = all_deps;
shellHook = ''
export CARGO_MANIFEST_DIR=$(pwd)
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${pkgs.lib.makeLibraryPath all_deps}"
'';
CARGO_TARGET_DIR = "/home/pop/.cargo/target";
};
}
);
}

@ -0,0 +1 @@
/nix/store/4qpbdnz6vq95fb63cr54z1vcpvbjkfq1-home-manager-generation

@ -0,0 +1,4 @@
[toolchain]
channel = "nightly-2025-06-16"
components = [ "rustfmt", "rustc-dev", "cargo", "clippy", "rust-analyzer", "rustc-codegen-cranelift" ]
targets = [ "x86_64-unknown-linux-gnu" ]

@ -0,0 +1,12 @@
use super::*;
/// A good starting place for creating a game building on top of the base Bevy app
pub struct BaseGamePlugin;
impl Plugin for BaseGamePlugin {
fn build(&self, app: &mut App) {
app.add_plugins(DefaultPlugins)
.add_plugins(DebuggingPlugin);
}
}

@ -0,0 +1,16 @@
use games::*;
fn main() {
App::new()
.add_plugins(BaseGamePlugin)
.add_systems(Update, (
f.run_if(any_component_added::<Foo>),
f.run_if(any_component_changed::<Foo>),
))
.run();
}
#[derive(Component)]
struct Foo;
fn f() { }

@ -0,0 +1,34 @@
use super::*;
/// Debugging systems, resources, events, etc.
pub struct DebuggingPlugin;
impl Plugin for DebuggingPlugin {
fn build(&self, app: &mut App) {
app.init_state::<DebuggingState>()
.add_systems(Update, toggle_debug_state.run_if(on_keyboard_press(KeyCode::F12)));
}
}
/// Tracks if the debugger is on or off for other games systems to hook into
///
/// The Debugging state may add it's own global debugging information, but is mostly a shell
#[derive(States, Debug, Default, Hash, Eq, PartialEq, Clone)]
pub enum DebuggingState {
#[default]
Off,
On,
}
/// Toggles the debug state from off -> on // off -> on when triggered
fn toggle_debug_state(
mut next: ResMut<NextState<DebuggingState>>,
curr: Res<State<DebuggingState>>,
) {
use DebuggingState::*;
next.set(match curr.get() {
On => Off,
Off => On,
});
}

@ -0,0 +1,9 @@
mod base_game;
mod debug;
mod scheduling;
pub use bevy::{prelude::*, input::{keyboard::KeyboardInput, ButtonState}};
pub use base_game::*;
pub use debug::*;
pub use scheduling::*;

@ -0,0 +1,18 @@
use super::*;
/// Scheduling condition for determining if a component has been added
pub fn any_component_added<T: Component>(q: Query<Entity, Added<T>>) -> bool {
!q.is_empty()
}
/// Scheduling condition for determining if a component has been changed
pub fn any_component_changed<T: Component>(q: Query<Entity, Changed<T>>) -> bool {
!q.is_empty()
}
/// Scheduling condition to trigger a system when a specific key is pressed
pub fn on_keyboard_press(key: KeyCode) -> impl FnMut(Res<ButtonInput<KeyCode>>) -> bool {
move |keys: Res<ButtonInput<KeyCode>>| {
keys.just_pressed(key)
}
}
Loading…
Cancel
Save