Skip to content

Commit

Permalink
feat!: upgrade to bevy 0.10 (#168)
Browse files Browse the repository at this point in the history
* Update to bevy `0.10`

* Fix and refactor `LdtkPlugin::build`

* Fix clippy warnings

* Schedule `LdtkSystemSet::ProcessApi` before `PhysicsSet::SyncBackend`

* Refactor `InternalSystemSet`

* Update doc comments

* Improve doc comment

* Update src/lib.rs

Co-authored-by: Trevor Lovell <trevorlovelldesign@gmail.com>

* Export `LdtkSystemSet` in `prelude` and small fixups

---------

Co-authored-by: Trevor Lovell <trevorlovelldesign@gmail.com>
  • Loading branch information
geieredgar and Trouv committed Mar 14, 2023
1 parent a832da0 commit 5b8f17c
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 106 deletions.
9 changes: 6 additions & 3 deletions Cargo.toml
Expand Up @@ -16,7 +16,7 @@ members = ["macros"]
[dependencies]
bevy_ecs_ldtk_macros = { version = "0.5.0", optional = true, path = "macros" }
bevy_ecs_tilemap = { version = "0.9", default-features = false }
bevy = { version = "0.9", default-features = false, features = ["bevy_sprite"] }
bevy = { version = "0.10", default-features = false, features = ["bevy_sprite"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
regex = "1"
Expand All @@ -25,8 +25,8 @@ anyhow = "1.0"
thiserror = "1.0"

[dev-dependencies]
bevy = "0.9"
bevy_rapier2d = "0.19"
bevy = "0.10"
bevy_rapier2d = "0.21"
rand = "0.8"

[features]
Expand All @@ -38,3 +38,6 @@ render = ["bevy_ecs_tilemap/render"]
[[example]]
name = "platformer"
path = "examples/platformer/main.rs"

[patch.crates-io]
bevy_ecs_tilemap = { version = "0.9", git = "https://github.com/geieredgar/bevy_ecs_tilemap", branch = "bevy_track" }
33 changes: 15 additions & 18 deletions examples/platformer/components.rs
Expand Up @@ -70,7 +70,6 @@ impl From<IntGridCell> for SensorBundle {
sensor: Sensor,
rotation_constraints,
active_events: ActiveEvents::COLLISION_EVENTS,
..Default::default()
}
} else {
SensorBundle::default()
Expand Down Expand Up @@ -189,23 +188,21 @@ impl LdtkEntity for Patrol {
.find(|f| f.identifier == *"patrol")
.unwrap();
if let FieldValue::Points(ldtk_points) = &ldtk_patrol.value {
for ldtk_point in ldtk_points {
if let Some(ldtk_point) = ldtk_point {
// The +1 is necessary here due to the pivot of the entities in the sample
// file.
// The patrols set up in the file look flat and grounded,
// but technically they're not if you consider the pivot,
// which is at the bottom-center for the skulls.
let pixel_coords = (ldtk_point.as_vec2() + Vec2::new(0.5, 1.))
* Vec2::splat(layer_instance.grid_size as f32);

points.push(ldtk_pixel_coords_to_translation_pivoted(
pixel_coords.as_ivec2(),
layer_instance.c_hei * layer_instance.grid_size,
IVec2::new(entity_instance.width, entity_instance.height),
entity_instance.pivot,
));
}
for ldtk_point in ldtk_points.iter().flatten() {
// The +1 is necessary here due to the pivot of the entities in the sample
// file.
// The patrols set up in the file look flat and grounded,
// but technically they're not if you consider the pivot,
// which is at the bottom-center for the skulls.
let pixel_coords = (ldtk_point.as_vec2() + Vec2::new(0.5, 1.))
* Vec2::splat(layer_instance.grid_size as f32);

points.push(ldtk_pixel_coords_to_translation_pivoted(
pixel_coords.as_ivec2(),
layer_instance.c_hei * layer_instance.grid_size,
IVec2::new(entity_instance.width, entity_instance.height),
entity_instance.pivot,
));
}
}

Expand Down
2 changes: 2 additions & 0 deletions examples/platformer/main.rs
Expand Up @@ -14,6 +14,8 @@ fn main() {
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_plugin(LdtkPlugin)
.add_plugin(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))
// Required to prevent race conditions between bevy_ecs_ldtk's and bevy_rapier's systems
.configure_set(LdtkSystemSet::ProcessApi.before(PhysicsSet::SyncBackend))
.insert_resource(RapierConfiguration {
gravity: Vec2::new(0.0, -2000.0),
..Default::default()
Expand Down
32 changes: 16 additions & 16 deletions examples/platformer/systems.rs
Expand Up @@ -309,6 +309,7 @@ pub fn patrol(mut query: Query<(&mut Transform, &mut Velocity, &mut Patrol)>) {

const ASPECT_RATIO: f32 = 16. / 9.;

#[allow(clippy::type_complexity)]
pub fn camera_fit_inside_current_level(
mut camera_query: Query<
(
Expand Down Expand Up @@ -339,27 +340,26 @@ pub fn camera_fit_inside_current_level(
let level = &ldtk_level.level;
if level_selection.is_match(&0, level) {
let level_ratio = level.px_wid as f32 / ldtk_level.level.px_hei as f32;

orthographic_projection.scaling_mode = bevy::render::camera::ScalingMode::None;
orthographic_projection.bottom = 0.;
orthographic_projection.left = 0.;
orthographic_projection.viewport_origin = Vec2::ZERO;
if level_ratio > ASPECT_RATIO {
// level is wider than the screen
orthographic_projection.top = (level.px_hei as f32 / 9.).round() * 9.;
orthographic_projection.right = orthographic_projection.top * ASPECT_RATIO;
camera_transform.translation.x = (player_translation.x
- level_transform.translation.x
- orthographic_projection.right / 2.)
.clamp(0., level.px_wid as f32 - orthographic_projection.right);
let height = (level.px_hei as f32 / 9.).round() * 9.;
let width = height * ASPECT_RATIO;
orthographic_projection.scaling_mode =
bevy::render::camera::ScalingMode::Fixed { width, height };
camera_transform.translation.x =
(player_translation.x - level_transform.translation.x - width / 2.)
.clamp(0., level.px_wid as f32 - width);
camera_transform.translation.y = 0.;
} else {
// level is taller than the screen
orthographic_projection.right = (level.px_wid as f32 / 16.).round() * 16.;
orthographic_projection.top = orthographic_projection.right / ASPECT_RATIO;
camera_transform.translation.y = (player_translation.y
- level_transform.translation.y
- orthographic_projection.top / 2.)
.clamp(0., level.px_hei as f32 - orthographic_projection.top);
let width = (level.px_wid as f32 / 16.).round() * 16.;
let height = width / ASPECT_RATIO;
orthographic_projection.scaling_mode =
bevy::render::camera::ScalingMode::Fixed { width, height };
camera_transform.translation.y =
(player_translation.y - level_transform.translation.y - height / 2.)
.clamp(0., level.px_hei as f32 - height);
camera_transform.translation.x = 0.;
}

Expand Down
88 changes: 41 additions & 47 deletions src/lib.rs
Expand Up @@ -138,33 +138,34 @@ mod plugin {

use super::*;

/// [SystemLabel] used by the plugin for scheduling its systems.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, SystemLabel)]
pub enum LdtkSystemLabel {
ProcessAssets,
LevelSelection,
LevelSet,
LevelSpawning,
Other,
}

/// [StageLabel] for stages added by the plugin.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, StageLabel)]
pub enum LdtkStage {
/// Occurs immediately after [CoreStage::Update].
/// Base [SystemSet]s for systems added by the plugin.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, SystemSet)]
#[system_set(base)]
pub enum LdtkSystemSet {
/// Scheduled after [CoreSet::UpdateFlush].
///
/// Used for systems that process components and resources provided by this plugin's API.
/// In particular, this stage processes..
/// In particular, this set processes..
/// - [resources::LevelSelection]
/// - [components::LevelSet]
/// - [components::Worldly]
/// - [components::Respawn]
///
/// As a result, you can expect minimal frame delay when updating these in
/// [CoreStage::Update].
/// [CoreSet::Update].
///
/// You might need to add additional scheduling constraints to prevent race conditions
/// between systems in this set and other external systems. As an example, `bevy_rapier`'s
/// `PhysicsSet::BackendSync` should be scheduled after `LdtkSystemSet::ProcessApi`.
ProcessApi,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, SystemSet)]
enum ProcessApiSet {
PreClean,
Clean,
}

/// Adds the default systems, assets, and resources used by `bevy_ecs_ldtk`.
///
/// Add it to your [App] to gain LDtk functionality!
Expand All @@ -178,10 +179,15 @@ mod plugin {
app = app.add_plugin(bevy_ecs_tilemap::TilemapPlugin);
}

app.add_stage_after(
CoreStage::Update,
LdtkStage::ProcessApi,
SystemStage::parallel(),
app.configure_set(
LdtkSystemSet::ProcessApi
.after(CoreSet::UpdateFlush)
.before(CoreSet::PostUpdate),
)
.configure_sets(
(ProcessApiSet::PreClean, ProcessApiSet::Clean)
.chain()
.in_base_set(LdtkSystemSet::ProcessApi),
)
.init_non_send_resource::<app::LdtkEntityMap>()
.init_non_send_resource::<app::LdtkIntCellMap>()
Expand All @@ -191,37 +197,25 @@ mod plugin {
.add_asset::<assets::LdtkLevel>()
.init_asset_loader::<assets::LdtkLevelLoader>()
.add_event::<resources::LevelEvent>()
.add_system_to_stage(
CoreStage::PreUpdate,
systems::process_ldtk_assets.label(LdtkSystemLabel::ProcessAssets),
)
.add_system_to_stage(
CoreStage::PreUpdate,
systems::process_ldtk_levels.label(LdtkSystemLabel::LevelSpawning),
)
.add_system_to_stage(
LdtkStage::ProcessApi,
systems::worldly_adoption.label(LdtkSystemLabel::Other),
)
.add_system_to_stage(
LdtkStage::ProcessApi,
systems::apply_level_selection.label(LdtkSystemLabel::LevelSelection),
.add_systems(
(systems::process_ldtk_assets, systems::process_ldtk_levels)
.in_base_set(CoreSet::PreUpdate),
)
.add_system_to_stage(
LdtkStage::ProcessApi,
systems::apply_level_set
.label(LdtkSystemLabel::LevelSet)
.after(LdtkSystemLabel::LevelSelection),
.add_system(systems::worldly_adoption.in_set(ProcessApiSet::PreClean))
.add_systems(
(systems::apply_level_selection, systems::apply_level_set)
.chain()
.in_set(ProcessApiSet::PreClean),
)
.add_system_to_stage(
LdtkStage::ProcessApi,
systems::clean_respawn_entities.at_end(),
.add_systems(
(apply_system_buffers, systems::clean_respawn_entities)
.chain()
.in_set(ProcessApiSet::Clean),
)
.add_system_to_stage(
CoreStage::PostUpdate,
.add_system(
systems::detect_level_spawned_events
.pipe(systems::fire_level_transformed_events)
.label(LdtkSystemLabel::Other),
.in_base_set(CoreSet::PostUpdate),
)
.register_type::<GridCoords>()
.register_type::<TileMetadata>()
Expand All @@ -242,7 +236,7 @@ pub mod prelude {
Respawn, TileEnumTags, TileMetadata, Worldly,
},
ldtk::{self, FieldValue, LayerInstance, TilesetDefinition},
plugin::LdtkPlugin,
plugin::{LdtkPlugin, LdtkSystemSet},
resources::{
IntGridRendering, LdtkSettings, LevelBackground, LevelEvent, LevelSelection,
LevelSpawnBehavior, SetClearColor,
Expand Down
29 changes: 7 additions & 22 deletions src/resources.rs
Expand Up @@ -63,10 +63,11 @@ impl Default for SetClearColor {
}

/// Option in [LdtkSettings] that determines level spawn behavior.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
pub enum LevelSpawnBehavior {
/// Newly spawned levels will be spawned with a translation of zero relative to the
/// [LdtkWorldBundle].
#[default]
UseZeroTranslation,
/// Newly spawned levels will be spawned with translations like their location in the LDtk
/// world.
Expand All @@ -79,43 +80,27 @@ pub enum LevelSpawnBehavior {
},
}

impl Default for LevelSpawnBehavior {
fn default() -> Self {
LevelSpawnBehavior::UseZeroTranslation
}
}

/// Option in [LdtkSettings] that determines the visual representation of IntGrid layers when they don't have AutoTile rules.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
pub enum IntGridRendering {
/// Renders the tile with its corresponding color in LDtk, so it appears like it does in LDtk
#[default]
Colorful,
/// Does not render the tile
Invisible,
}

impl Default for IntGridRendering {
fn default() -> Self {
IntGridRendering::Colorful
}
}

/// Option in [LdtkSettings] that dictates how the plugin handles level backgrounds.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
pub enum LevelBackground {
/// The level background's color (and image, if it exists) are rendered.
/// The first layer of the level will be the background color.
#[default]
Rendered,
/// There will be no level backgrounds, not even an empty layer.
Nonexistent,
}

impl Default for LevelBackground {
fn default() -> Self {
LevelBackground::Rendered
}
}

/// Settings resource for the plugin.
/// Check out the documentation for each field type to learn more.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, Resource)]
Expand All @@ -139,7 +124,7 @@ pub enum LevelEvent {
/// you want to listen for.
/// If your systems are [GlobalTransform]-dependent, see [LevelEvent::Transformed].
Spawned(String),
/// Occurs during the [CoreStage::PostUpdate] after the level has spawned, so all
/// Occurs during the [CoreSet::PostUpdate] after the level has spawned, so all
/// [GlobalTransform]s of the level should be updated.
Transformed(String),
/// Indicates that a level has despawned.
Expand Down

0 comments on commit 5b8f17c

Please sign in to comment.