use super::{WATER, WATER_MAX, image_sprite, z};
use crate::app::Sim;
use crate::app::art::Art;
use crate::app::layout::TILE;
use crate::sim::TideEvent;
use bevy::prelude::*;
#[derive(Component)]
pub struct Waterline(pub u8);
pub fn spawn_waterline(commands: &mut Commands) {
for side in 0..4u8 {
commands.spawn((
Waterline(side),
Sprite::from_color(WATER, Vec2::ZERO),
Transform::from_translation(Vec3::new(0.0, 0.0, z::WATER)),
));
}
}
pub fn update_waterline(
sim: Res<Sim>,
time: Res<Time>,
mut bars: Query<(&Waterline, &mut Sprite, &mut Transform)>,
) {
let board = &sim.0;
let Some(remaining) = board.remaining_ticks() else {
for (_, mut sprite, _) in &mut bars {
sprite.custom_size = Some(Vec2::ZERO);
}
return;
};
let total = board.ticks() + remaining;
let elapsed = 1.0 - remaining as f32 / total.max(1) as f32;
let mut depth = 6.0 + elapsed * WATER_MAX;
if board.in_surge() && !board.round_over() {
depth += (time.elapsed_secs() * 6.0).sin() * 3.0;
}
let w = f32::from(board.width()) * TILE;
let h = f32::from(board.height()) * TILE;
for (bar, mut sprite, mut transform) in &mut bars {
let (size, pos) = match bar.0 {
0 => (
Vec2::new(w + depth * 2.0, depth),
Vec2::new(0.0, (h + depth) / 2.0),
),
1 => (
Vec2::new(w + depth * 2.0, depth),
Vec2::new(0.0, -(h + depth) / 2.0),
),
2 => (Vec2::new(depth, h), Vec2::new(-(w + depth) / 2.0, 0.0)),
_ => (Vec2::new(depth, h), Vec2::new((w + depth) / 2.0, 0.0)),
};
sprite.custom_size = Some(size);
transform.translation = pos.extend(z::WATER);
}
}
#[derive(Component)]
pub struct WaterFoam(pub u8);
pub fn spawn_water_foam(commands: &mut Commands, art: &Art) {
for side in 0..4u8 {
commands.spawn((
WaterFoam(side),
image_sprite(&art.foam, Color::WHITE, Vec2::ZERO),
Transform::from_translation(Vec3::new(0.0, 0.0, z::FOAM)),
));
}
}
pub fn update_water_foam(
sim: Res<Sim>,
time: Res<Time>,
mut bars: Query<(&Waterline, &mut Sprite), Without<WaterFoam>>,
mut foam: Query<(&WaterFoam, &mut Sprite, &mut Transform)>,
) {
let board = &sim.0;
let mania_tint = match board.last_event() {
Some((TideEvent::CrabMania, at)) if board.ticks().saturating_sub(at) < 300 => {
Some(Color::srgba(0.35, 0.72, 0.55, 0.65))
}
Some((TideEvent::GullMania, at)) if board.ticks().saturating_sub(at) < 300 => {
Some(Color::srgba(0.35, 0.38, 0.48, 0.7))
}
_ => None,
};
for (_, mut sprite) in &mut bars {
let target = mania_tint.unwrap_or(WATER);
if sprite.color != target {
sprite.color = target;
}
}
let Some(remaining) = board.remaining_ticks() else {
for (_, mut sprite, _) in &mut foam {
if sprite.custom_size != Some(Vec2::ZERO) {
sprite.custom_size = Some(Vec2::ZERO);
}
}
return;
};
let total = board.ticks() + remaining;
let elapsed = 1.0 - remaining as f32 / total.max(1) as f32;
let mut depth = 6.0 + elapsed * WATER_MAX;
if board.in_surge() && !board.round_over() {
depth += (time.elapsed_secs() * 6.0).sin() * 3.0;
}
let lap = (time.elapsed_secs() * 1.8).sin() * 1.5;
let w = f32::from(board.width()) * TILE;
let h = f32::from(board.height()) * TILE;
const FOAM: f32 = 7.0;
for (bar, mut sprite, mut transform) in &mut foam {
let (size, pos, rot) = match bar.0 {
0 => (
Vec2::new(w + depth * 2.0, FOAM),
Vec2::new(0.0, h / 2.0 + depth - lap),
0.0,
),
1 => (
Vec2::new(w + depth * 2.0, FOAM),
Vec2::new(0.0, -h / 2.0 - depth + lap),
std::f32::consts::PI,
),
2 => (
Vec2::new(h, FOAM),
Vec2::new(-w / 2.0 - depth + lap, 0.0),
-std::f32::consts::FRAC_PI_2,
),
_ => (
Vec2::new(h, FOAM),
Vec2::new(w / 2.0 + depth - lap, 0.0),
std::f32::consts::FRAC_PI_2,
),
};
sprite.custom_size = Some(size);
transform.translation = pos.extend(z::FOAM);
transform.rotation = Quat::from_rotation_z(rot);
}
}