In a good-ish spot, going to save

main
Elijah C. Voigt 2 years ago
parent f0a64541e1
commit 609ae8ebb9

@ -33,7 +33,7 @@ invalid = "/sfx/3D/3DInvalidMove"
# Options: Off, Sample2, Sample4, Sample8
# Requires: display3d.ssoa.quality_level = "Off"
###
msaa = "Off"
msaa = "Sample4"
###
# Enable HDR lighting
@ -62,8 +62,8 @@ valid_move = "Valid Move Spot"
[display3d.models.animations]
intro_a = "GameCamIntro1"
intro_b = "GameCamIntro2"
turn_a = "GameCamSide2>1"
turn_b = "GameCamSide1>2"
turn_b = "GameCamSide2>1"
turn_a = "GameCamSide1>2"
[display3d.models.animations.pick_up]
pawn = "PawnPiecePickup"
@ -113,7 +113,7 @@ Rgba = { red = 1.0, green = 1.0, blue = 1.0, alpha = 0.0 }
# https://docs.rs/bevy/0.11.3/bevy/pbr/enum.FogFalloff.html
###
[display3d.fog.falloff]
Exponential = { density = 0.000 }
Exponential = { density = 1.0 }
# Examples:
# * Linear = { start = 1.0, end = 10.0 }
# * Exponential = { density = 1.0 }

@ -36,7 +36,7 @@ impl Plugin for AudioPlugin {
#[derive(Event, Debug, PartialEq, Component, Clone)]
pub enum AudioEvent {
MainMusic,
StopMainMusic,
_StopMainMusic,
MenuHover,
MenuSelect,
PickUp,
@ -56,7 +56,7 @@ fn play_audio(mut events: Query<&AudioSource, Added<AudioSource>>) {
fn audio_trigger(
mut events: EventReader<AudioEvent>,
sources: Query<(&AudioSource, &AudioEvent)>,
sources: Query<(Entity, &AudioSource, &AudioEvent)>,
studio: Res<FmodStudio>,
mut commands: Commands,
server: Res<AssetServer>,
@ -69,7 +69,7 @@ fn audio_trigger(
let state = display_state.get();
events.read().for_each(|event| {
let aud = match event {
AudioEvent::MainMusic | AudioEvent::StopMainMusic => {
AudioEvent::MainMusic | AudioEvent::_StopMainMusic => {
tweak.get::<String>("audio_music_main").unwrap()
}
AudioEvent::MenuHover => tweak.get::<String>("audio_menu_hover").unwrap(),
@ -79,7 +79,7 @@ fn audio_trigger(
AudioEvent::Idle | AudioEvent::StopIdle => tweak.get::<String>("audio_display3d_idle").unwrap(),
AudioEvent::Invalid => tweak.get::<String>("audio_display3d_invalid").unwrap(),
};
// There is an event for this
// There is an event, play an audio
if !aud.is_empty() {
let event_str = format!("event:{}", aud);
if let Ok(event_description) = studio.0.get_event(event_str.as_str()) {
@ -90,25 +90,28 @@ fn audio_trigger(
AudioEvent::StopIdle => {
sources
.iter()
.filter(|(_, source_event)| **source_event == AudioEvent::Idle)
.for_each(|(source, _)| {
.filter(|(_, _, source_event)| **source_event == AudioEvent::Idle)
.for_each(|(entity, source, _)| {
info!("Stopping audio {}", event_str);
source.stop();
commands.entity(entity).despawn_recursive();
});
}
// Find and stop playing instances of main music
AudioEvent::StopMainMusic => {
AudioEvent::_StopMainMusic => {
sources
.iter()
.filter(|(_, source_event)| **source_event == AudioEvent::MainMusic)
.for_each(|(source, _)| {
.filter(|(_, _, source_event)| **source_event == AudioEvent::MainMusic)
.for_each(|(entity, source, _)| {
info!("Stopping audio {}", event_str);
source.stop();
commands.entity(entity).despawn_recursive();
});
}
// we are playing a sound
_ => {
info!("Playing audio {}", event_str);
// TODO: Can we batch spawn all sounds at startup? Then Start/Stop/Reset at runtime?
commands.spawn((audio_source, event.clone()));
}
}

@ -32,7 +32,7 @@ impl Plugin for Display3dPlugin {
.insert_resource(Msaa::Off)
.add_systems(
OnExit(GameState::Loading),
(initialize, fix_skybox.before(initialize)),
(initialize, fix_skybox.before(initialize), update_tweaks.run_if(resource_exists::<tweak::GameTweaks>()),),
)
.add_systems(
Update,
@ -44,9 +44,10 @@ impl Plugin for Display3dPlugin {
set_piece_model.run_if(any_component_added::<Piece>),
set_board_model.run_if(any_component_added::<game::BoardComponent>),
set_board_model.run_if(any_component_added::<TilesComponent>),
set_valid_move_model.run_if(any_component_added::<game::ValidMove>),
set_tile_hitbox.run_if(any_component_added::<game::Tile>),
set_piece_position.run_if(any_component_changed::<BoardIndex>),
set_piece_texture.run_if(any_component_changed::<Side>),
set_piece_texture.run_if(any_component_changed::<Side>).run_if(resource_exists::<tweak::GameTweaks>()),
select
.run_if(in_state(GameState::Play))
.run_if(in_state(DisplayState::Display3d))
@ -56,8 +57,7 @@ impl Plugin for Display3dPlugin {
switch_sides
.run_if(in_state(GameState::Play))
.run_if(state_changed::<game::TurnState>()),
set_valid_move_model.run_if(any_component_added::<game::ValidMove>),
update_tweaks.run_if(on_event::<AssetEvent<Tweaks>>()),
update_tweaks.run_if(on_event::<AssetEvent<Tweaks>>()).run_if(resource_exists::<tweak::GameTweaks>()),
scale_lighting.run_if(
any_component_added::<DirectionalLight>
.or_else(any_component_added::<SpotLight>)
@ -84,11 +84,10 @@ impl Plugin for Display3dPlugin {
OnEnter(DisplayState::Display3d),
(
activate::<Display3d>,
set_piece_texture,
set_piece_texture.run_if(resource_exists::<tweak::GameTweaks>()),
opening_animation
.run_if(run_once())
.run_if(in_state(GameState::Play)),
update_tweaks,
),
)
.add_systems(OnExit(DisplayState::Display3d), deactivate::<Display3d>)
@ -97,6 +96,7 @@ impl Plugin for Display3dPlugin {
(
activate::<Display3d>.run_if(in_state(DisplayState::Display3d)),
set_piece_texture,
update_tweaks.run_if(resource_exists::<tweak::GameTweaks>()),
opening_animation
.run_if(run_once())
.run_if(in_state(DisplayState::Display3d)),
@ -160,6 +160,8 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
// Hitboxes
game::tiles().for_each(|(index, tile)| {
let side = Board::side(index).expect("Spawn valid side");
parent.spawn((
Display3d,
index,
@ -170,12 +172,15 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
visibility: Visibility::Hidden,
..default()
},
side,
game::Selectable,
));
});
// Valid move indicators
game::tiles().for_each(|(index, _)| {
let side = Board::side(index).expect("Spawn valid side");
parent.spawn((
Display3d,
index,
@ -184,6 +189,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
transform: Transform::from_translation(board_translation(&index)),
..default()
},
side,
game::ValidMove,
));
});
@ -232,7 +238,7 @@ fn hydrate_camera(
DisplayState::Display3d,
Camera3dBundle {
camera: Camera {
is_active: false,
is_active: true,
hdr: tweak.get::<bool>("display3d_hdr").unwrap(),
..default()
},
@ -732,9 +738,10 @@ fn select(
meshes: Res<Assets<Mesh>>,
cameras: Query<(&Camera, &GlobalTransform)>,
windows: Query<&Window, With<PrimaryWindow>>,
selectable: Query<(Entity, &BoardIndex), (With<game::Selectable>, With<Display3d>)>,
selectable: Query<(Entity, &BoardIndex, &Side, Option<&Piece>), (With<game::Selectable>, With<Display3d>)>,
children: Query<&Children>,
mut selections: EventWriter<game::Selection>,
state: Res<State<game::TurnState>>,
) {
events
.read()
@ -753,15 +760,20 @@ fn select(
hit::intersects3d(&ray, mesh, &gt).and_then(|_hit| {
selectable
.iter()
.find_map(|(e, &board_index)| {
// A child was hit (pieces)
let primary = entity == e;
.find_map(|(e, &board_index, &side, piece_ish)| {
// Check if this piece is on the active side
let side_check = piece_ish.is_some() && *state.get() == side;
// This entity was hit (tile hitboxes)
let primary = entity == e;
// A child was hit (pieces)
let secondary = children
.iter_descendants(e)
.any(|child| child == entity);
(primary || secondary).then_some(board_index)
(side_check && (primary || secondary)).then_some(board_index)
})
.iter()
.for_each(|&board_index| {
@ -804,7 +816,7 @@ fn moves_gizmo(
}
fn set_valid_move_model(
mut events: Query<&mut Handle<Scene>, (With<Display3d>, Added<game::ValidMove>)>,
mut events: Query<(&mut Handle<Scene>, &mut Visibility), (With<Display3d>, Added<game::ValidMove>)>,
gltfs: Res<Assets<Gltf>>,
tweaks: Res<Assets<Tweaks>>,
tweaks_file: Res<tweak::GameTweaks>,
@ -816,7 +828,7 @@ fn set_valid_move_model(
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
if let Some(gltf) = gltfs.get(assets_handle) {
events.iter_mut().for_each(|mut handle| {
events.iter_mut().for_each(|(mut handle, mut visibility)| {
*handle = gltf
.named_scenes
.get(
@ -826,7 +838,9 @@ fn set_valid_move_model(
.as_str(),
)
.unwrap()
.clone()
.clone();
*visibility = Visibility::Hidden;
})
}
}

@ -12,6 +12,7 @@ impl Plugin for GamePlugin {
.add_state::<TurnState>()
.insert_resource(Score { ..default() })
.add_systems(Startup, setup_board)
.add_systems(OnEnter(GameState::Play), hide_valid_moves)
.add_systems(
Update,
(
@ -24,9 +25,6 @@ impl Plugin for GamePlugin {
buttons.just_pressed(MouseButton::Right)
}),
handle_selection.run_if(on_event::<Selection>()),
switch_sides.run_if(|input: Res<Input<KeyCode>>| -> bool {
input.just_pressed(KeyCode::N)
}),
show_valid_moves.run_if(any_component_added::<Selected>),
hide_valid_moves.run_if(any_component_removed::<Selected>()),
manage_score.run_if(any_component_added::<Captured>),
@ -45,11 +43,34 @@ impl Plugin for GamePlugin {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
pub(crate) enum TurnState {
#[default]
SideA,
// HACK: Opening animation starts on B side
#[default]
SideB,
}
impl std::ops::Not for TurnState {
type Output = Self;
fn not(self) -> Self::Output {
match self {
TurnState::SideA => TurnState::SideB,
TurnState::SideB => TurnState::SideA,
}
}
}
// Allow comparison between turn state and sides
impl PartialEq<Side> for TurnState {
fn eq(&self, other: &Side) -> bool {
match (self, other) {
(TurnState::SideA, Side::A) | (TurnState::SideB, Side::B) => true,
(TurnState::SideB, Side::A) | (TurnState::SideA, Side::B) => false,
}
}
}
#[derive(Debug, Component, Clone, PartialEq, Copy, Hash)]
pub(crate) enum Piece {
Pawn,
@ -481,18 +502,25 @@ pub(crate) fn update_board(
selected: Query<Entity, With<Selected>>,
mut commands: Commands,
mut played: Local<bool>,
curr_state: Res<State<TurnState>>,
mut next_state: ResMut<NextState<TurnState>>,
) {
events.read().for_each(|Move { from, to, .. }| {
pieces.iter_mut().for_each(|(entity, mut index)| {
if *index == *from {
match to {
Some(to_idx) => {
info!("Moving piece {:?} to {:?}", entity, to_idx);
info!("Moving piece {:?} {:?} -> {:?}", entity, from, to_idx);
*index = to_idx.clone();
if !(*played) {
audio_events.send(audio::AudioEvent::PutDown);
audio_events.send(audio::AudioEvent::StopIdle);
*played = true;
if *from != *to_idx {
let ns = !*curr_state.get() ;
info!("Piece moved, switching sides: {:?}", ns);
next_state.set(ns);
}
}
}
None => {
@ -650,26 +678,19 @@ fn asserts<T: Component>(
}
}
fn switch_sides(state: Res<State<TurnState>>, mut next: ResMut<NextState<TurnState>>) {
match state.get() {
TurnState::SideA => next.set(TurnState::SideB),
TurnState::SideB => next.set(TurnState::SideA),
}
}
/// Spawn "Valid move" indicators when a piece is selected
/// Another system registers these new entities and associates the correct models and plays animations.
fn show_valid_moves(
events: Query<&BoardIndex, (With<Piece>, Added<Selected>)>,
board: Res<Board>,
mut valid_moves: Query<(&BoardIndex, &mut Visibility), With<ValidMove>>,
mut indicators: Query<(&BoardIndex, &mut Visibility), With<ValidMove>>,
) {
// When a piece is selected
events.iter().for_each(|idx| {
// Iterate over all ValidMove entities
// For each one with a ValidMove index, make it visible
board.valid_moves(*idx).iter().for_each(|idx| {
valid_moves.iter_mut().for_each(|(i, mut vis)| {
indicators.iter_mut().for_each(|(i, mut vis)| {
if i == idx {
*vis = Visibility::Inherited;
}
@ -680,12 +701,9 @@ fn show_valid_moves(
/// Hide "Valid Move" indicators when a piece is de-selected
fn hide_valid_moves(
mut events: RemovedComponents<Selected>,
mut valid_moves: Query<&mut Visibility, With<ValidMove>>,
mut indicators: Query<&mut Visibility, With<ValidMove>>,
) {
events.read().for_each(|_| {
valid_moves.iter_mut().for_each(|mut visibility| {
*visibility = Visibility::Hidden;
});
indicators.iter_mut().for_each(|mut visibility| {
*visibility = Visibility::Hidden;
});
}

@ -1,8 +1,6 @@
use bevy::{
render::{
mesh::{MeshVertexAttribute, VertexAttributeValues},
render_resource::VertexFormat,
},
use bevy::render::{
mesh::{MeshVertexAttribute, VertexAttributeValues},
render_resource::VertexFormat,
};
use crate::prelude::*;

@ -101,7 +101,7 @@ fn toggle_display_camera(
}
fn activate<Marker: Component>(
mut entities: Query<&mut Visibility, (With<Marker>, Without<game::Captured>)>,
mut entities: Query<&mut Visibility, (With<Marker>, Without<game::Captured>, Without<game::ValidMove>)>,
) {
entities.iter_mut().for_each(|mut visibility| {
*visibility = Visibility::Visible;

@ -50,6 +50,16 @@ fn init_menu_ui(mut commands: Commands) {
},
))
.with_children(|parent| {
parent.spawn(
TextBundle::from_section(
"M A R T I A N C H E S S",
TextStyle {
font_size: 48.0,
color: Color::ORANGE_RED,
..default()
},
)
);
parent
.spawn((
GameState::Play,

Loading…
Cancel
Save