Skip to content

Instantly share code, notes, and snippets.

@IronGremlin
Last active September 29, 2023 19:42
Show Gist options
  • Save IronGremlin/7916e8f11e34c2629a35a9eb8d6ed6cd to your computer and use it in GitHub Desktop.
Save IronGremlin/7916e8f11e34c2629a35a9eb8d6ed6cd to your computer and use it in GitHub Desktop.
Example
use std::time::Duration;
use bevy::prelude::*;
use crate::SimState;
#[derive(Resource)]
pub struct GameClock {
delta: Duration,
// We store this here so that the user can pause/unpause separately from incremently advancing our scalar all the way back down/up from 0.
resume_speed: TickRate
}
impl Default for GameClock {
fn default() -> Self {
GameClock { delta: Duration::new(0, 0), resume_speed: TickRate::Standard }
}
}
#[derive(Component)]
pub struct SimTimer {
pub time: Timer
}
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
pub enum TickRate {
#[default]
Paused,
Standard,
X2,
X4
}
pub struct GameTimerPlugin;
const BASE_TICK_RATE: f32 = 1.0;
impl Plugin for GameTimerPlugin {
fn build(&self, app: &mut App) {
app
.insert_resource(GameClock::default())
.add_state::<TickRate>()
.add_systems(OnEnter(SimState::Playing),resume_when_sim_resumes)
.add_systems(OnEnter(SimState::Paused),pause_when_sim_pauses)
.add_systems(Update, (advance_scaled_time, tick_sim_timers))
.add_systems(Update, adjust_sim_speed);
}
}
fn scaled_time(rate: &TickRate, duration: Duration ) -> Duration {
let scalar :f32 = match rate {
TickRate::Paused => 0.0,
TickRate::Standard => 1.0,
TickRate::X2 => 2.0,
TickRate::X4 => 4.0
};
Duration::from_secs_f32(scalar * duration.as_secs_f32() * BASE_TICK_RATE)
}
fn pause_when_sim_pauses(mut rate : ResMut<NextState<TickRate>>, current_rate: Res<State<TickRate>>, mut timer: ResMut<GameClock>) {
// we treat "paused" as a valid rate to record - this is intentional, because if the player were to open a menu or do anything else that causes out of band
// sim halt while the sim clock is manually paused, we should not surprise the player by returning them to an unpaused sim once that state is exited.
timer.resume_speed = current_rate.get().clone();
rate.set(TickRate::Paused);
}
fn resume_when_sim_resumes(mut rate : ResMut<NextState<TickRate>>, timer: Res<GameClock>) {
rate.set(timer.resume_speed.clone());
}
fn advance_scaled_time(time: Res<Time>, mut game_time: ResMut<GameClock>, rate: Res<State<TickRate>>) {
let elapsed = scaled_time(rate.get(),time.delta());
game_time.delta = elapsed;
}
fn tick_sim_timers(time: Res<GameClock>, mut simtimers : Query<&mut SimTimer>) {
for mut simtimer in simtimers.iter_mut() {
simtimer.time.tick(time.delta);
}
}
fn adjust_sim_speed(input: Res<Input<KeyCode>>, mut rate : ResMut<NextState<TickRate>>, current_rate: Res<State<TickRate>>) {
if input.pressed(KeyCode::Comma) {
rate.set(slower_rate(&current_rate.get()))
}
if (input.pressed(KeyCode::Period)) {
rate.set(faster_rate(&current_rate.get()))
}
}
fn faster_rate(rate: &TickRate) -> TickRate {
match rate {
TickRate::Paused => TickRate::Standard,
TickRate::Standard => TickRate::X2,
TickRate::X2 => TickRate::X4,
TickRate::X4 => TickRate::X4,
_ => TickRate::Paused
}
}
fn slower_rate(rate: &TickRate) -> TickRate {
match rate {
TickRate::Paused => TickRate::Paused,
TickRate::Standard => TickRate::Paused,
TickRate::X2 => TickRate::Standard,
TickRate::X4 => TickRate::X2,
_ => TickRate::Paused
}
}
#[derive(Component)]
pub struct Lifespan;
pub struct EatenFood(i32);
#[derive(Component)]
pub struct PassiveHunger {
stomach: EatenFood
}
fn cull_mortals(mut commands: Commands, mortals: Query<(&Parent, &SimTimer), With<Lifespan>>) {
for (parent, age) in mortals.iter() {
if age.time.finished() {
commands.entity(parent.get()).despawn_recursive();
}
}
}
fn cull_starving(mut commands: Commands, hungry: Query<(&Parent, &PassiveHunger)>) {
for (parent, hunger) in hungry.iter() {
if hunger.stomach.0 <= 0 {
commands.entity(parent.get()).despawn_recursive();
}
}
}
fn apply_hunger(mut hungry: Query<(&mut PassiveHunger, &SimTimer)>) {
for (mut hunger, timer) in hungry.iter_mut() {
if timer.time.finished() {
hunger.stomach.0 -= 1;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment