Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ This template comes with a basic project structure that you may find useful:

| Path | Description |
| -------------------------------------------------- | ------------------------------------------------------------------ |
| [`src/lib.rs`](./src/lib.rs) | App setup |
| [`src/main.rs`](./src/main.rs) | App setup |
| [`src/asset_tracking.rs`](./src/asset_tracking.rs) | A high-level way to load collections of asset handles as resources |
| [`src/audio.rs`](./src/audio.rs) | Marker components for sound effects and music |
| [`src/demo/`](./src/demo) | Example game mechanics & content (replace with your own code) |
| [`src/dev_tools.rs`](./src/dev_tools.rs) | Dev tools for dev builds (press \` aka backtick to toggle) |
| [`src/screens/`](./src/screens) | Splash screen, title screen, gameplay screen, etc. |
| [`src/demo/`](./src/demo) | Example game mechanics & content (replace with your own code) |
| [`src/menus/`](./src/menus) | Main menu, pause menu, settings menu, etc. |
| [`src/screens/`](./src/screens) | Splash screen, title screen, loading screen, etc. |
| [`src/theme/`](./src/theme) | Reusable UI widgets & theming |

Feel free to move things around however you want, though.
Expand Down Expand Up @@ -141,4 +142,4 @@ The CC0 license explicitly does not waive patent rights, but we confirm that we

## Credits

The [assets](./assets) in this repository are all 3rd-party. See the [credits screen](./src/screens/credits.rs) for more information.
The [assets](./assets) in this repository are all 3rd-party. See the [credits menu](./src/menus/credits.rs) for more information.
3 changes: 1 addition & 2 deletions docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ pub enum Screen {
Splash,
Loading,
Title,
Credits,
Gameplay,
Victory,
Leaderboard,
Expand Down Expand Up @@ -137,7 +136,7 @@ fn enter_title_screen(mut next_state: ResMut<NextState<Screen>>) {

### Reasoning

"Screen" is not meant as the physical screen, but as "what kind of screen is the game showing right now", e.g. the title screen, the loading screen, the credits screen, the victory screen, etc.
"Screen" is not meant as the physical screen, but as "what kind of screen is the game showing right now", e.g. the title screen, the loading screen, the victory screen, etc.
These screens usually correspond to different logical states of your game that have different systems running.

By using a dedicated `State` type for your screens, you can easily manage systems and entities that are only relevant for a specific screen and flexibly transition between
Expand Down
1 change: 0 additions & 1 deletion post-generate.rhai
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ file::rename(".github/workflows/release.yaml.template", ".github/workflows/relea
file::rename("Cargo.toml.template", "Cargo.toml");
file::rename("README.md.template", "README.md");
file::rename("src/main.rs.template", "src/main.rs");
file::rename("src/lib.rs.template", "src/lib.rs");

// Generate `Cargo.lock`.
system::command("cargo", ["update", "--package", variable::get("project-name")]);
90 changes: 0 additions & 90 deletions src/lib.rs.template

This file was deleted.

2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod audio;
mod demo;
#[cfg(feature = "dev")]
mod dev_tools;
mod menus;
mod screens;
mod theme;

Expand Down Expand Up @@ -62,6 +63,7 @@ impl Plugin for AppPlugin {
demo::plugin,
#[cfg(feature = "dev")]
dev_tools::plugin,
menus::plugin,
screens::plugin,
theme::plugin,
));
Expand Down
85 changes: 81 additions & 4 deletions src/main.rs.template
Original file line number Diff line number Diff line change
@@ -1,11 +1,88 @@
// Disable console on Windows for non-dev builds.
#![cfg_attr(not(feature = "dev"), windows_subsystem = "windows")]
// Support configuring Bevy lints within code.
#![cfg_attr(bevy_lint, feature(register_tool), register_tool(bevy))]
// Disable console on Windows for non-dev builds.
#![cfg_attr(not(feature = "dev"), windows_subsystem = "windows")]

use bevy::prelude::*;
use {{crate_name}}::AppPlugin;
mod asset_tracking;
mod audio;
mod demo;
#[cfg(feature = "dev")]
mod dev_tools;
mod menus;
mod screens;
mod theme;

use bevy::{asset::AssetMetaCheck, prelude::*};

fn main() -> AppExit {
App::new().add_plugins(AppPlugin).run()
}

pub struct AppPlugin;

impl Plugin for AppPlugin {
fn build(&self, app: &mut App) {
// Order new `AppSystems` variants by adding them here:
app.configure_sets(
Update,
(
AppSystems::TickTimers,
AppSystems::RecordInput,
AppSystems::Update,
)
.chain(),
);

// Spawn the main camera.
app.add_systems(Startup, spawn_camera);

// Add Bevy plugins.
app.add_plugins(
DefaultPlugins
.set(AssetPlugin {
// Wasm builds will check for meta files (that don't exist) if this isn't set.
// This causes errors and even panics on web build on itch.
// See https://github.com/bevyengine/bevy_github_ci_template/issues/48.
meta_check: AssetMetaCheck::Never,
..default()
})
.set(WindowPlugin {
primary_window: Window {
title: "{{project-name | title_case}}".to_string(),
fit_canvas_to_parent: true,
..default()
}
.into(),
..default()
}),
);

// Add other plugins.
app.add_plugins((
asset_tracking::plugin,
demo::plugin,
#[cfg(feature = "dev")]
dev_tools::plugin,
menus::plugin,
screens::plugin,
theme::plugin,
));
}
}

/// High-level groupings of systems for the app in the `Update` schedule.
/// When adding a new variant, make sure to order it in the `configure_sets`
/// call above.
#[derive(SystemSet, Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)]
enum AppSystems {
/// Tick timers.
TickTimers,
/// Record player input.
RecordInput,
/// Do everything else (consider splitting this into further variants).
Update,
}

fn spawn_camera(mut commands: Commands) {
commands.spawn((Name::new("Camera"), Camera2d));
}
34 changes: 22 additions & 12 deletions src/screens/credits.rs → src/menus/credits.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
//! A credits screen that can be accessed from the title screen.
//! The credits menu.

use bevy::{ecs::spawn::SpawnIter, prelude::*, ui::Val::*};
use bevy::{
ecs::spawn::SpawnIter, input::common_conditions::input_just_pressed, prelude::*, ui::Val::*,
};

use crate::{asset_tracking::LoadResource, audio::music, screens::Screen, theme::prelude::*};
use crate::{asset_tracking::LoadResource, audio::music, menus::Menu, theme::prelude::*};

pub(super) fn plugin(app: &mut App) {
app.add_systems(OnEnter(Screen::Credits), spawn_credits_screen);
app.add_systems(OnEnter(Menu::Credits), spawn_credits_menu);
app.add_systems(
Update,
go_back.run_if(in_state(Menu::Credits).and(input_just_pressed(KeyCode::Escape))),
);

app.register_type::<CreditsAssets>();
app.load_resource::<CreditsAssets>();
app.add_systems(OnEnter(Screen::Credits), start_credits_music);
app.add_systems(OnEnter(Menu::Credits), start_credits_music);
}

fn spawn_credits_screen(mut commands: Commands) {
fn spawn_credits_menu(mut commands: Commands) {
commands.spawn((
widget::ui_root("Credits Screen"),
StateScoped(Screen::Credits),
widget::ui_root("Credits Menu"),
StateScoped(Menu::Credits),
children![
widget::header("Created by"),
created_by(),
widget::header("Assets"),
assets(),
widget::button("Back", enter_title_screen),
widget::button("Back", go_back_on_click),
],
));
}
Expand Down Expand Up @@ -73,8 +79,12 @@ fn grid(content: Vec<[&'static str; 2]>) -> impl Bundle {
)
}

fn enter_title_screen(_: Trigger<Pointer<Click>>, mut next_screen: ResMut<NextState<Screen>>) {
next_screen.set(Screen::Title);
fn go_back_on_click(_: Trigger<Pointer<Click>>, mut next_menu: ResMut<NextState<Menu>>) {
next_menu.set(Menu::Main);
}

fn go_back(mut next_menu: ResMut<NextState<Menu>>) {
next_menu.set(Menu::Main);
}

#[derive(Resource, Asset, Clone, Reflect)]
Expand All @@ -96,7 +106,7 @@ impl FromWorld for CreditsAssets {
fn start_credits_music(mut commands: Commands, credits_music: Res<CreditsAssets>) {
commands.spawn((
Name::new("Credits Music"),
StateScoped(Screen::Credits),
StateScoped(Menu::Credits),
music(credits_music.music.clone()),
));
}
54 changes: 54 additions & 0 deletions src/menus/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//! The main menu (seen on the title screen).

use bevy::prelude::*;

use crate::{asset_tracking::ResourceHandles, menus::Menu, screens::Screen, theme::widget};

pub(super) fn plugin(app: &mut App) {
app.add_systems(OnEnter(Menu::Main), spawn_main_menu);
}

fn spawn_main_menu(mut commands: Commands) {
commands.spawn((
widget::ui_root("Main Menu"),
StateScoped(Menu::Main),
#[cfg(not(target_family = "wasm"))]
children![
widget::button("Play", enter_loading_or_gameplay_screen),
widget::button("Settings", open_settings_menu),
widget::button("Credits", open_credits_menu),
widget::button("Exit", exit_app),
],
#[cfg(target_family = "wasm")]
children![
widget::button("Play", enter_loading_or_gameplay_screen),
widget::button("Settings", open_settings_menu),
widget::button("Credits", open_credits_menu),
],
));
}

fn enter_loading_or_gameplay_screen(
_: Trigger<Pointer<Click>>,
resource_handles: Res<ResourceHandles>,
mut next_screen: ResMut<NextState<Screen>>,
) {
if resource_handles.is_all_done() {
next_screen.set(Screen::Gameplay);
} else {
next_screen.set(Screen::Loading);
}
}

fn open_settings_menu(_: Trigger<Pointer<Click>>, mut next_menu: ResMut<NextState<Menu>>) {
next_menu.set(Menu::Settings);
}

fn open_credits_menu(_: Trigger<Pointer<Click>>, mut next_menu: ResMut<NextState<Menu>>) {
next_menu.set(Menu::Credits);
}

#[cfg(not(target_family = "wasm"))]
fn exit_app(_: Trigger<Pointer<Click>>, mut app_exit: EventWriter<AppExit>) {
app_exit.write(AppExit::Success);
}
Loading