mod castles;
mod pools;
mod signposts;
mod statics;
mod surround;
mod tide;
pub use castles::{
CastleFlight, CastleKick, CastleSprite, castle_body, cheer_tier_ups, crown_the_leader,
flinch_castles, fly_castles, kick_castles, steady_castle_shadows, sync_castles, wave_pennants,
};
pub(crate) use castles::{castle_parts, kick_keep};
pub use pools::ripple_pools;
pub(crate) use pools::{POOL_LAYERS, spawn_glint, spawn_layer};
pub use signposts::{SignpostSprite, dress_signposts, sync_signposts};
pub use statics::{
BoardStatic, TurnstileSprite, animate_turnstiles, pulse_spawners, spawn_board_grid,
spawn_static_board, sync_turnstiles,
};
pub use surround::{drift_cloud_shadows, lay_the_sea, sea_uniform};
pub(crate) type LiveBoard = (
BoardStatic,
CastleSprite,
CastleKick,
castles::CastleFlinch,
TurnstileSprite,
SignpostSprite,
statics::SpawnerSprite,
pools::PoolRipple,
);
pub fn spawn_board_pieces(
commands: &mut Commands,
board: &crate::sim::Board,
art: &crate::app::art::Art,
) {
use crate::sim::TileKind;
for (x, y, kind) in board.tiles() {
match kind {
TileKind::Castle(owner) => {
castles::spawn_castle(commands, art, board, (x, y), owner);
}
TileKind::Turnstile { next_right } => {
statics::spawn_log(commands, art, board, (x, y), next_right);
}
TileKind::Empty
| TileKind::Rock
| TileKind::Spawner(_)
| TileKind::Kelp
| TileKind::Pool => {}
}
if let Some(sp) = board.signpost_at(x, y) {
signposts::spawn_signpost(commands, art, board, (x, y), sp);
}
}
}
use crate::app::layout::image_sprite;
use bevy::prelude::*;
pub(super) struct Caster {
pub footprint: f32,
pub height: f32,
pub alpha: f32,
}
pub(super) fn cast_shadow(
art: &crate::app::art::Art,
at: Vec3,
caster: Caster,
) -> (Sprite, Transform) {
let Caster {
footprint,
height,
alpha,
} = caster;
let sun = crate::app::layout::SUN.normalize();
let ground = at.truncate() + crate::app::layout::SUN + sun * height;
(
image_sprite(
&art.shadow,
Color::srgba(1.0, 1.0, 1.0, alpha),
Vec2::new(footprint * 1.15, footprint * 0.55),
),
Transform::from_translation(ground.extend(at.z))
.with_rotation(Quat::from_rotation_z(sun.y.atan2(sun.x))),
)
}
fn on_board(board: &crate::sim::Board, x: u8, y: u8) -> bool {
x < board.width() && y < board.height()
}
trait OnTile {
fn tile(&self) -> (u8, u8);
}
fn clear_stale<S: OnTile, T: std::ops::Deref<Target = S>>(
commands: &mut Commands,
board: &crate::sim::Board,
covered: &mut Vec<bool>,
sprites: impl IntoIterator<Item = (Entity, T)>,
mut current: impl FnMut(&mut T) -> bool,
) {
covered.clear();
covered.resize(board.width() as usize * board.height() as usize, false);
for (entity, mut sprite) in sprites {
let (x, y) = sprite.tile();
if !on_board(board, x, y) {
commands.entity(entity).despawn();
continue;
}
if current(&mut sprite) {
covered[usize::from(board.index_of(x, y))] = true;
} else {
commands.entity(entity).despawn();
}
}
}
const WALL_COLOR: Color = Color::srgb(0.35, 0.28, 0.22);
pub(crate) const RIM: f32 = 51.0;
pub(crate) const FENCE_DEPTH: f32 = 13.0;
pub(super) use crate::app::layout::z;