Update to Bevy 0.9
This commit is contained in:
1000
Cargo.lock
generated
1000
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -6,14 +6,14 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
iyes_loopless = "0.8.0"
|
iyes_loopless = "0.9.1"
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
bevy_editor_pls = "0.1.1"
|
bevy_editor_pls = "0.2.0"
|
||||||
bevy_tweening = "0.5.0"
|
bevy_tweening = "0.6.0"
|
||||||
|
|
||||||
[dependencies.bevy]
|
[dependencies.bevy]
|
||||||
version = "0.8.1"
|
version = "0.9.0"
|
||||||
features = ["dynamic"]
|
features = ["dynamic"]
|
||||||
|
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ impl Plugin for CanvasPlugin {
|
|||||||
|
|
||||||
fn spawn_background(mut commands: Commands) {
|
fn spawn_background(mut commands: Commands) {
|
||||||
commands
|
commands
|
||||||
.spawn_bundle(SpriteBundle {
|
.spawn(SpriteBundle {
|
||||||
sprite: Sprite {
|
sprite: Sprite {
|
||||||
color: Color::DARK_GRAY,
|
color: Color::DARK_GRAY,
|
||||||
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE * f32::from(grid::SIZE))),
|
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE * f32::from(grid::SIZE))),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub struct FruitPlugin;
|
|||||||
impl Plugin for FruitPlugin {
|
impl Plugin for FruitPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<EatenEvent>()
|
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(eat_fruit_system.run_if(tick_triggered))
|
||||||
.add_system(debug_eaten_event_system)
|
.add_system(debug_eaten_event_system)
|
||||||
.add_system(despawn_fruit_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.");
|
.expect("Should always be found.");
|
||||||
|
|
||||||
commands
|
commands
|
||||||
.spawn_bundle(SpriteBundle {
|
.spawn(SpriteBundle {
|
||||||
sprite: Sprite {
|
sprite: Sprite {
|
||||||
color: Color::GREEN,
|
color: Color::GREEN,
|
||||||
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE) * 0.6),
|
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE) * 0.6),
|
||||||
|
|||||||
20
src/main.rs
20
src/main.rs
@@ -26,15 +26,17 @@ enum AppState {
|
|||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.insert_resource(ClearColor(Color::rgb_u8(12, 12, 12)))
|
.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_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(EditorPlugin)
|
||||||
.add_plugin(TweeningPlugin)
|
.add_plugin(TweeningPlugin)
|
||||||
.add_plugin(TickPlugin)
|
.add_plugin(TickPlugin)
|
||||||
@@ -52,7 +54,7 @@ fn setup_system(mut commands: Commands) {
|
|||||||
let grid_dimensions = f32::from(SIZE) * SEGMENT_SIZE * 1.2;
|
let grid_dimensions = f32::from(SIZE) * SEGMENT_SIZE * 1.2;
|
||||||
|
|
||||||
commands
|
commands
|
||||||
.spawn_bundle(Camera2dBundle {
|
.spawn(Camera2dBundle {
|
||||||
projection: OrthographicProjection {
|
projection: OrthographicProjection {
|
||||||
scaling_mode: ScalingMode::Auto {
|
scaling_mode: ScalingMode::Auto {
|
||||||
min_width: grid_dimensions,
|
min_width: grid_dimensions,
|
||||||
|
|||||||
86
src/snake.rs
86
src/snake.rs
@@ -13,12 +13,6 @@ use iyes_loopless::prelude::*;
|
|||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, StageLabel)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, StageLabel)]
|
||||||
struct MovementStage;
|
struct MovementStage;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, SystemLabel)]
|
|
||||||
pub enum SystemLabel {
|
|
||||||
StartUp,
|
|
||||||
SegmentMovement,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SnakePlugin;
|
pub struct SnakePlugin;
|
||||||
|
|
||||||
impl Plugin for SnakePlugin {
|
impl Plugin for SnakePlugin {
|
||||||
@@ -26,14 +20,13 @@ impl Plugin for SnakePlugin {
|
|||||||
let movement_stage = SystemStage::parallel();
|
let movement_stage = SystemStage::parallel();
|
||||||
|
|
||||||
app.insert_resource(BulgePropagationTimer::default())
|
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_stage_after(CoreStage::Update, MovementStage, movement_stage)
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
MovementStage,
|
MovementStage,
|
||||||
segments_movement_system
|
segments_movement_system
|
||||||
.run_in_state(AppState::InGame)
|
.run_in_state(AppState::InGame)
|
||||||
.run_if(tick_triggered)
|
.run_if(tick_triggered),
|
||||||
.label(SystemLabel::SegmentMovement),
|
|
||||||
)
|
)
|
||||||
.add_system(
|
.add_system(
|
||||||
apply_direction_system
|
apply_direction_system
|
||||||
@@ -69,19 +62,13 @@ struct SnakeSegment;
|
|||||||
pub struct SnakeHead;
|
pub struct SnakeHead;
|
||||||
|
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
struct Snake {
|
struct Segments(Vec<Entity>);
|
||||||
about_to_collide: bool,
|
|
||||||
segments: Vec<Entity>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Snake {
|
#[derive(Component, Debug)]
|
||||||
fn with_segments(segments: &[Entity]) -> Self {
|
struct Snake;
|
||||||
Self {
|
|
||||||
about_to_collide: false,
|
// #[derive(Bundle)]
|
||||||
segments: segments.to_owned(),
|
// struct SnakeBundle;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component, Copy, Clone, Debug)]
|
#[derive(Component, Copy, Clone, Debug)]
|
||||||
enum Direction {
|
enum Direction {
|
||||||
@@ -110,9 +97,14 @@ impl Direction {
|
|||||||
#[derive(Component, Default, Debug)]
|
#[derive(Component, Default, Debug)]
|
||||||
struct DirectionBuffer(Option<Direction>);
|
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 {
|
fn create_snake_segment(commands: &mut Commands, grid_position: grid::Coordinate) -> Entity {
|
||||||
commands
|
commands
|
||||||
.spawn_bundle(SpriteBundle {
|
.spawn(SpriteBundle {
|
||||||
sprite: Sprite {
|
sprite: Sprite {
|
||||||
color: Color::RED,
|
color: Color::RED,
|
||||||
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE) * 0.9),
|
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE) * 0.9),
|
||||||
@@ -135,11 +127,14 @@ fn setup_snake_system(mut commands: Commands) {
|
|||||||
.insert(SnakeHead);
|
.insert(SnakeHead);
|
||||||
|
|
||||||
commands
|
commands
|
||||||
.spawn()
|
.spawn((
|
||||||
.insert(Snake::with_segments(&[snake_head]))
|
Snake,
|
||||||
.insert(Name::new("Snake"))
|
Name::new("Snake"),
|
||||||
.insert(DirectionBuffer::default())
|
SpatialBundle::default(),
|
||||||
.insert_bundle(SpatialBundle::default())
|
DirectionBuffer::default(),
|
||||||
|
Collision::default(),
|
||||||
|
Segments(vec![snake_head]),
|
||||||
|
))
|
||||||
.add_child(snake_head);
|
.add_child(snake_head);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,19 +154,19 @@ fn add_direction_system(
|
|||||||
fn add_tail_system(
|
fn add_tail_system(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut eaten_event_reader: EventReader<fruit::EatenEvent>,
|
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() {
|
for _ in eaten_event_reader.iter() {
|
||||||
let segment =
|
let segment =
|
||||||
create_snake_segment(&mut commands, grid::Coordinate::splat(grid::Index::MIN / 2));
|
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
|
commands
|
||||||
.entity(segment)
|
.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);
|
commands.entity(snake_entity).add_child(segment);
|
||||||
}
|
}
|
||||||
@@ -215,31 +210,22 @@ fn grid_transform_system(
|
|||||||
|
|
||||||
fn segments_movement_system(
|
fn segments_movement_system(
|
||||||
mut segment_query: Query<&mut grid::Coordinate, With<SnakeSegment>>,
|
mut segment_query: Query<&mut grid::Coordinate, With<SnakeSegment>>,
|
||||||
snake_query: Query<(&Snake, &Direction)>,
|
snake_query: Query<(&Collision, &Direction, &Segments), With<Snake>>,
|
||||||
) {
|
) {
|
||||||
for (
|
for (collision, direction, segments) in snake_query.iter() {
|
||||||
Snake {
|
if collision.about_to_collide {
|
||||||
about_to_collide,
|
|
||||||
segments,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
direction,
|
|
||||||
) in snake_query.iter()
|
|
||||||
{
|
|
||||||
if *about_to_collide {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ... then the other elements
|
// ... 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 previous_coordinate = *segment_query.get(previous_segment).unwrap();
|
||||||
let mut coordinate = segment_query.get_mut(segment).unwrap();
|
let mut coordinate = segment_query.get_mut(segment).unwrap();
|
||||||
*coordinate = previous_coordinate;
|
*coordinate = previous_coordinate;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First move head ...
|
// 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();
|
let mut head_coordinate = segment_query.get_mut(head).unwrap();
|
||||||
*head_coordinate = next_grid_coordinate(&head_coordinate, direction);
|
*head_coordinate = next_grid_coordinate(&head_coordinate, direction);
|
||||||
}
|
}
|
||||||
@@ -248,10 +234,10 @@ fn segments_movement_system(
|
|||||||
fn collision_system(
|
fn collision_system(
|
||||||
segment_query: Query<&grid::Coordinate, (With<SnakeSegment>, Without<SnakeHead>)>,
|
segment_query: Query<&grid::Coordinate, (With<SnakeSegment>, Without<SnakeHead>)>,
|
||||||
head_query: Query<(&grid::Coordinate, &Parent), With<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() {
|
for (head_coordinate, parent) in head_query.iter() {
|
||||||
let (direction, mut snake) = snake_query
|
let (direction, mut collision) = snake_query
|
||||||
.get_mut(parent.get())
|
.get_mut(parent.get())
|
||||||
.expect("Head must be child of Snake");
|
.expect("Head must be child of Snake");
|
||||||
|
|
||||||
@@ -263,11 +249,11 @@ fn collision_system(
|
|||||||
.iter()
|
.iter()
|
||||||
.all(|&coordinate| coordinate != next_head_coordinate);
|
.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 {
|
if query.get_single().unwrap().about_to_collide {
|
||||||
commands.insert_resource(NextState(AppState::End));
|
commands.insert_resource(NextState(AppState::End));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::{Snake, SnakeHead, SnakeSegment};
|
use super::{Segments, Snake, SnakeHead, SnakeSegment};
|
||||||
use crate::{fruit, tick::TICK_PERIOD};
|
use crate::{fruit, tick::TICK_PERIOD};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_tweening::{lens::TransformScaleLens, *};
|
use bevy_tweening::{lens::TransformScaleLens, *};
|
||||||
@@ -8,11 +8,15 @@ use std::time::Duration;
|
|||||||
#[component(storage = "SparseSet")]
|
#[component(storage = "SparseSet")]
|
||||||
pub(super) struct BulgeMarker;
|
pub(super) struct BulgeMarker;
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
pub(super) struct BulgePropagationTimer(Timer);
|
pub(super) struct BulgePropagationTimer(Timer);
|
||||||
|
|
||||||
impl Default for BulgePropagationTimer {
|
impl Default for BulgePropagationTimer {
|
||||||
fn default() -> Self {
|
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(
|
pub(super) fn propagate_bulge_system(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
bulge_segment_query: Query<(Entity, &Parent), (With<SnakeSegment>, With<BulgeMarker>)>,
|
bulge_segment_query: Query<(Entity, &Parent), (With<SnakeSegment>, With<BulgeMarker>)>,
|
||||||
snake_query: Query<&Snake>,
|
snake_query: Query<&Segments, With<Snake>>,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
mut timer: ResMut<BulgePropagationTimer>,
|
mut timer: ResMut<BulgePropagationTimer>,
|
||||||
) {
|
) {
|
||||||
@@ -43,7 +47,7 @@ pub(super) fn propagate_bulge_system(
|
|||||||
for (entity, parent) in bulge_segment_query.iter() {
|
for (entity, parent) in bulge_segment_query.iter() {
|
||||||
commands.entity(entity).remove::<BulgeMarker>();
|
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);
|
segment_iter.find(|&&segment_entity| segment_entity == entity);
|
||||||
|
|
||||||
if let Some(&segment_entity) = segment_iter.next() {
|
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() {
|
for entity in query.iter() {
|
||||||
let tween_to = Tween::new(
|
let tween_to = Tween::new(
|
||||||
EaseFunction::QuadraticInOut,
|
EaseFunction::QuadraticInOut,
|
||||||
TweeningType::Once,
|
|
||||||
Duration::from_millis(100),
|
Duration::from_millis(100),
|
||||||
TransformScaleLens {
|
TransformScaleLens {
|
||||||
start: Vec3::splat(1.0),
|
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(
|
let tween_back = Tween::new(
|
||||||
EaseFunction::QuadraticInOut,
|
EaseFunction::QuadraticInOut,
|
||||||
TweeningType::Once,
|
|
||||||
Duration::from_millis(150),
|
Duration::from_millis(150),
|
||||||
TransformScaleLens {
|
TransformScaleLens {
|
||||||
start: Vec3::splat(1.1),
|
start: Vec3::splat(1.1),
|
||||||
|
|||||||
@@ -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>) {
|
fn tick_event_system(mut event_writer: EventWriter<TickEvent>) {
|
||||||
event_writer.send(TickEvent);
|
event_writer.send(TickEvent);
|
||||||
|
|||||||
Reference in New Issue
Block a user