Update to Bevy 0.9

This commit is contained in:
2022-11-28 22:16:05 +01:00
parent e70ec51673
commit 0e5114c3d9
8 changed files with 643 additions and 498 deletions

1000
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,14 +6,14 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
iyes_loopless = "0.8.0"
iyes_loopless = "0.9.1"
itertools = "0.10.5"
rand = "0.8.5"
bevy_editor_pls = "0.1.1"
bevy_tweening = "0.5.0"
bevy_editor_pls = "0.2.0"
bevy_tweening = "0.6.0"
[dependencies.bevy]
version = "0.8.1"
version = "0.9.0"
features = ["dynamic"]
[profile.dev.package."*"]

View File

@@ -11,7 +11,7 @@ impl Plugin for CanvasPlugin {
fn spawn_background(mut commands: Commands) {
commands
.spawn_bundle(SpriteBundle {
.spawn(SpriteBundle {
sprite: Sprite {
color: Color::DARK_GRAY,
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE * f32::from(grid::SIZE))),

View File

@@ -14,7 +14,7 @@ pub struct FruitPlugin;
impl Plugin for FruitPlugin {
fn build(&self, app: &mut App) {
app.add_event::<EatenEvent>()
.add_startup_system(spawn_fruit_system.after(snake::SystemLabel::StartUp))
.add_startup_system(spawn_fruit_system)
.add_system(eat_fruit_system.run_if(tick_triggered))
.add_system(debug_eaten_event_system)
.add_system(despawn_fruit_system)
@@ -53,7 +53,7 @@ fn spawn_fruit_system(mut commands: Commands, coordinate_query: Query<&grid::Coo
.expect("Should always be found.");
commands
.spawn_bundle(SpriteBundle {
.spawn(SpriteBundle {
sprite: Sprite {
color: Color::GREEN,
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE) * 0.6),

View File

@@ -26,15 +26,17 @@ enum AppState {
fn main() {
App::new()
.insert_resource(ClearColor(Color::rgb_u8(12, 12, 12)))
.insert_resource(WindowDescriptor {
title: "Bevy-Snake".into(),
resizable: true,
width: WINDOW_WIDTH,
height: WINDOW_HEIGHT,
..Default::default()
})
.add_loopless_state(AppState::Begin)
.add_plugins(DefaultPlugins)
.add_plugins(DefaultPlugins.set(WindowPlugin {
window: WindowDescriptor {
title: "Bevy-Snake".into(),
resizable: true,
width: WINDOW_WIDTH,
height: WINDOW_HEIGHT,
..Default::default()
},
..Default::default()
}))
.add_plugin(EditorPlugin)
.add_plugin(TweeningPlugin)
.add_plugin(TickPlugin)
@@ -52,7 +54,7 @@ fn setup_system(mut commands: Commands) {
let grid_dimensions = f32::from(SIZE) * SEGMENT_SIZE * 1.2;
commands
.spawn_bundle(Camera2dBundle {
.spawn(Camera2dBundle {
projection: OrthographicProjection {
scaling_mode: ScalingMode::Auto {
min_width: grid_dimensions,

View File

@@ -13,12 +13,6 @@ use iyes_loopless::prelude::*;
#[derive(Debug, Clone, PartialEq, Eq, Hash, StageLabel)]
struct MovementStage;
#[derive(Debug, Clone, PartialEq, Eq, Hash, SystemLabel)]
pub enum SystemLabel {
StartUp,
SegmentMovement,
}
pub struct SnakePlugin;
impl Plugin for SnakePlugin {
@@ -26,14 +20,13 @@ impl Plugin for SnakePlugin {
let movement_stage = SystemStage::parallel();
app.insert_resource(BulgePropagationTimer::default())
.add_startup_system(setup_snake_system.label(SystemLabel::StartUp))
.add_startup_system(setup_snake_system)
.add_stage_after(CoreStage::Update, MovementStage, movement_stage)
.add_system_to_stage(
MovementStage,
segments_movement_system
.run_in_state(AppState::InGame)
.run_if(tick_triggered)
.label(SystemLabel::SegmentMovement),
.run_if(tick_triggered),
)
.add_system(
apply_direction_system
@@ -69,19 +62,13 @@ struct SnakeSegment;
pub struct SnakeHead;
#[derive(Component, Debug)]
struct Snake {
about_to_collide: bool,
segments: Vec<Entity>,
}
struct Segments(Vec<Entity>);
impl Snake {
fn with_segments(segments: &[Entity]) -> Self {
Self {
about_to_collide: false,
segments: segments.to_owned(),
}
}
}
#[derive(Component, Debug)]
struct Snake;
// #[derive(Bundle)]
// struct SnakeBundle;
#[derive(Component, Copy, Clone, Debug)]
enum Direction {
@@ -110,9 +97,14 @@ impl Direction {
#[derive(Component, Default, Debug)]
struct DirectionBuffer(Option<Direction>);
#[derive(Component, Default, Debug)]
struct Collision {
about_to_collide: bool,
}
fn create_snake_segment(commands: &mut Commands, grid_position: grid::Coordinate) -> Entity {
commands
.spawn_bundle(SpriteBundle {
.spawn(SpriteBundle {
sprite: Sprite {
color: Color::RED,
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE) * 0.9),
@@ -135,11 +127,14 @@ fn setup_snake_system(mut commands: Commands) {
.insert(SnakeHead);
commands
.spawn()
.insert(Snake::with_segments(&[snake_head]))
.insert(Name::new("Snake"))
.insert(DirectionBuffer::default())
.insert_bundle(SpatialBundle::default())
.spawn((
Snake,
Name::new("Snake"),
SpatialBundle::default(),
DirectionBuffer::default(),
Collision::default(),
Segments(vec![snake_head]),
))
.add_child(snake_head);
}
@@ -159,19 +154,19 @@ fn add_direction_system(
fn add_tail_system(
mut commands: Commands,
mut eaten_event_reader: EventReader<fruit::EatenEvent>,
mut snake_query: Query<(Entity, &mut Snake)>,
mut snake_query: Query<(Entity, &mut Segments), With<Snake>>,
) {
for _ in eaten_event_reader.iter() {
let segment =
create_snake_segment(&mut commands, grid::Coordinate::splat(grid::Index::MIN / 2));
let (snake_entity, mut snake) = snake_query.single_mut();
let (snake_entity, mut segments) = snake_query.single_mut();
snake.segments.push(segment);
segments.0.push(segment);
commands
.entity(segment)
.insert(Name::new(format!("Segment {}", snake.segments.len())));
.insert(Name::new(format!("Segment {}", segments.0.len())));
commands.entity(snake_entity).add_child(segment);
}
@@ -215,31 +210,22 @@ fn grid_transform_system(
fn segments_movement_system(
mut segment_query: Query<&mut grid::Coordinate, With<SnakeSegment>>,
snake_query: Query<(&Snake, &Direction)>,
snake_query: Query<(&Collision, &Direction, &Segments), With<Snake>>,
) {
for (
Snake {
about_to_collide,
segments,
..
},
direction,
) in snake_query.iter()
{
if *about_to_collide {
for (collision, direction, segments) in snake_query.iter() {
if collision.about_to_collide {
continue;
}
// ... then the other elements
for (&segment, &previous_segment) in segments.iter().rev().tuple_windows() {
for (&segment, &previous_segment) in segments.0.iter().rev().tuple_windows() {
let previous_coordinate = *segment_query.get(previous_segment).unwrap();
let mut coordinate = segment_query.get_mut(segment).unwrap();
*coordinate = previous_coordinate;
}
// First move head ...
let head = *segments.iter().next().expect("Snake has always a head");
let head = *segments.0.first().expect("Snake has always a head");
let mut head_coordinate = segment_query.get_mut(head).unwrap();
*head_coordinate = next_grid_coordinate(&head_coordinate, direction);
}
@@ -248,10 +234,10 @@ fn segments_movement_system(
fn collision_system(
segment_query: Query<&grid::Coordinate, (With<SnakeSegment>, Without<SnakeHead>)>,
head_query: Query<(&grid::Coordinate, &Parent), With<SnakeHead>>,
mut snake_query: Query<(&Direction, &mut Snake)>,
mut snake_query: Query<(&Direction, &mut Collision), With<Snake>>,
) {
for (head_coordinate, parent) in head_query.iter() {
let (direction, mut snake) = snake_query
let (direction, mut collision) = snake_query
.get_mut(parent.get())
.expect("Head must be child of Snake");
@@ -263,11 +249,11 @@ fn collision_system(
.iter()
.all(|&coordinate| coordinate != next_head_coordinate);
snake.about_to_collide = hit_border || hit_snake;
collision.about_to_collide = hit_border || hit_snake;
}
}
fn game_over_system(query: Query<&Snake>, mut commands: Commands) {
fn game_over_system(query: Query<&Collision, With<Snake>>, mut commands: Commands) {
if query.get_single().unwrap().about_to_collide {
commands.insert_resource(NextState(AppState::End));
}

View File

@@ -1,4 +1,4 @@
use super::{Snake, SnakeHead, SnakeSegment};
use super::{Segments, Snake, SnakeHead, SnakeSegment};
use crate::{fruit, tick::TICK_PERIOD};
use bevy::prelude::*;
use bevy_tweening::{lens::TransformScaleLens, *};
@@ -8,11 +8,15 @@ use std::time::Duration;
#[component(storage = "SparseSet")]
pub(super) struct BulgeMarker;
#[derive(Resource)]
pub(super) struct BulgePropagationTimer(Timer);
impl Default for BulgePropagationTimer {
fn default() -> Self {
Self(Timer::new(Duration::from_millis(TICK_PERIOD / 4), true))
Self(Timer::new(
Duration::from_millis(TICK_PERIOD / 4),
TimerMode::Repeating,
))
}
}
@@ -30,7 +34,7 @@ pub(super) fn add_bulge_system(
pub(super) fn propagate_bulge_system(
mut commands: Commands,
bulge_segment_query: Query<(Entity, &Parent), (With<SnakeSegment>, With<BulgeMarker>)>,
snake_query: Query<&Snake>,
snake_query: Query<&Segments, With<Snake>>,
time: Res<Time>,
mut timer: ResMut<BulgePropagationTimer>,
) {
@@ -43,7 +47,7 @@ pub(super) fn propagate_bulge_system(
for (entity, parent) in bulge_segment_query.iter() {
commands.entity(entity).remove::<BulgeMarker>();
let mut segment_iter = snake_query.get(parent.get()).unwrap().segments.iter();
let mut segment_iter = snake_query.get(parent.get()).unwrap().0.iter();
segment_iter.find(|&&segment_entity| segment_entity == entity);
if let Some(&segment_entity) = segment_iter.next() {
@@ -52,11 +56,13 @@ pub(super) fn propagate_bulge_system(
}
}
pub(super) fn animate_bulge_system(mut commands: Commands, query: Query<Entity, Added<BulgeMarker>>) {
pub(super) fn animate_bulge_system(
mut commands: Commands,
query: Query<Entity, Added<BulgeMarker>>,
) {
for entity in query.iter() {
let tween_to = Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(100),
TransformScaleLens {
start: Vec3::splat(1.0),
@@ -66,7 +72,6 @@ pub(super) fn animate_bulge_system(mut commands: Commands, query: Query<Entity,
let tween_back = Tween::new(
EaseFunction::QuadraticInOut,
TweeningType::Once,
Duration::from_millis(150),
TransformScaleLens {
start: Vec3::splat(1.1),

View File

@@ -22,7 +22,7 @@ impl Plugin for TickPlugin {
}
}
pub struct TickEvent;
pub struct TickEvent; // TODO remove again
fn tick_event_system(mut event_writer: EventWriter<TickEvent>) {
event_writer.send(TickEvent);