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 = {
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
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 }:
|
outputs =
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
{
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (
|
||||||
|
system:
|
||||||
let
|
let
|
||||||
systems = ["x86_64-linux"];
|
overlays = [ ];
|
||||||
overlays = [
|
pkgs = import nixpkgs {
|
||||||
(import rust-overlay)
|
|
||||||
wild.overlays.default
|
|
||||||
];
|
|
||||||
wildStdenv = pkgs.useWildLinker pkgs.stdenv;
|
|
||||||
pkgs = (import nixpkgs) {
|
|
||||||
inherit system overlays;
|
inherit system overlays;
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
};
|
||||||
naersk' = pkgs.callPackage naersk { };
|
|
||||||
buildInputs = with pkgs; [
|
|
||||||
vulkan-loader
|
|
||||||
xorg.libXcursor
|
|
||||||
xorg.libXi
|
|
||||||
xorg.libXrandr
|
|
||||||
libxkbcommon
|
|
||||||
wayland
|
|
||||||
alsa-lib
|
|
||||||
udev
|
|
||||||
pkg-config
|
|
||||||
clang
|
|
||||||
lld
|
|
||||||
mold
|
|
||||||
binaryen
|
|
||||||
];
|
|
||||||
nativeBuildInputs = with pkgs; [
|
|
||||||
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" ];
|
|
||||||
}))
|
|
||||||
];
|
|
||||||
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
|
in
|
||||||
rec {
|
{
|
||||||
# For `nix build` & `nix run`:
|
devShells.default =
|
||||||
defaultPackage = packages.bevy_template { stdenv = wildStdenv; };
|
with pkgs;
|
||||||
packages = rec {
|
mkShell {
|
||||||
bevy_template = naersk'.buildPackage {
|
buildInputs =
|
||||||
src = ./.;
|
[
|
||||||
nativeBuildInputs = nativeBuildInputs;
|
pkg-config
|
||||||
buildInputs = buildInputs;
|
# for Linux
|
||||||
postInstall = ''
|
# Audio (Linux only)
|
||||||
cp -r assets $out/bin/
|
alsa-lib
|
||||||
'';
|
# Cross Platform 3D Graphics API
|
||||||
# Disables dynamic linking when building with Nix
|
vulkan-loader
|
||||||
cargoBuildOptions = x: x ++ [ "--no-default-features" ];
|
# For debugging around vulkan
|
||||||
|
vulkan-tools
|
||||||
|
# Other dependencies
|
||||||
|
libudev-zero
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXcursor
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libXrandr
|
||||||
|
libxkbcommon
|
||||||
|
# Fast linker
|
||||||
|
clang
|
||||||
|
mold
|
||||||
|
# Rustup
|
||||||
|
rustup
|
||||||
|
wayland # To use the wayland feature
|
||||||
|
];
|
||||||
|
LD_LIBRARY_PATH = lib.makeLibraryPath [
|
||||||
|
alsa-lib
|
||||||
|
libxkbcommon
|
||||||
|
udev
|
||||||
|
vulkan-loader
|
||||||
|
wayland
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXcursor
|
||||||
|
xorg.libXi
|
||||||
|
];
|
||||||
|
CARGO_TARGET_DIR = "/home/pop/.cargo/target";
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
# 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}"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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