Skip to content

Commit

Permalink
add more animations to attacks
Browse files Browse the repository at this point in the history
  • Loading branch information
asafigan committed Aug 29, 2022
1 parent 8bb9a6c commit 9e006a5
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 16 deletions.
Binary file added assets/particles/star_06.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
153 changes: 151 additions & 2 deletions src/battle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ use bevy::{
prelude::*,
render::{camera::ScalingMode, view::RenderLayers},
};
use bevy_tweening::{
lens::TransformPositionLens, Animator, Delay, EaseFunction, Tween, TweeningType,
};
use iyes_loopless::prelude::*;
use strum::{EnumCount, IntoEnumIterator};
use strum_macros::{Display, EnumCount, EnumIter, EnumVariantNames};

use crate::{
board::{BoardPrefab, BoardState, Element, Match},
board::{
BoardPrefab, BoardState, Element, Match, Tile, BETWEEN_MATCH_DELAY, MATCH_START_DELAY,
},
cards::{CardsPrefab, CardsState},
particles::ParticleEmitter,
player::{Player, Spell},
prefab::{spawn, Prefab},
transitions::{FadeScreenPrefab, TransitionDirection, TransitionEnd},
Expand Down Expand Up @@ -50,14 +56,17 @@ impl Plugin for BattlePlugin {
ConditionSet::new()
.run_in_state(BattleState::PlayerTurn)
.with_system(track_matches)
.with_system(animate_matches)
.with_system(start_outtro)
.with_system(kill_enemies)
.with_system(end_player_turn.run_in_state(BoardState::End))
.into(),
)
.add_enter_system(
BoardState::End,
player_attack.run_in_state(BattleState::PlayerTurn),
player_attack
.chain(animate_attack)
.run_in_state(BattleState::PlayerTurn),
)
.add_enter_system(BattleState::EnemyTurn, enemies_attack)
.add_system_set(
Expand Down Expand Up @@ -301,6 +310,146 @@ fn track_matches(mut events: EventReader<Match>, mut matches: ResMut<Matches>) {
matches.0.extend(events.iter().cloned());
}

fn animate_matches(
mut events: EventReader<Match>,
mut commands: Commands,
tiles: Query<&GlobalTransform, With<Tile>>,
mut materials: ResMut<Assets<StandardMaterial>>,
asset_server: Res<AssetServer>,
player: Res<Player>,
) {
if let Some(spell) = player.active_spell.as_ref() {
let start_delay = Duration::from_secs_f32(MATCH_START_DELAY);
let delay_between_matches = Duration::from_secs_f32(BETWEEN_MATCH_DELAY);

let mut delay = start_delay;
for event in events
.iter()
.filter(|x| spell.elements.contains(&x.element))
{
let material = materials.add(StandardMaterial {
base_color: event.element.color(),
base_color_texture: Some(asset_server.load("particles/star_06.png")),
double_sided: true,
unlit: true,
alpha_mode: AlphaMode::Blend,
..default()
});

for tile in &event.tiles {
let transform = tiles.get(*tile).unwrap();

let transform = transform.compute_transform() * Transform::from_xyz(0.0, 0.0, 1.0);
commands
.spawn_bundle(SpatialBundle {
transform,
..default()
})
.insert(BOARD_LAYER)
.insert(DelayedDespawn::from_seconds(0.7))
.insert(Animator::new(Delay::new(delay).then(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_secs_f32(0.5),
TransformPositionLens {
start: transform.translation,
end: Vec3::new(0.0, -2.5, 1.0),
},
))))
.with_children(|c| {
c.spawn_bundle(SpatialBundle::default())
.insert(ParticleEmitter {
material: material.clone(),
timer: Timer::from_seconds(1.0 / 200.0, true),
size_range: 0.2..0.3,
velocity_range: -0.01..0.01,
lifetime_range: 0.5..1.0,
particles_track: true,
});

c.spawn_bundle(SpatialBundle::default())
.insert(ParticleEmitter {
material: material.clone(),
timer: Timer::from_seconds(1.0 / 100.0, true),
size_range: 0.2..0.3,
velocity_range: -0.01..0.01,
lifetime_range: 0.2..0.5,
particles_track: false,
});
});

delay += delay_between_matches;
}
}
}
}

fn animate_attack(
matches: Res<Matches>,
mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>,
asset_server: Res<AssetServer>,
player: Res<Player>,
) {
if let Some(spell) = player.active_spell.as_ref() {
for event in matches
.0
.iter()
.filter(|x| spell.elements.contains(&x.element))
{
let material = materials.add(StandardMaterial {
base_color: event.element.color(),
base_color_texture: Some(asset_server.load("particles/star_06.png")),
double_sided: true,
unlit: true,
alpha_mode: AlphaMode::Blend,
..default()
});

for _ in &event.tiles {
let transform = Transform::from_xyz(0.0, -2.5, 1.0);
commands
.spawn_bundle(SpatialBundle {
transform,
..default()
})
.insert(BOARD_LAYER)
.insert(DelayedDespawn::from_seconds(0.7))
.insert(Animator::new(Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_secs_f32(0.5),
TransformPositionLens {
start: transform.translation,
end: Vec3::new(0.0, 2.1, 1.0),
},
)))
.with_children(|c| {
c.spawn_bundle(SpatialBundle::default())
.insert(ParticleEmitter {
material: material.clone(),
timer: Timer::from_seconds(1.0 / 200.0, true),
size_range: 0.2..0.3,
velocity_range: -0.01..0.01,
lifetime_range: 0.5..1.0,
particles_track: true,
});

c.spawn_bundle(SpatialBundle::default())
.insert(ParticleEmitter {
material: material.clone(),
timer: Timer::from_seconds(1.0 / 100.0, true),
size_range: 0.2..0.3,
velocity_range: -0.01..0.01,
lifetime_range: 0.2..0.5,
particles_track: false,
});
});
}
}
}
}

fn player_attack(
mut enemies: Query<(&mut Enemy, &mut EnemyAnimator, &EnemyAnimations)>,
mut animation_players: Query<&mut AnimationPlayer>,
Expand Down
7 changes: 5 additions & 2 deletions src/board.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,13 @@ fn match_gems(
events.send_batch(matches.into_iter());
}

pub const MATCH_START_DELAY: f32 = 0.1;
pub const BETWEEN_MATCH_DELAY: f32 = 0.1;

fn destroy_matches(mut events: EventReader<Match>, tiles: Query<&Tile>, mut commands: Commands) {
let start_delay = Duration::from_secs_f32(0.1);
let start_delay = Duration::from_secs_f32(MATCH_START_DELAY);
let delay_between_gems = Duration::from_secs_f32(0.0);
let delay_between_matches = Duration::from_secs_f32(0.2);
let delay_between_matches = Duration::from_secs_f32(BETWEEN_MATCH_DELAY);
let animation_time = Duration::from_secs_f32(0.1);

let mut delay = start_delay;
Expand Down
11 changes: 7 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@ use board::{BoardPlugin, BoardState};
use cards::{CardPlugin, CardsState};
use iyes_loopless::prelude::*;
use main_state::{MainState, MainStatePlugin};
use particles::ParticlesPlugin;
use std::{fmt::Debug, hash::Hash};
use transitions::TransitionPlugin;
use utils::UtilsPlugin;

#[cfg(target_arch = "wasm32")]
mod wasm;

mod battle;
mod board;
mod cards;
mod main_state;
mod particles;
mod player;
mod prefab;
mod transitions;
mod tween_untils;
mod ui;
mod utils;

#[cfg(target_arch = "wasm32")]
mod wasm;
pub mod utils;

pub fn build_app() -> App {
let mut app = App::new();
Expand Down Expand Up @@ -51,6 +53,7 @@ pub fn build_app() -> App {
.add_plugin(BattlePlugin)
.add_plugin(TransitionPlugin)
.add_plugin(MainStatePlugin)
.add_plugin(ParticlesPlugin)
.add_system(log_states::<BoardState>)
.add_system(log_states::<BattleState>)
.add_system(log_states::<MainState>)
Expand Down
104 changes: 104 additions & 0 deletions src/particles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use std::ops::Range;

use bevy::{
pbr::{NotShadowCaster, NotShadowReceiver},
prelude::*,
render::view::RenderLayers,
};

use crate::utils::square_mesh;

pub struct ParticlesPlugin;

impl Plugin for ParticlesPlugin {
fn build(&self, app: &mut App) {
app.add_system(emit_particles).add_system(move_particles);
}
}

#[derive(Component)]
pub struct Particle {
pub lifetime: Timer,
pub velocity: Vec3,
}

#[derive(Component)]
pub struct ParticleEmitter {
pub material: Handle<StandardMaterial>,
pub timer: Timer,
pub size_range: Range<f32>,
pub velocity_range: Range<f32>,
// in seconds
pub lifetime_range: Range<f32>,
pub particles_track: bool,
}

fn emit_particles(
mut emitters: Query<(
Entity,
&mut ParticleEmitter,
&GlobalTransform,
Option<&RenderLayers>,
)>,
mut commands: Commands,
time: Res<Time>,
) {
let mut rng = fastrand::Rng::new();
for (entity, mut emitter, transform, render_layers) in &mut emitters {
for _ in 0..(emitter.timer.tick(time.delta()).times_finished_this_tick()) {
let lifetime = random_in_range(&emitter.lifetime_range, &mut rng);
let size = random_in_range(&emitter.size_range, &mut rng);
let velocity = Vec2::new(
random_in_range(&emitter.velocity_range, &mut rng),
random_in_range(&emitter.velocity_range, &mut rng),
)
.extend(0.0);

let particle = commands
.spawn_bundle(PbrBundle {
mesh: square_mesh(),
material: emitter.material.clone(),
transform: if emitter.particles_track {
default()
} else {
transform.compute_transform()
}
.with_scale(Vec3::splat(size)),
..default()
})
.insert(Particle {
lifetime: Timer::from_seconds(lifetime, false),
velocity,
})
.insert(NotShadowCaster)
.insert(NotShadowReceiver)
.id();

if emitter.particles_track {
commands.entity(entity).add_child(particle);
}

if let Some(render_layers) = render_layers {
commands.entity(particle).insert(*render_layers);
}
}
}
}

fn random_in_range(range: &Range<f32>, rng: &mut fastrand::Rng) -> f32 {
rng.f32() * (range.end - range.start) + range.start
}

fn move_particles(
mut particles: Query<(Entity, &mut Particle, &mut Transform)>,
mut commands: Commands,
time: Res<Time>,
) {
for (entity, mut particle, mut transform) in &mut particles {
if particle.lifetime.tick(time.delta()).finished() {
commands.entity(entity).despawn();
} else {
transform.translation += particle.velocity;
}
}
}
28 changes: 20 additions & 8 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{hash::Hash, time::Duration};

use bevy::{
asset::HandleId,
ecs::system::AsSystemLabel,
ecs::{query::QueryEntityError, system::AsSystemLabel},
pbr::{NotShadowCaster, NotShadowReceiver},
prelude::{shape::Quad, *},
reflect::TypeUuid,
Expand All @@ -24,12 +24,20 @@ impl Plugin for UtilsPlugin {
.add_event::<WorldCursorEvent>()
.add_startup_system(add_meshes)
.add_startup_system(add_materials)
.add_system(delayed_despawn)
.add_stage_before(
CoreStage::PostUpdate,
"delayed_despawn",
SystemStage::parallel(),
)
.add_system_to_stage("delayed_despawn", delayed_despawn)
.add_system_to_stage(
CoreStage::PostUpdate,
update_progress.before(TransformSystem::TransformPropagate),
)
.add_system_to_stage(CoreStage::PostUpdate, propagate_render_layers)
.add_system_to_stage(
"delayed_despawn",
propagate_render_layers.before(delayed_despawn),
)
.add_system_to_stage(CoreStage::PreUpdate, update_world_cursors)
.add_system_to_stage(
CoreStage::PreUpdate,
Expand Down Expand Up @@ -153,12 +161,16 @@ fn propagate_render_layers(

while !children.is_empty() {
for child in std::mem::take(&mut children) {
if let Ok(mut child_layer) = layers.get_mut(child) {
if *child_layer != layer {
*child_layer = layer;
match layers.get_mut(child) {
Ok(mut child_layer) => {
if *child_layer != layer {
*child_layer = layer;
}
}
} else {
commands.entity(child).insert(layer);
Err(QueryEntityError::QueryDoesNotMatch(entity)) => {
commands.entity(entity).insert(layer);
}
_ => {}
}

children.extend(children_query.get(child).into_iter().flatten().cloned());
Expand Down

0 comments on commit 9e006a5

Please sign in to comment.