Skip to content

Commit c0fb17e

Browse files
committed
sound effects, polish
1 parent 9f1b615 commit c0fb17e

14 files changed

+104
-12
lines changed

Cargo.toml

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
[package]
22
name = "lifecycler"
3-
version = "0.1.9"
3+
description = "Bevy Game Jam #5 submission. Terminal aquarium."
4+
version = "0.2.0"
45
edition = "2021"
56
license = "MIT OR Apache-2.0 OR CC0-1.0"
7+
authors = ["cxreiff <[email protected]>"]
8+
readme = "README.md"
9+
repository = "https://github.com/cxreiff/lifecycler"
10+
categories = ["games", "command-line-interface"]
11+
keywords = ["bevy", "ratatui", "terminal", "tui", "aquarium"]
12+
include = ["/src", "/assets"]
613

714
[dependencies]
815
bevy = "0.14.0"

assets/bubble.ogg

4.55 KB
Binary file not shown.

assets/frame.glb

353 KB
Binary file not shown.

assets/gravel.glb

0 Bytes
Binary file not shown.

assets/off.ogg

7.46 KB
Binary file not shown.

assets/on.ogg

7.78 KB
Binary file not shown.

src/camera.rs

+21-3
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@ use bevy::{core_pipeline::bloom::BloomSettings, prelude::*};
22
use bevy_atmosphere::plugin::AtmosphereCamera;
33
use bevy_ratatui_render::RatatuiRenderContext;
44

5-
const LIGHT_INTENSITY_DAYTIME: f32 = 800_000.;
5+
use crate::{general::play_sfx, Flags};
6+
7+
const LIGHT_INTENSITY_DAYTIME: f32 = 500_000.;
68
const LIGHT_INTENSITY_NIGHTTIME: f32 = 500_000.;
79

810
const LIGHT_COLOR_DAYTIME: Color = Color::hsl(190., 0.5, 1.0);
911
const LIGHT_COLOR_NIGHTTIME: Color = Color::hsl(36., 0.2, 0.5);
1012

11-
const LIGHT_TRANSLATION_DAYTIME: Vec3 = Vec3::new(2., 3., 5.);
13+
const LIGHT_TRANSLATION_DAYTIME: Vec3 = Vec3::new(1.7, 2.5, 5.);
1214
const LIGHT_TRANSLATION_NIGHTTIME: Vec3 = Vec3::new(0., -2.5, 5.);
1315

1416
pub(super) fn plugin(app: &mut App) {
15-
app.add_systems(Startup, setup_camera_system)
17+
app.add_systems(Startup, (setup_camera_system, setup_sfx_system))
1618
.add_systems(Update, toggle_daylight_system)
1719
.add_event::<DaylightEvent>();
1820
}
@@ -23,6 +25,12 @@ pub struct Daylight;
2325
#[derive(Event, Default)]
2426
pub struct DaylightEvent;
2527

28+
#[derive(Resource, Deref)]
29+
pub struct ClickOnSound(Handle<AudioSource>);
30+
31+
#[derive(Resource, Deref)]
32+
pub struct ClickOffSound(Handle<AudioSource>);
33+
2634
fn setup_camera_system(mut commands: Commands, ratatui_render: Res<RatatuiRenderContext>) {
2735
commands.spawn((
2836
Camera3dBundle {
@@ -53,22 +61,32 @@ fn setup_camera_system(mut commands: Commands, ratatui_render: Res<RatatuiRender
5361
));
5462
}
5563

64+
fn setup_sfx_system(mut commands: Commands, asset_server: Res<AssetServer>) {
65+
commands.insert_resource(ClickOnSound(asset_server.load("on.ogg")));
66+
commands.insert_resource(ClickOffSound(asset_server.load("off.ogg")));
67+
}
68+
5669
fn toggle_daylight_system(
5770
mut commands: Commands,
5871
camera_query: Query<(Entity, Option<&AtmosphereCamera>), With<Camera>>,
5972
mut light_query: Query<(&mut PointLight, &mut Transform), With<Daylight>>,
6073
mut daylight_events: EventReader<DaylightEvent>,
74+
flags: Res<Flags>,
75+
on_click: Res<ClickOnSound>,
76+
off_click: Res<ClickOffSound>,
6177
) {
6278
for _ in daylight_events.read() {
6379
let (camera, atmosphere) = camera_query.single();
6480
let (mut light, mut light_transform) = light_query.single_mut();
6581

6682
if atmosphere.is_some() {
83+
play_sfx(&mut commands, &off_click, &flags);
6784
commands.entity(camera).remove::<AtmosphereCamera>();
6885
light.intensity = LIGHT_INTENSITY_NIGHTTIME;
6986
light.color = LIGHT_COLOR_NIGHTTIME;
7087
light_transform.translation = LIGHT_TRANSLATION_NIGHTTIME;
7188
} else {
89+
play_sfx(&mut commands, &on_click, &flags);
7290
commands.entity(camera).insert(AtmosphereCamera::default());
7391
light.intensity = LIGHT_INTENSITY_DAYTIME;
7492
light.color = LIGHT_COLOR_DAYTIME;

src/creatures/behavior.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bevy::ecs::query::QueryEntityError;
22
use bevy::prelude::*;
3-
use rand::SeedableRng;
3+
use rand::{RngCore, SeedableRng};
44
use rand_chacha::ChaCha8Rng;
55

66
use crate::pellets::Pellet;
@@ -11,6 +11,7 @@ pub(super) fn plugin(app: &mut App) {
1111
app.init_resource::<CreatureRng>();
1212
}
1313

14+
#[derive(Debug)]
1415
pub enum CreatureBehaviorVariant {
1516
Debut,
1617
Idle,
@@ -66,12 +67,17 @@ pub trait CreatureOperations {
6667
self.clamp();
6768
}
6869

69-
fn decide_behavior(&mut self, time: &Time, _rng: &mut CreatureRng) {
70+
fn decide_behavior(&mut self, time: &Time, rng: &mut CreatureRng) {
7071
self.behavior().timer.tick(time.delta());
7172

7273
if self.behavior().timer.just_finished() {
7374
match self.behavior().variant {
7475
CreatureBehaviorVariant::Idle => {
76+
if rng.next_u32() % 9 == 0 {
77+
self.start_seek_point(rng);
78+
return;
79+
}
80+
7581
let current_y = self.transform().rotation.y;
7682
self.face_left();
7783
if self.transform().rotation.y != current_y {
@@ -223,6 +229,7 @@ pub trait CreatureOperations {
223229
max - Self::valid_point_buffer(),
224230
)
225231
.sample_interior(&mut rng.0)
232+
+ min.midpoint(max)
226233
}
227234

228235
fn valid_point_buffer() -> Vec3 {

src/draw.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ fn draw_scene_system(
3636
let _msg = &flags.msg;
3737
let position = Rect::new(
3838
(frame.size().width / 2 + frame.size().width.min(frame.size().height * 2) / 2)
39-
.saturating_sub(13),
40-
1,
41-
11,
39+
.saturating_sub(11 + if flags.muted { 8 } else { 0 }),
40+
1 + (frame.size().height * 2).saturating_sub(frame.size().width) / 4,
41+
9,
4242
1,
4343
);
4444
let fps = Text::raw(format!(" fps: {value:.0} "))
@@ -49,6 +49,22 @@ fn draw_scene_system(
4949
frame.render_widget(fps, position);
5050
}
5151
}
52+
53+
if flags.muted {
54+
let position = Rect::new(
55+
(frame.size().width / 2 + frame.size().width.min(frame.size().height * 2) / 2)
56+
.saturating_sub(9),
57+
1 + (frame.size().height * 2).saturating_sub(frame.size().width) / 4,
58+
7,
59+
1,
60+
);
61+
let fps = Text::raw(" muted ")
62+
.alignment(Alignment::Center)
63+
.bg(ratatui::style::Color::White)
64+
.fg(ratatui::style::Color::Black);
65+
66+
frame.render_widget(fps, position);
67+
}
5268
})?;
5369

5470
Ok(())

src/general.rs

+11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use bevy::prelude::*;
22

3+
use crate::Flags;
4+
35
pub(super) fn plugin(app: &mut App) {
46
app.add_systems(PostUpdate, deferred_despawn_system);
57
}
@@ -17,3 +19,12 @@ fn deferred_despawn_system(
1719
}
1820
}
1921
}
22+
23+
pub fn play_sfx(commands: &mut Commands, source: &Handle<AudioSource>, flags: &Flags) {
24+
if !flags.muted {
25+
commands.spawn(AudioBundle {
26+
source: source.clone(),
27+
settings: PlaybackSettings::DESPAWN,
28+
});
29+
}
30+
}

src/input.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use crossterm::event::{KeyCode, KeyEventKind, MouseButton, MouseEventKind};
77

88
use crate::{camera::DaylightEvent, pellets::PelletEvent, Flags};
99

10+
const DRAGS_PER_EVENT: u32 = 2;
11+
1012
pub(super) fn plugin(app: &mut App) {
1113
app.add_systems(PreUpdate, (handle_keyboard_system, handle_mouse_system))
1214
.init_resource::<DragThreshold>();
@@ -31,6 +33,10 @@ fn handle_keyboard_system(
3133
flags.debug = !flags.debug;
3234
}
3335

36+
KeyCode::Char('m') => {
37+
flags.muted = !flags.muted;
38+
}
39+
3440
_ => {}
3541
},
3642
_ => {}
@@ -61,7 +67,7 @@ fn handle_mouse_system(
6167
{
6268
pellet_event.send(PelletEvent(transform));
6369
}
64-
**drag_threshold = 1;
70+
**drag_threshold = DRAGS_PER_EVENT;
6571
} else {
6672
**drag_threshold -= 1;
6773
}

src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::time::Duration;
22

33
use bevy::{
4-
app::ScheduleRunnerPlugin, diagnostic::FrameTimeDiagnosticsPlugin, prelude::*,
4+
app::ScheduleRunnerPlugin, diagnostic::FrameTimeDiagnosticsPlugin, log::LogPlugin, prelude::*,
55
window::ExitCondition,
66
};
77
use bevy_atmosphere::plugin::AtmospherePlugin;
@@ -30,6 +30,10 @@ impl Plugin for AppPlugin {
3030
primary_window: None,
3131
exit_condition: ExitCondition::DontExit,
3232
close_when_requested: false,
33+
})
34+
.set(LogPlugin {
35+
level: bevy::log::Level::ERROR,
36+
..default()
3337
}),
3438
EmbeddedAssetPlugin::default(),
3539
ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(1. / 90.)),
@@ -61,5 +65,6 @@ impl Plugin for AppPlugin {
6165
#[derive(Resource, Default)]
6266
pub struct Flags {
6367
debug: bool,
68+
muted: bool,
6469
msg: String,
6570
}

src/pellets.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ use rand_chacha::{
55
ChaCha8Rng,
66
};
77

8+
use crate::{general::play_sfx, Flags};
9+
810
pub(super) fn plugin(app: &mut App) {
9-
app.add_systems(Startup, setup_pellets_system)
11+
app.add_systems(Startup, (setup_pellets_system, setup_sfx_system))
1012
.add_systems(
1113
Update,
1214
(
@@ -43,6 +45,9 @@ pub struct Perishable(Timer);
4345
#[derive(Event, Deref)]
4446
pub struct PelletEvent(pub Transform);
4547

48+
#[derive(Resource, Deref)]
49+
pub struct PelletSound(Handle<AudioSource>);
50+
4651
fn setup_pellets_system(
4752
mut commands: Commands,
4853
mut meshes: ResMut<Assets<Mesh>>,
@@ -68,19 +73,28 @@ fn setup_pellets_system(
6873
commands.insert_resource(PelletRng(seeded_rng));
6974
}
7075

76+
fn setup_sfx_system(mut commands: Commands, asset_server: Res<AssetServer>) {
77+
commands.insert_resource(PelletSound(asset_server.load("bubble.ogg")));
78+
}
79+
7180
fn create_pellets_system(
7281
mut commands: Commands,
82+
flags: Res<Flags>,
7383
mut pellet_events: EventReader<PelletEvent>,
7484
mut pellet_rng: ResMut<PelletRng>,
7585
pellet_mesh: Res<PelletMesh>,
7686
pellet_materials: Res<PelletMaterials>,
87+
pellet_sound: Res<PelletSound>,
7788
) {
7889
for mouse_position in pellet_events.read() {
7990
let fall_target = Vec3::new(
8091
mouse_position.translation.x.clamp(-1.75, 1.75),
8192
-1.7,
8293
pellet_rng.next_u32() as f32 / u32::MAX as f32 * 0.75 - 0.25,
8394
);
95+
96+
play_sfx(&mut commands, &pellet_sound, &flags);
97+
8498
commands.spawn((
8599
Pellet,
86100
PelletFalling(fall_target),

src/tank.rs

+8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ fn setup_tank_system(
3838
..default()
3939
});
4040

41+
commands.spawn(SceneBundle {
42+
transform: Transform::from_scale(Vec3::new(2., 2., 0.6))
43+
.with_translation(Vec3::new(0., 0.0, 0.))
44+
.with_rotation(Quat::from_rotation_x(0.)),
45+
scene: asset_server.load(GltfAssetLabel::Scene(0).from_asset("embedded://frame.glb")),
46+
..default()
47+
});
48+
4149
let coral_bundle = PbrBundle {
4250
transform: Transform::IDENTITY
4351
.with_scale(Vec3::splat(0.35))

0 commit comments

Comments
 (0)