From 17c7989450889d8be71f50ae33748142e2671c1a Mon Sep 17 00:00:00 2001 From: SecretPocketCat Date: Thu, 19 Oct 2023 23:42:56 +0200 Subject: [PATCH 01/14] add virtual_time example --- Cargo.toml | 36 +++++- examples/README.md | 7 ++ examples/time/virtual_time.rs | 201 ++++++++++++++++++++++++++++++++++ 3 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 examples/time/virtual_time.rs diff --git a/Cargo.toml b/Cargo.toml index 02de4c4115c57..57ca4f5082519 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,11 @@ bevy_asset = ["bevy_internal/bevy_asset"] bevy_audio = ["bevy_internal/bevy_audio"] # Provides cameras and other basic render pipeline features -bevy_core_pipeline = ["bevy_internal/bevy_core_pipeline", "bevy_asset", "bevy_render"] +bevy_core_pipeline = [ + "bevy_internal/bevy_core_pipeline", + "bevy_asset", + "bevy_render", +] # Plugin for dynamic loading (using [libloading](https://crates.io/crates/libloading)) bevy_dynamic_plugin = ["bevy_internal/bevy_dynamic_plugin"] @@ -83,7 +87,12 @@ bevy_gilrs = ["bevy_internal/bevy_gilrs"] bevy_gltf = ["bevy_internal/bevy_gltf", "bevy_asset", "bevy_scene", "bevy_pbr"] # Adds PBR rendering -bevy_pbr = ["bevy_internal/bevy_pbr", "bevy_asset", "bevy_render", "bevy_core_pipeline"] +bevy_pbr = [ + "bevy_internal/bevy_pbr", + "bevy_asset", + "bevy_render", + "bevy_core_pipeline", +] # Provides rendering functionality bevy_render = ["bevy_internal/bevy_render"] @@ -98,7 +107,12 @@ bevy_sprite = ["bevy_internal/bevy_sprite", "bevy_render", "bevy_core_pipeline"] bevy_text = ["bevy_internal/bevy_text", "bevy_asset", "bevy_sprite"] # A custom ECS-driven UI framework -bevy_ui = ["bevy_internal/bevy_ui", "bevy_core_pipeline", "bevy_text", "bevy_sprite"] +bevy_ui = [ + "bevy_internal/bevy_ui", + "bevy_core_pipeline", + "bevy_text", + "bevy_sprite", +] # winit window and input backend bevy_winit = ["bevy_internal/bevy_winit"] @@ -113,7 +127,11 @@ trace_chrome = ["trace", "bevy_internal/trace_chrome"] trace_tracy = ["trace", "bevy_internal/trace_tracy"] # Tracing support, with memory profiling, exposing a port for Tracy -trace_tracy_memory = ["trace", "bevy_internal/trace_tracy", "bevy_internal/trace_tracy_memory"] +trace_tracy_memory = [ + "trace", + "bevy_internal/trace_tracy", + "bevy_internal/trace_tracy_memory", +] # Tracing support trace = ["bevy_internal/trace"] @@ -1408,6 +1426,16 @@ description = "Explains how Time is handled in ECS" category = "ECS (Entity Component System)" wasm = false +[[example]] +name = "virtual_time" +path = "examples/time/virtual_time.rs" + +[package.metadata.example.virtual_time] +name = "Virtual time" +description = "Shows how `Time` can be used to pause, resume, slow down and speed up a game." +category = "Time" +wasm = false + [[example]] name = "timers" path = "examples/ecs/timers.rs" diff --git a/examples/README.md b/examples/README.md index a54765b500e0c..7026a337abf29 100644 --- a/examples/README.md +++ b/examples/README.md @@ -53,6 +53,7 @@ git checkout v0.4.0 - [Scene](#scene) - [Shaders](#shaders) - [Stress Tests](#stress-tests) + - [Time](#time) - [Tools](#tools) - [Transforms](#transforms) - [UI (User Interface)](#ui-user-interface) @@ -325,6 +326,12 @@ Example | Description [Text Pipeline](../examples/stress_tests/text_pipeline.rs) | Text Pipeline benchmark [Transform Hierarchy](../examples/stress_tests/transform_hierarchy.rs) | Various test cases for hierarchy and transform propagation performance +## Time + +Example | Description +--- | --- +[Virtual time](../examples/time/virtual_time.rs) | Shows how `Time` can be used to pause, resume, slow down and speed up a game. + ## Tools Example | Description diff --git a/examples/time/virtual_time.rs b/examples/time/virtual_time.rs new file mode 100644 index 0000000000000..1c7592f0766b0 --- /dev/null +++ b/examples/time/virtual_time.rs @@ -0,0 +1,201 @@ +//! Shows how `Time` can be used to pause, resume, slow down +//! and speed up a game. + +use std::time::Duration; + +use bevy::{input::common_conditions::input_just_pressed, prelude::*}; +use bevy_internal::{math::bool, time::common_conditions::on_timer, window::WindowResolution}; + +fn main() { + App::new() + .insert_resource(ClearColor(Color::DARK_GRAY)) + .add_plugins(DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + resizable: false, + resolution: WindowResolution::new(WINDOW_WIDTH, WINDOW_HEIGTH), + ..default() + }), + ..default() + })) + .add_systems(Startup, setup) + .add_systems( + Update, + ( + move_virtual_time_sprites, + move_real_time_sprites, + toggle_pause.run_if(input_just_pressed(KeyCode::Space)), + change_time_speed::<1>.run_if(input_just_pressed(KeyCode::Up)), + change_time_speed::<-1>.run_if(input_just_pressed(KeyCode::Down)), + (update_virtual_time_text, update_real_time_text) + .run_if(on_timer(Duration::from_millis(250))), + ), + ) + .run(); +} + +const WINDOW_WIDTH: f32 = 1000.; +const WINDOW_HEIGTH: f32 = 600.; + +#[derive(Component)] +struct RealTime; + +#[derive(Component)] +struct VirtualTime; + +fn setup(mut commands: Commands, asset_server: Res) { + commands.spawn(Camera2dBundle::default()); + + let virtual_color = Color::GOLD; + let sprite_scale = Vec2::splat(0.5).extend(1.); + let texture_handle = asset_server.load("branding/icon.png"); + + // the sprite moving based on real time + commands.spawn(( + SpriteBundle { + texture: texture_handle.clone(), + transform: Transform::from_scale(sprite_scale), + ..default() + }, + RealTime, + )); + + // the sprite moving based on virtual time + commands.spawn(( + SpriteBundle { + texture: texture_handle, + sprite: Sprite { + color: virtual_color, + ..default() + }, + transform: Transform { + scale: sprite_scale, + translation: Vec3::new(0., -160., 0.), + ..default() + }, + ..default() + }, + VirtualTime, + )); + + // info UI + let font_size = 40.; + + commands + .spawn(NodeBundle { + style: Style { + display: Display::Flex, + justify_content: JustifyContent::SpaceBetween, + width: Val::Percent(100.), + position_type: PositionType::Absolute, + top: Val::Px(0.), + padding: UiRect::all(Val::Px(20.0)), + ..default() + }, + ..default() + }) + .with_children(|builder| { + // real time info + builder.spawn(( + TextBundle::from_section( + "", + TextStyle { + font_size, + ..default() + }, + ), + RealTime, + )); + + // keybindings + builder.spawn( + TextBundle::from_section( + "CONTROLS\nUn/Pause: Space\nSpeed+: +/Up\nSpeed-: -/Down", + TextStyle { + font_size, + color: Color::rgb(0.7, 0.7, 0.7), + ..default() + }, + ) + .with_text_alignment(TextAlignment::Center), + ); + + // virtual time info + builder.spawn(( + TextBundle::from_section( + "", + TextStyle { + font_size, + color: virtual_color, + ..default() + }, + ) + .with_text_alignment(TextAlignment::Right), + VirtualTime, + )); + }); +} + +fn move_real_time_sprites( + mut sprite_query: Query<&mut Transform, (With, With)>, + time: Res>, +) { + for mut transform in sprite_query.iter_mut() { + transform.translation.x = get_sprite_translation_x(time.elapsed_seconds()); + } +} + +fn move_virtual_time_sprites( + mut sprite_query: Query<&mut Transform, (With, With)>, + // in Update systems this's Time so scaling (todo: whatever is the proper name, also type ref) and applies meaning + time: Res