Add eating animation

This commit is contained in:
2022-08-21 21:41:35 +02:00
parent 0c59cfd898
commit 0140be1121
5 changed files with 105 additions and 7 deletions

17
Cargo.lock generated
View File

@@ -246,6 +246,7 @@ version = "0.1.0"
dependencies = [
"bevy",
"bevy_editor_pls",
"bevy_tweening",
"itertools",
"iyes_loopless",
"rand",
@@ -880,6 +881,16 @@ dependencies = [
"bevy_reflect",
]
[[package]]
name = "bevy_tweening"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "164bcb41708fa1aeb435b6bba6cae61777b9f8cf3e18b207bb6209ca5b970e77"
dependencies = [
"bevy",
"interpolation",
]
[[package]]
name = "bevy_ui"
version = "0.8.1"
@@ -2012,6 +2023,12 @@ dependencies = [
"web-sys",
]
[[package]]
name = "interpolation"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3b7357d2bbc5ee92f8e899ab645233e43d21407573cceb37fed8bc3dede2c02"
[[package]]
name = "io-kit-sys"
version = "0.2.0"

View File

@@ -11,6 +11,7 @@ itertools = "0.10.3"
# bevy-inspector-egui = "0.12.1"
rand = "0.8.5"
bevy_editor_pls = { git = "https://github.com/jakobhellermann/bevy_editor_pls" }
bevy_tweening = "0.5.0"
[dependencies.bevy]
version = "0.8.0"

View File

@@ -29,10 +29,7 @@ fn eaten_event_sent(mut eaten_event_reader: EventReader<EatenEvent>) -> bool {
eaten_event_reader.iter().count() != 0
}
fn spawn_fruit_system(
mut commands: Commands,
coordinate_query: Query<&grid::Coordinate>,
) {
fn spawn_fruit_system(mut commands: Commands, coordinate_query: Query<&grid::Coordinate>) {
fn random_coordinate() -> grid::Coordinate {
let mut rng = rand::thread_rng();
let coordinate_range = 0..grid::SIZE;
@@ -49,7 +46,7 @@ fn spawn_fruit_system(
.any(|&snake_coordinate| snake_coordinate == coordinate)
};
let fruit_coordinate = std::iter::repeat(random_coordinate())
let fruit_coordinate = std::iter::repeat_with(random_coordinate)
.find(|&coordinate| !coordinate_in_other_element(coordinate))
.expect("Should always be found.");

View File

@@ -3,6 +3,7 @@ use bevy::{prelude::*, render::camera::ScalingMode};
use bevy_editor_pls::prelude::*;
use grid::{SEGMENT_SIZE, SIZE};
use iyes_loopless::prelude::*;
use bevy_tweening::TweeningPlugin;
mod canvas;
mod fruit;
@@ -35,6 +36,7 @@ fn main() {
.add_loopless_state(AppState::Begin)
.add_plugins(DefaultPlugins)
.add_plugin(EditorPlugin)
.add_plugin(TweeningPlugin)
.add_plugin(TickPlugin)
.add_plugin(SnakePlugin)
.add_plugin(FruitPlugin)

View File

@@ -1,7 +1,9 @@
use crate::{fruit, grid, tick::tick_triggered, AppState};
use bevy::prelude::*;
use bevy_tweening::{lens::TransformScaleLens, *};
use itertools::Itertools;
use iyes_loopless::prelude::*;
use std::time::Duration;
#[derive(Debug, Clone, PartialEq, Eq, Hash, StageLabel)]
struct MovementStage;
@@ -17,7 +19,8 @@ impl Plugin for SnakePlugin {
fn build(&self, app: &mut App) {
let movement_stage = SystemStage::parallel();
app.add_startup_system(setup_snake_system)
app.insert_resource(BulgePropagationTimer::default())
.add_startup_system(setup_snake_system)
.add_stage_after(CoreStage::Update, MovementStage, movement_stage)
.add_system_to_stage(
MovementStage,
@@ -49,7 +52,10 @@ impl Plugin for SnakePlugin {
.add_system(add_direction_system.run_in_state(AppState::Begin))
.add_system(change_direction_system.run_in_state(AppState::InGame))
.add_system(grid_transform_system.run_in_state(AppState::InGame))
.add_system(add_tail_system);
.add_system(add_tail_system)
.add_system(add_bulge_system)
.add_system(propagate_bulge_system)
.add_system(animate_bulge_system);
}
}
@@ -78,6 +84,18 @@ struct Snake;
#[derive(Component)]
struct SnakeSegments(Vec<Entity>);
#[derive(Component)]
#[component(storage = "SparseSet")]
struct BulgeMarker;
struct BulgePropagationTimer(Timer);
impl Default for BulgePropagationTimer {
fn default() -> Self {
Self(Timer::new(Duration::from_millis(30), true))
}
}
impl SnakeSegments {
fn with_head(snake_head: Entity) -> Self {
Self(vec![snake_head])
@@ -167,6 +185,69 @@ fn add_tail_system(
}
}
fn add_bulge_system(
mut commands: Commands,
mut eaten_event_reader: EventReader<fruit::EatenEvent>,
query: Query<Entity, With<SnakeHead>>,
) {
for _ in eaten_event_reader.iter() {
let snake_head_entity = query.single();
commands.entity(snake_head_entity).insert(BulgeMarker);
}
}
fn propagate_bulge_system(
mut commands: Commands,
query: Query<(Entity, &Parent), (With<SnakeSegment>, With<BulgeMarker>)>,
snake_segments_query: Query<&SnakeSegments>,
time: Res<Time>,
mut timer: ResMut<BulgePropagationTimer>,
) {
timer.0.tick(time.delta());
if !timer.0.finished() {
return;
}
for (entity, parent) in query.iter() {
commands.entity(entity).remove::<BulgeMarker>();
let mut segment_iter = snake_segments_query.get(parent.get()).unwrap().0.iter();
segment_iter.find(|&&segment_entity| segment_entity == entity);
if let Some(&segment_entity) = segment_iter.next() {
commands.entity(segment_entity).insert(BulgeMarker);
}
}
}
fn animate_bulge_system(mut commands: Commands, query: Query<Entity, Added<BulgeMarker>>) {
for entity in query.iter() {
let tween_to = Tween::new(
EaseFunction::CubicInOut,
TweeningType::Once,
Duration::from_millis(100),
TransformScaleLens {
start: Vec3::splat(1.0),
end: Vec3::splat(1.1),
},
);
let tween_back = Tween::new(
EaseFunction::CubicInOut,
TweeningType::Once,
Duration::from_millis(150),
TransformScaleLens {
start: Vec3::splat(1.1),
end: Vec3::splat(1.0),
},
);
let tween = tween_to.then(tween_back);
commands.entity(entity).insert(Animator::new(tween));
}
}
fn update_direction_system(
mut query: Query<(&mut Direction, &mut DirectionBuffer), With<SnakeHead>>,
) {