Fleshing out some resuable debugging systems and adding README docs
parent
0c61d5d5d6
commit
3a9fdf1c05
@ -0,0 +1,3 @@
|
||||
/target
|
||||
|
||||
.direnv/*
|
||||
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…
Reference in New Issue