Fix Changed<T> by rewriting ecs `Filter`s, position `TileMapPos` entities with ChildOf relations

This commit is contained in:
SeanOMik 2024-11-30 12:33:23 -05:00 committed by SeanOMik
parent 418765d595
commit 5a0e06f94d
20 changed files with 279 additions and 201 deletions

View File

@ -56,12 +56,15 @@ impl ComponentColumn {
pub unsafe fn new(info: ComponentInfo, capacity: usize) -> Self { pub unsafe fn new(info: ComponentInfo, capacity: usize) -> Self {
let data = ComponentColumn::alloc(info.layout(), capacity); let data = ComponentColumn::alloc(info.layout(), capacity);
let mut ticks = Vec::with_capacity(capacity);
ticks.resize(capacity, Tick::from(0));
Self { Self {
data: RefCell::new(data), data: RefCell::new(data),
capacity, capacity,
info, info,
len: 0, len: 0,
entity_ticks: Vec::new(), entity_ticks: ticks,
} }
} }
@ -99,9 +102,7 @@ impl ComponentColumn {
let dest = NonNull::new_unchecked(data.as_ptr().add(entity_index * size)); let dest = NonNull::new_unchecked(data.as_ptr().add(entity_index * size));
ptr::copy_nonoverlapping(comp_src.as_ptr(), dest.as_ptr(), size); ptr::copy_nonoverlapping(comp_src.as_ptr(), dest.as_ptr(), size);
// check if a component spot is being set twice and that the entity's tick is self.entity_ticks[entity_index] = tick;
// already stored
self.entity_ticks.push(tick);
self.len += 1; self.len += 1;
} }
@ -175,6 +176,7 @@ impl ComponentColumn {
*data = new_ptr; *data = new_ptr;
} }
self.entity_ticks.resize(new_capacity, Tick::from(0));
self.capacity = new_capacity; self.capacity = new_capacity;
} }

View File

@ -272,11 +272,11 @@ mod tests {
let mut world = World::new(); let mut world = World::new();
let e = world.spawn(b); let e = world.spawn(b);
let pos = world.view_one::<&Vec2>(e).get() let pos = world.view_one::<&Vec2>(e)
.expect("failed to find spawned Vec2 from Bundle on Entity"); .expect("failed to find spawned Vec2 from Bundle on Entity");
assert!(pos.x == b_pos.x && pos.y == b_pos.y, "Spawned Vec2 values were not correct, got: {:?}, expected: {:?}", *pos, b_pos); assert!(pos.x == b_pos.x && pos.y == b_pos.y, "Spawned Vec2 values were not correct, got: {:?}, expected: {:?}", *pos, b_pos);
let flag = world.view_one::<&SomeFlag>(e).get() let flag = world.view_one::<&SomeFlag>(e)
.expect("failed to find spawned SomeFlag from Bundle on Entity"); .expect("failed to find spawned SomeFlag from Bundle on Entity");
assert_eq!(*flag, b_flag); assert_eq!(*flag, b_flag);
} }

View File

@ -1,6 +1,6 @@
use std::{any::Any, cell::RefMut, mem::{self, MaybeUninit}, ptr::{self, NonNull}}; use std::{any::Any, cell::RefMut, mem::{self, MaybeUninit}, ptr::{self, NonNull}};
use crate::{system::FnArgFetcher, Access, Bundle, Entities, Entity, World}; use crate::{system::FnArgFetcher, Access, Bundle, Entities, Entity, Relation, World};
/// A Command be used to delay mutation of the world until after this system is ran. /// A Command be used to delay mutation of the world until after this system is ran.
pub trait Command: Any { pub trait Command: Any {
@ -175,6 +175,12 @@ impl<'a, 'b> Commands<'a, 'b> {
}); });
} }
pub fn add_relation<R: Relation>(&mut self, origin: Entity, relation: R, target: Entity){
self.add(move | world: &mut World| {
world.add_relation(origin, relation, target);
});
}
/// Execute all commands in the queue, in order of insertion /// Execute all commands in the queue, in order of insertion
pub fn execute(&mut self, world: &mut World) { pub fn execute(&mut self, world: &mut World) {
self.queue.execute(Some(world)); self.queue.execute(Some(world));

View File

@ -1,6 +1,6 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use crate::{query::{AsFilter, AsQuery, Fetch, Filter, Query}, Component, ComponentColumn, DynTypeId, Tick, World}; use crate::{query::{AsQuery, Fetch, Query}, Component, ComponentColumn, DynTypeId, Tick, World};
pub struct ChangedFetcher<'a, T> { pub struct ChangedFetcher<'a, T> {
col: &'a ComponentColumn, col: &'a ComponentColumn,
@ -20,7 +20,10 @@ where
unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item { unsafe fn get_item(&mut self, entity: crate::world::ArchetypeEntityId) -> Self::Item {
let tick = self.col.entity_ticks[entity.0 as usize]; let tick = self.col.entity_ticks[entity.0 as usize];
*tick >= (*self.tick) - 1 if *tick > 50 {
//debug!("tick: {}, world tick: {}", *tick, *self.tick);
}
*tick >= *self.tick
} }
} }
@ -77,10 +80,10 @@ where
archetype.has_column(self.type_id) archetype.has_column(self.type_id)
} }
unsafe fn fetch<'a>(&self, w: &'a World, a: &'a crate::archetype::Archetype, _: crate::Tick) -> Self::Fetch<'a> { unsafe fn fetch<'a>(&self, _: &'a World, a: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> {
ChangedFetcher { ChangedFetcher {
col: a.get_column(self.type_id).unwrap(), col: a.get_column(self.type_id).unwrap(),
tick: w.current_tick(), tick,
_phantom: PhantomData::<&T>, _phantom: PhantomData::<&T>,
} }
} }
@ -88,10 +91,4 @@ where
impl<T: Component> AsQuery for Changed<T> { impl<T: Component> AsQuery for Changed<T> {
type Query = Self; type Query = Self;
}
impl<T: Component> Filter for Changed<T> { }
impl<T: Component> AsFilter for Changed<T> {
type Filter = Self;
} }

View File

@ -1,6 +1,6 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use crate::{query::{AsFilter, AsQuery, Filter, Query}, Archetype, Component, DynTypeId, World}; use crate::{query::{AsQuery, Query}, Archetype, Component, DynTypeId, World};
use super::StaticFetcher; use super::StaticFetcher;
@ -45,8 +45,8 @@ impl<C: Component> AsQuery for Has<C> {
type Query = Self; type Query = Self;
} }
impl<C: Component> Filter for Has<C> { } //impl<C: Component> Filter for Has<C> { }
impl<C: Component> AsFilter for Has<C> { /* impl<C: Component> AsFilter for Has<C> {
type Filter = Self; type Filter = Self;
} } */

View File

@ -10,7 +10,73 @@ pub use not::*;
mod changed; mod changed;
pub use changed::*; pub use changed::*;
use super::Fetch; use crate::{Archetype, ArchetypeEntityId, Tick, World};
use super::{Fetch, Query};
pub trait FilterFetch<'a> {
/// Returns true if the entity should be visited or skipped.
fn can_visit(&mut self, entity: ArchetypeEntityId) -> bool;
}
pub trait Filter: Copy {
/// The fetcher used for the filter
type Fetch<'a>: FilterFetch<'a>;
fn new() -> Self;
/// Returns true if the archetype should be visited or skipped.
fn can_visit_archetype(&self, archetype: &Archetype) -> bool;
unsafe fn fetch<'a>(&self, world: &'a World, archetype: &'a Archetype, tick: Tick) -> Self::Fetch<'a>;
/// Returns a fetcher that doesn't fetch from an archetype.
unsafe fn fetch_world<'a>(&self, world: &'a World) -> Option<Self::Fetch<'a>> {
let _ = world;
None
}
}
/// A trait for getting the filter of a type.
pub trait AsFilter {
/// The query for this type
type Filter: Filter;
}
impl<Q> Filter for Q
where
Q: for <'a> Query<Item<'a> = bool>,
{
type Fetch<'a> = Q::Fetch<'a>;
fn new() -> Self {
Query::new()
}
fn can_visit_archetype(&self, archetype: &Archetype) -> bool {
Query::can_visit_archetype(self, archetype)
}
unsafe fn fetch<'a>(&self, world: &'a World, archetype: &'a Archetype, tick: Tick) -> Self::Fetch<'a> {
Query::fetch(self, world, archetype, tick)
}
}
impl<'a, F> FilterFetch<'a> for F
where
F: Fetch<'a, Item = bool>
{
fn can_visit(&mut self, entity: ArchetypeEntityId) -> bool {
Fetch::can_visit_item(self, entity) && unsafe { Fetch::get_item(self, entity) }
}
}
impl<Q> AsFilter for Q
where
Q: for <'a> Query<Item<'a> = bool>
{
type Filter = Q;
}
/// A fetcher that just returns a provided value /// A fetcher that just returns a provided value
pub struct StaticFetcher<T: Clone> { pub struct StaticFetcher<T: Clone> {

View File

@ -1,4 +1,4 @@
use crate::{query::{AsFilter, AsQuery, Filter, Query}, Archetype, World}; use crate::{query::{AsQuery, Query}, Archetype, World};
use super::StaticFetcher; use super::StaticFetcher;
@ -43,10 +43,4 @@ impl<Q: Query> Query for Not<Q> {
impl<Q: Query> AsQuery for Not<Q> { impl<Q: Query> AsQuery for Not<Q> {
type Query = Self; type Query = Self;
}
impl<Q: Query> Filter for Not<Q> { }
impl<Q: Query> AsFilter for Not<Q> {
type Filter = Self;
} }

View File

@ -38,6 +38,7 @@ pub use world_tick::*;
pub mod dynamic; pub mod dynamic;
pub mod filter; pub mod filter;
pub use filter::{Filter, AsFilter};
/// A [`Fetch`]er implementation gets data out of an archetype. /// A [`Fetch`]er implementation gets data out of an archetype.
pub trait Fetch<'a> { pub trait Fetch<'a> {
@ -93,30 +94,24 @@ pub trait AsQuery {
type Query: Query; type Query: Query;
} }
/// A trait for getting the filter of a type.
pub trait AsFilter {
/// The query for this type
type Filter: Filter;
}
pub trait IntoQuery { pub trait IntoQuery {
fn into_query(self) -> Self; fn into_query(self) -> Self;
} }
impl<'a> Fetch<'a> for () { impl<'a> Fetch<'a> for () {
type Item = (); type Item = bool;
fn dangling() -> Self { fn dangling() -> Self {
unreachable!() unreachable!()
} }
unsafe fn get_item(&mut self, _: ArchetypeEntityId) -> Self::Item { unsafe fn get_item(&mut self, _: ArchetypeEntityId) -> Self::Item {
() true
} }
} }
impl Query for () { impl Query for () {
type Item<'a> = (); type Item<'a> = bool;
type Fetch<'a> = (); type Fetch<'a> = ();
@ -135,22 +130,10 @@ impl Query for () {
} }
} }
impl Filter for () {
type Item<'a> = bool;
}
impl AsQuery for () { impl AsQuery for () {
type Query = (); type Query = ();
} }
pub trait Filter: Query {
type Item<'a> = bool;
}
impl AsFilter for () {
type Filter = ();
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{World, archetype::Archetype, tests::Vec2}; use crate::{World, archetype::Archetype, tests::Vec2};

View File

@ -1,6 +1,6 @@
use crate::World; use crate::World;
use super::{Query, Fetch, AsQuery, Filter, AsFilter}; use super::{Query, Fetch, AsQuery, Filter, AsFilter, filter::FilterFetch, ArchetypeEntityId};
/* impl<'a, F1> Fetch<'a> for (F1,) /* impl<'a, F1> Fetch<'a> for (F1,)
where where
@ -139,10 +139,7 @@ macro_rules! impl_bundle_tuple {
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
let ( $($name,)+ ) = self; let ( $($name,)+ ) = self;
$($name.can_visit_archetype(archetype)) &&+
// this is the only way I could figure out how to do an 'and'
let bools = vec![$($name.can_visit_archetype(archetype),)+];
bools.iter().all(|b| *b)
} }
unsafe fn fetch<'a>(&self, world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { unsafe fn fetch<'a>(&self, world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> {
@ -156,26 +153,30 @@ macro_rules! impl_bundle_tuple {
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
impl<$($name: Filter),+> Filter for ($($name,)+) { impl<'a, $($name: FilterFetch<'a>),+> FilterFetch<'a> for ($($name,)+) {
//type Item<'a> = ($(<$name as Query>::Item<'a>,)+); fn can_visit(&mut self, entity: ArchetypeEntityId) -> bool {
//type Fetch<'a> = ($(<$name as Query>::Fetch<'a>,)+); let ( $($name,)+ ) = self;
$($name.can_visit(entity)) &&+
}
}
/* fn new() -> Self { #[allow(non_snake_case)]
impl<$($name: Filter),+> Filter for ($($name,)+) {
type Fetch<'a> = ($(<$name as Filter>::Fetch<'a>,)+);
fn new() -> Self {
( $($name::new(),)+ ) ( $($name::new(),)+ )
} }
fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool { fn can_visit_archetype(&self, archetype: &crate::archetype::Archetype) -> bool {
let ( $($name,)+ ) = self; let ( $($name,)+ ) = self;
$($name.can_visit_archetype(archetype)) &&+
// this is the only way I could figure out how to do an 'and'
let bools = vec![$($name.can_visit_archetype(archetype),)+];
bools.iter().all(|b| *b)
} }
unsafe fn fetch<'a>(&self, world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> { unsafe fn fetch<'a>(&self, world: &'a World, archetype: &'a crate::archetype::Archetype, tick: crate::Tick) -> Self::Fetch<'a> {
let ( $($name,)+ ) = self; let ( $($name,)+ ) = self;
( $($name.fetch(world, archetype, tick),)+ ) ( $($name.fetch(world, archetype, tick),)+ )
} */ }
} }
impl<$($name: AsFilter),+> AsFilter for ($($name,)+) { impl<$($name: AsFilter),+> AsFilter for ($($name,)+) {

View File

@ -1,8 +1,8 @@
use std::ops::Range; use std::{ops::Range, ptr::NonNull};
use crate::{archetype::Archetype, world::{ArchetypeEntityId, World}, EntityId, Tick}; use crate::{archetype::Archetype, system::FnArgFetcher, world::{ArchetypeEntityId, World}, Entity, Tick};
use super::{AsFilter, AsQuery, Fetch, Filter, Query}; use super::{filter::{AsFilter, Filter, FilterFetch}, AsQuery, Fetch, Query};
pub type View<'a, Q, F = ()> = ViewState<'a, <Q as AsQuery>::Query, <F as AsQuery>::Query>; pub type View<'a, Q, F = ()> = ViewState<'a, <Q as AsQuery>::Query, <F as AsQuery>::Query>;
@ -109,7 +109,7 @@ where
let filter_fetcher = self.filter_fetcher.as_mut().unwrap(); let filter_fetcher = self.filter_fetcher.as_mut().unwrap();
let entity_index = ArchetypeEntityId(entity_index); let entity_index = ArchetypeEntityId(entity_index);
if fetcher.can_visit_item(entity_index) && filter_fetcher.can_visit_item(entity_index) { if fetcher.can_visit_item(entity_index) && filter_fetcher.can_visit(entity_index) {
let i = unsafe { fetcher.get_item(entity_index) }; let i = unsafe { fetcher.get_item(entity_index) };
return Some(i); return Some(i);
} }
@ -138,27 +138,27 @@ where
} }
} }
pub struct ViewOne<'a, Q: Query> { pub type ViewOne<'a, Q> = ViewOneState<'a, <Q as AsQuery>::Query>;
pub struct ViewOneState<'a, Q: Query> {
world: &'a World, world: &'a World,
tick: Tick, tick: Tick,
entity: EntityId,
query: Q, query: Q,
} }
impl<'a, Q: Query> ViewOne<'a, Q> { impl<'a, Q: Query> ViewOneState<'a, Q> {
pub fn new(world: &'a World, entity: EntityId, query: Q) -> Self { pub fn new(world: &'a World, query: Q) -> Self {
//let tick = world.tick_tracker().tick_when(Q::MUTATES); //let tick = world.tick_tracker().tick_when(Q::MUTATES);
Self { Self {
world, world,
tick: world.current_tick(), tick: world.current_tick(),
entity,
query query
} }
} }
pub fn get(self) -> Option<Q::Item<'a>> { pub fn get(&self, entity: Entity) -> Option<Q::Item<'a>> {
if let Some(record) = self.world.entities.arch_index.get(&self.entity) { if let Some(record) = self.world.entities.arch_index.get(&entity.id()) {
let arch = self.world.archetypes.get(&record.id) let arch = self.world.archetypes.get(&record.id)
.expect("An invalid record was specified for an entity"); .expect("An invalid record was specified for an entity");
@ -172,4 +172,18 @@ impl<'a, Q: Query> ViewOne<'a, Q> {
None None
} }
}
impl<Q: Query> FnArgFetcher for ViewOneState<'_, Q> {
type State = ();
type Arg<'a, 'state> = ViewOneState<'a, Q>;
unsafe fn get<'a, 'state>(_: &'state mut Self::State, world: NonNull<World>) -> Self::Arg<'a, 'state> {
let world = world.as_ref();
ViewOneState::<Q>::new(world, Q::new())
}
fn apply_deferred(_: Self::State, _: NonNull<World>) { }
fn create_state(_: NonNull<World>) -> Self::State { () }
} }

View File

@ -2,7 +2,7 @@ use std::{any::TypeId, collections::HashMap, ops::Deref, ptr::NonNull};
use atomic_refcell::{AtomicRef, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefMut};
use crate::{archetype::{Archetype, ArchetypeId}, bundle::Bundle, query::{dynamic::DynamicView, AsFilter, AsQuery, Query, Res, ResMut, ViewIter, ViewOne, ViewState}, resource::ResourceData, ComponentInfo, DynTypeId, DynamicBundle, Entities, Entity, ResourceObject, Tick, TickTracker, TrackedResource}; use crate::{archetype::{Archetype, ArchetypeId}, bundle::Bundle, query::{dynamic::DynamicView, Filter, AsFilter, AsQuery, Query, Res, ResMut, ViewIter, ViewOneState, ViewState}, resource::ResourceData, ComponentInfo, DynTypeId, DynamicBundle, Entities, Entity, ResourceObject, Tick, TickTracker, TrackedResource};
/// The id of the entity for the Archetype. /// The id of the entity for the Archetype.
/// ///
@ -397,8 +397,8 @@ impl World {
DynamicView::new(self) DynamicView::new(self)
} }
pub fn view_one<T: AsQuery>(&self, entity: Entity) -> ViewOne<T::Query> { pub fn view_one<T: AsQuery>(&self, entity: Entity) -> Option<<T::Query as Query>::Item<'_>> {
ViewOne::new(self, entity.id, T::Query::new()) ViewOneState::<T::Query>::new(self, T::Query::new()).get(entity)
} }
/// Add a resource to the world. /// Add a resource to the world.
@ -688,7 +688,7 @@ mod tests {
world.insert(e, (Vec3::rand(),)); world.insert(e, (Vec3::rand(),));
assert!(world.view_one::<&Vec3>(e).get().is_some()) assert!(world.view_one::<&Vec3>(e).is_some())
} }
#[test] #[test]
@ -698,7 +698,7 @@ mod tests {
world.insert(e, (Vec3::rand(),)); world.insert(e, (Vec3::rand(),));
assert!(world.view_one::<&Vec3>(e).get().is_some()) assert!(world.view_one::<&Vec3>(e).is_some())
} }
#[test] #[test]
@ -712,7 +712,7 @@ mod tests {
let e3 = world.spawn(v2s[2]); let e3 = world.spawn(v2s[2]);
println!("Spawned entities"); println!("Spawned entities");
let ev2 = world.view_one::<&Vec2>(e2).get() let ev2 = world.view_one::<&Vec2>(e2)
.expect("Failed to find Vec2 and Vec3 on inserted entity!"); .expect("Failed to find Vec2 and Vec3 on inserted entity!");
assert_eq!(*ev2, v2s[1]); assert_eq!(*ev2, v2s[1]);
drop(ev2); drop(ev2);
@ -722,7 +722,7 @@ mod tests {
world.insert(e, (v3,)); world.insert(e, (v3,));
println!("inserted entity"); println!("inserted entity");
let (ev2, ev3) = world.view_one::<(&Vec2, &Vec3)>(e).get() let (ev2, ev3) = world.view_one::<(&Vec2, &Vec3)>(e)
.expect("Failed to find Vec2 and Vec3 on inserted entity!"); .expect("Failed to find Vec2 and Vec3 on inserted entity!");
assert_eq!(*ev2, v2); assert_eq!(*ev2, v2);
assert_eq!(*ev3, v3); assert_eq!(*ev3, v3);
@ -747,7 +747,7 @@ mod tests {
let e = world.spawn((v,)); let e = world.spawn((v,));
let view = world.view_one::<&Vec2>(e); let view = world.view_one::<&Vec2>(e);
assert_eq!(*view.get().unwrap(), v); assert_eq!(*view.unwrap(), v);
} }
#[test] #[test]
@ -782,11 +782,11 @@ mod tests {
world.insert(first, Vec2::new(50.0, 50.0)); world.insert(first, Vec2::new(50.0, 50.0));
let pos = world.view_one::<&mut Vec2>(first).get().unwrap(); let pos = world.view_one::<&mut Vec2>(first).unwrap();
assert_eq!(*pos, Vec2::new(50.0, 50.0)); assert_eq!(*pos, Vec2::new(50.0, 50.0));
drop(pos); drop(pos);
let pos = world.view_one::<&mut Vec2>(second).get().unwrap(); let pos = world.view_one::<&mut Vec2>(second).unwrap();
assert_eq!(*pos, Vec2::new(5.0, 5.0)); assert_eq!(*pos, Vec2::new(5.0, 5.0));
} }

View File

@ -43,8 +43,6 @@ impl TransformsNode {
fn process_component_queue(world: &mut lyra_ecs::World, component_queue: Vec<(Entity, Option<InterpTransform>, Option<TransformIndex>)>) { fn process_component_queue(world: &mut lyra_ecs::World, component_queue: Vec<(Entity, Option<InterpTransform>, Option<TransformIndex>)>) {
for (en, interp, index) in component_queue { for (en, interp, index) in component_queue {
println!("writing index {:?} for entity {}", index, en.id().0);
match (interp, index) { match (interp, index) {
(None, None) => unreachable!(), (None, None) => unreachable!(),
(None, Some(index)) => world.insert(en, index), (None, Some(index)) => world.insert(en, index),
@ -94,7 +92,7 @@ fn update_transforms(
// Interpolate the transform for this entity using a component. // Interpolate the transform for this entity using a component.
// If the entity does not have the component then it will be queued to be added // If the entity does not have the component then it will be queued to be added
// to it after all the entities are prepared for rendering. // to it after all the entities are prepared for rendering.
let transform = match interp_tran { /* let transform = match interp_tran {
Some(mut interp_transform) => { Some(mut interp_transform) => {
// found in https://youtu.be/YJB1QnEmlTs?t=472 // found in https://youtu.be/YJB1QnEmlTs?t=472
interp_transform.alpha = 1.0 - interp_transform.alpha.powf(*delta_time); interp_transform.alpha = 1.0 - interp_transform.alpha.powf(*delta_time);
@ -112,6 +110,21 @@ fn update_transforms(
component_queue.push((entity, Some(interp), None)); component_queue.push((entity, Some(interp), None));
transform transform
} }
}; */
let transform = match interp_tran {
Some(mut interp_transform) => {
interp_transform.last_transform = transform;
transform
}
None => {
let interp = InterpTransform {
last_transform: transform,
alpha: 1.0,
};
component_queue.push((entity, Some(interp), None));
transform
}
}; };
// Get the TransformIndex from the entity, or reserve a new one if the entity doesn't have // Get the TransformIndex from the entity, or reserve a new one if the entity doesn't have
@ -120,11 +133,6 @@ fn update_transforms(
Some(i) => *i, Some(i) => *i,
None => { None => {
let i = buffers.reserve_transform(&device); let i = buffers.reserve_transform(&device);
debug!(
"Reserved transform index {:?} for entity {}",
i,
entity.id().0
);
component_queue.push((entity, None, Some(i))); component_queue.push((entity, None, Some(i)));
i i

View File

@ -1,24 +1,25 @@
use std::collections::VecDeque;
use glam::{UVec2, UVec3, Vec2, Vec3}; use glam::{UVec2, UVec3, Vec2, Vec3};
use lyra_ecs::{ use lyra_ecs::{
query::{Entities, View}, query::{
relation::ChildOf, filter::{Changed, Has, Not},
Commands, Component, Entity, World, Entities, View, ViewOne,
},
relation::{ChildOf, RelationOriginComponent},
Commands, Component, Entity,
}; };
use lyra_math::Transform; use lyra_math::Transform;
use lyra_reflect::Reflect; use lyra_reflect::Reflect;
use lyra_resource::ResHandle; use lyra_resource::ResHandle;
use lyra_scene::WorldTransform; use lyra_scene::WorldTransform;
use tracing::{debug, error}; use tracing::error;
use crate::{game::GameStages, plugin::Plugin}; use crate::{game::GameStages, plugin::Plugin};
use super::{AtlasSprite, TextureAtlas}; use super::{AtlasSprite, TextureAtlas};
/// A position relative to a tile on a tilemap /// A position on a tile map
#[derive(Clone, Copy, Component, Reflect)] #[derive(Clone, Copy, Component, Reflect)]
pub struct RelativeToTile { pub struct TileMapPos {
#[reflect(skip)] // TODO: impl reflect for Entity #[reflect(skip)] // TODO: impl reflect for Entity
pub tilemap_entity: Entity, pub tilemap_entity: Entity,
/// The position of the tile to spawn at. /// The position of the tile to spawn at.
@ -107,9 +108,9 @@ impl TileMap {
/// A system to update the tilemap when tiles are inserted/removed. /// A system to update the tilemap when tiles are inserted/removed.
pub fn system_tilemap_update( pub fn system_tilemap_update(
mut commands: Commands, mut commands: Commands,
view: View<(&mut TileMap, &Transform)>, view: View<(Entities, &mut TileMap)>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
for (mut map, pos) in view.into_iter() { for (map_en, mut map) in view.into_iter() {
let tile_size = map.tile_size; let tile_size = map.tile_size;
let atlas_handle = map.atlas.clone(); let atlas_handle = map.atlas.clone();
let atlas = match atlas_handle.data_ref() { let atlas = match atlas_handle.data_ref() {
@ -128,15 +129,32 @@ pub fn system_tilemap_update(
}; };
let grid = tile.tile.position * tile_size; let grid = tile.tile.position * tile_size;
let sprite_pos = *pos let sprite_pos = Transform::from_xyz(
+ Transform::from_xyz( grid.x as _,
grid.x as _, // expand the grid downwards so 0,0 is top left of the tilemap
grid.y as _, -(grid.y as f32),
tile.tile.z_level as _, tile.tile.z_level as _,
); );
tile.entity = Some(commands.spawn((sprite, sprite_pos, WorldTransform::default()))); let tile_en = commands.spawn((
debug!("Spawned tile at ({}, {})", grid.x, grid.y); sprite,
TileMapPos {
tilemap_entity: map_en,
position: tile.tile.position,
z_level: tile.tile.z_level,
},
tile.tile,
sprite_pos,
WorldTransform::default(),
));
commands.add_relation(tile_en, ChildOf, map_en);
tile.entity = Some(tile_en);
//debug!("Spawned tile at ({}, {})", grid.x, grid.y);
/* let tile_en = commands.spawn((sprite, sprite_pos, WorldTransform::default()));
commands.add_relation(tile_en, ChildOf, map_en);
tile.entity = Some(tile_en);
debug!("Spawned tile at ({}, {})", grid.x, grid.y); */
} else { } else {
error!( error!(
"Invalid atlas index '{}' for tile at pos '{:?}'", "Invalid atlas index '{}' for tile at pos '{:?}'",
@ -152,17 +170,22 @@ pub fn system_tilemap_update(
} }
fn system_relative_tile_position_update( fn system_relative_tile_position_update(
world: &mut World, mut commands: Commands,
view: View<(Entities, &RelativeToTile)>, view: View<
(
Entities,
&TileMapPos,
Option<&mut Transform>,
Option<&WorldTransform>,
),
(Changed<TileMapPos>, Not<Has<Tile>>),
>,
tile_map_view: ViewOne<&TileMap>,
child_of_rel_view: ViewOne<&RelationOriginComponent<ChildOf>>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let mut to_relate = VecDeque::new(); for (en, rel, pos, wpos) in view.into_iter() {
match tile_map_view.get(rel.tilemap_entity) {
for (en, rel) in view.into_iter() { Some(map) => {
match world
.view_one::<(&TileMap, &Transform)>(rel.tilemap_entity)
.get()
{
Some((map, pos)) => {
let layer = map.layers.last().unwrap(); let layer = map.layers.last().unwrap();
if let Some(tile_en) = layer if let Some(tile_en) = layer
@ -171,7 +194,27 @@ fn system_relative_tile_position_update(
.find(|t| t.tile.position == rel.position) .find(|t| t.tile.position == rel.position)
.and_then(|t| t.entity) .and_then(|t| t.entity)
{ {
to_relate.push_back((en, tile_en, Transform::from_translation(Vec3::new(0.0, 0.0, rel.z_level as _)))); if child_of_rel_view
.get(en)
.map(|rel| rel.target() != tile_en)
.unwrap_or(true)
{
commands.add_relation(en, ChildOf, tile_en);
}
if let Some(mut pos) = pos {
*pos = Transform::from_translation(Vec3::new(0.0, 0.0, rel.z_level as _));
if wpos.is_none() {
commands.insert(en, WorldTransform::from(*pos));
}
} else {
let pos =
Transform::from_translation(Vec3::new(0.0, 0.0, rel.z_level as _));
commands.insert(en, (pos, WorldTransform::from(pos)));
}
} else {
error!("Unknown tile in map at {:?}", rel.position);
} }
} }
None => { None => {
@ -183,13 +226,6 @@ fn system_relative_tile_position_update(
} }
} }
while let Some((from, to, pos)) = to_relate.pop_front() {
if world.view_one::<&WorldTransform>(from).get().is_none() {
world.add_relation(from, ChildOf, to);
world.insert(from, (pos, WorldTransform::default()));
}
}
Ok(()) Ok(())
} }

View File

@ -226,7 +226,7 @@ impl ApplicationHandler for WinitRunner {
.expect("missing window entity"); .expect("missing window entity");
// update the window and its cache so the sync system doesn't try to update the window // update the window and its cache so the sync system doesn't try to update the window
let (mut en_window, mut en_last_win) = self.app.world.view_one::<(&mut WindowOptions, &mut LastWindow)>(*en).get().unwrap(); let (mut en_window, mut en_last_win) = self.app.world.view_one::<(&mut WindowOptions, &mut LastWindow)>(*en).unwrap();
let pos = Some(DVec2::new(position.x, position.y)); let pos = Some(DVec2::new(position.x, position.y));
en_window.set_physical_cursor_position(pos); en_window.set_physical_cursor_position(pos);
en_last_win.set_physical_cursor_position(pos); en_last_win.set_physical_cursor_position(pos);
@ -242,7 +242,7 @@ impl ApplicationHandler for WinitRunner {
.expect("world missing WinitWindows resource") .expect("world missing WinitWindows resource")
.window_to_entity .window_to_entity
.get(&window_id) .get(&window_id)
.and_then(|e| self.app.world.view_one::<(&mut WindowOptions, &mut LastWindow)>(*e).get()) .and_then(|e| self.app.world.view_one::<(&mut WindowOptions, &mut LastWindow)>(*e))
.unwrap(); .unwrap();
// update the window and its cache so the sync system doesn't try to update the window // update the window and its cache so the sync system doesn't try to update the window
@ -259,7 +259,7 @@ impl ApplicationHandler for WinitRunner {
.expect("world missing WinitWindows resource") .expect("world missing WinitWindows resource")
.window_to_entity .window_to_entity
.get(&window_id) .get(&window_id)
.and_then(|e| self.app.world.view_one::<(&mut WindowOptions, &mut LastWindow)>(*e).get()) .and_then(|e| self.app.world.view_one::<(&mut WindowOptions, &mut LastWindow)>(*e))
.unwrap(); .unwrap();
window.set_physical_cursor_position(None); window.set_physical_cursor_position(None);
last_window.set_physical_cursor_position(None); last_window.set_physical_cursor_position(None);
@ -284,7 +284,7 @@ impl ApplicationHandler for WinitRunner {
.expect("world missing WinitWindows resource") .expect("world missing WinitWindows resource")
.window_to_entity .window_to_entity
.get(&window_id) .get(&window_id)
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get()) .and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e))
.unwrap(); .unwrap();
window_opts.focused = focused; window_opts.focused = focused;
}, },
@ -299,7 +299,7 @@ impl ApplicationHandler for WinitRunner {
.expect("world missing WinitWindows resource") .expect("world missing WinitWindows resource")
.window_to_entity .window_to_entity
.get(&window_id) .get(&window_id)
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get()) .and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e))
.unwrap(); .unwrap();
window_opts.scale_factor = scale_factor; window_opts.scale_factor = scale_factor;
}, },
@ -311,7 +311,7 @@ impl ApplicationHandler for WinitRunner {
.expect("world missing WinitWindows resource") .expect("world missing WinitWindows resource")
.window_to_entity .window_to_entity
.get(&window_id) .get(&window_id)
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get()) .and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e))
.unwrap(); .unwrap();
window_opts.theme = Some(theme); window_opts.theme = Some(theme);
}, },
@ -323,7 +323,7 @@ impl ApplicationHandler for WinitRunner {
.expect("world missing WinitWindows resource") .expect("world missing WinitWindows resource")
.window_to_entity .window_to_entity
.get(&window_id) .get(&window_id)
.and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e).get()) .and_then(|e| self.app.world.view_one::<&mut WindowOptions>(*e))
.unwrap(); .unwrap();
window_opts.occluded = occ; window_opts.occluded = occ;
}, },

View File

@ -224,7 +224,8 @@ impl ResourceLoader for GltfLoader {
} }
for en in graph.world().view_iter::<query::Entities>() { for en in graph.world().view_iter::<query::Entities>() {
graph.world().view_one::<(&WorldTransform, &Transform)>(en).get().expect("Scene node is missing world and local transform bundle!"); graph.world().view_one::<(&WorldTransform, &Transform)>(en)
.expect("Scene node is missing world and local transform bundle!");
} }
let graph = ResHandle::new_ready(Some(path.as_str()), graph); let graph = ResHandle::new_ready(Some(path.as_str()), graph);
@ -300,14 +301,14 @@ mod tests {
let mut node = None; let mut node = None;
//scene.world().view::<SceneNodeFlag() //scene.world().view::<SceneNodeFlag()
scene.traverse_down::<_, &WorldTransform>(|_, no, tran| { scene.traverse_down::<_, &WorldTransform>(|_, no, tran| {
tran.get().expect("scene node is missing a WorldTransform"); tran.expect("scene node is missing a WorldTransform");
node = Some(no.clone()); node = Some(no.clone());
}); });
let world = scene.world(); let world = scene.world();
let node = node.unwrap(); let node = node.unwrap();
let data = world.view_one::<(&ResHandle<Mesh>, &Transform)>(node.entity()).get(); let data = world.view_one::<(&ResHandle<Mesh>, &Transform)>(node.entity());
debug_assert!(data.is_some(), "The mesh was not loaded"); // transform will always be there debug_assert!(data.is_some(), "The mesh was not loaded"); // transform will always be there
let data = data.unwrap(); let data = data.unwrap();

View File

@ -73,17 +73,17 @@ impl<C: Component + Reflect> FromType<C> for ReflectedComponent {
}, },
fn_reflect: |world: &World, entity: Entity| { fn_reflect: |world: &World, entity: Entity| {
world.view_one::<&C>(entity) world.view_one::<&C>(entity)
.get().map(|c| c as Ref<dyn Reflect>) .map(|c| c as Ref<dyn Reflect>)
}, },
fn_reflect_mut: |world: &mut World, entity: Entity| { fn_reflect_mut: |world: &mut World, entity: Entity| {
world.view_one::<&mut C>(entity) world.view_one::<&mut C>(entity)
.get().map(|c| c as RefMut<dyn Reflect>) .map(|c| c as RefMut<dyn Reflect>)
}, },
fn_reflect_tick: |world: &World, entity: Entity| { fn_reflect_tick: |world: &World, entity: Entity| {
world.view_one::<TickOf<C>>(entity).get() world.view_one::<TickOf<C>>(entity)
}, },
fn_reflect_is_changed: |world: &World, entity: Entity| { fn_reflect_is_changed: |world: &World, entity: Entity| {
world.view_one::<Changed<C>>(entity).get() world.view_one::<Changed<C>>(entity)
} }
} }
} }

View File

@ -6,7 +6,7 @@ pub use node::*;
mod world_transform; mod world_transform;
pub use world_transform::*; pub use world_transform::*;
use lyra_ecs::{query::{Entities, ViewOne}, relation::ChildOf, Bundle, Component, World}; use lyra_ecs::{query::{Entities, Query}, relation::ChildOf, Bundle, Component, World};
use lyra_math::Transform; use lyra_math::Transform;
// So we can use lyra_ecs::Component derive macro // So we can use lyra_ecs::Component derive macro
@ -95,7 +95,7 @@ impl SceneGraph {
/// The traversal does not include the root scene node. /// The traversal does not include the root scene node.
pub fn traverse_down<F, Q>(&self, mut callback: F) pub fn traverse_down<F, Q>(&self, mut callback: F)
where where
F: FnMut(&World, &SceneNode, ViewOne<Q::Query>), F: FnMut(&World, &SceneNode, Option<<Q::Query as Query>::Item<'_>>),
Q: lyra_ecs::query::AsQuery, Q: lyra_ecs::query::AsQuery,
{ {
self.traverse_down_from::<F, Q>(self.root_node.clone(), &mut callback); self.traverse_down_from::<F, Q>(self.root_node.clone(), &mut callback);
@ -105,7 +105,7 @@ impl SceneGraph {
/// SceneNode and its world transform. /// SceneNode and its world transform.
fn traverse_down_from<F, Q>(&self, start: SceneNode, callback: &mut F) fn traverse_down_from<F, Q>(&self, start: SceneNode, callback: &mut F)
where where
F: FnMut(&World, &SceneNode, ViewOne<Q::Query>), F: FnMut(&World, &SceneNode, Option<<Q::Query as Query>::Item<'_>>),
Q: lyra_ecs::query::AsQuery, Q: lyra_ecs::query::AsQuery,
{ {
let v = self.world let v = self.world
@ -211,7 +211,7 @@ pub mod tests {
let mut idx = 0; let mut idx = 0;
scene.traverse_down::<_, &WorldTransform>(|_, _, v| { scene.traverse_down::<_, &WorldTransform>(|_, _, v| {
let pos = v.get().unwrap(); let pos = v.unwrap();
if idx == 0 { if idx == 0 {
assert_eq!(**pos, Transform::from_translation(v2s[idx])); assert_eq!(**pos, Transform::from_translation(v2s[idx]));
} else if idx == 1 { } else if idx == 1 {

View File

@ -25,7 +25,7 @@ impl SceneNode {
if let Some(parent) = self.parent { if let Some(parent) = self.parent {
let v = graph.world.view_one::<&RelationOriginComponent<ChildOf>>(parent); let v = graph.world.view_one::<&RelationOriginComponent<ChildOf>>(parent);
let p_parent = if let Some(pp) = v.get() { let p_parent = if let Some(pp) = v {
Some(pp.target()) Some(pp.target())
} else { None }; } else { None };
@ -81,7 +81,7 @@ mod tests {
let view = scene.world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>(); let view = scene.world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
crate::system_update_world_transforms(&scene.world, view).unwrap(); crate::system_update_world_transforms(&scene.world, view).unwrap();
let tran = scene.world.view_one::<&WorldTransform>(b.entity).get().unwrap(); let tran = scene.world.view_one::<&WorldTransform>(b.entity).unwrap();
assert_eq!(**tran, Transform::from_translation(Vec3::new(60.0, 60.0, 60.0))); assert_eq!(**tran, Transform::from_translation(Vec3::new(60.0, 60.0, 60.0)));
} }
} }

View File

@ -104,7 +104,7 @@ mod tests {
let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>(); let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
system_update_world_transforms(&world, view).unwrap(); system_update_world_transforms(&world, view).unwrap();
let g = world.view_one::<&WorldTransform>(child).get().unwrap(); let g = world.view_one::<&WorldTransform>(child).unwrap();
assert_eq!(**g, Transform::from_xyz(25.0, 25.0, 25.0)); assert_eq!(**g, Transform::from_xyz(25.0, 25.0, 25.0));
} }
@ -131,7 +131,7 @@ mod tests {
let mut base_offset = 25.0; let mut base_offset = 25.0;
for child in children.into_iter() { for child in children.into_iter() {
let g = world.view_one::<&WorldTransform>(child).get().unwrap(); let g = world.view_one::<&WorldTransform>(child).unwrap();
println!("Child {:?} at {:?}", child, g.translation); println!("Child {:?} at {:?}", child, g.translation);
assert_eq!(**g, Transform::from_xyz(base_offset, base_offset, base_offset)); assert_eq!(**g, Transform::from_xyz(base_offset, base_offset, base_offset));
@ -162,7 +162,7 @@ mod tests {
let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>(); let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
system_update_world_transforms(&world, view).unwrap(); system_update_world_transforms(&world, view).unwrap();
let g = world.view_one::<&WorldTransform>(five_child).get().unwrap(); let g = world.view_one::<&WorldTransform>(five_child).unwrap();
assert_eq!(**g, Transform::from_xyz(611.0, 248.0, 899.0)); assert_eq!(**g, Transform::from_xyz(611.0, 248.0, 899.0));
} }
@ -189,13 +189,13 @@ mod tests {
let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>(); let view = world.filtered_view::<(Entities, &mut WorldTransform, &Transform, Option<&ResHandle<SceneGraph>>), Not<Has<RelationOriginComponent<ChildOf>>>>();
system_update_world_transforms(&world, view).unwrap(); system_update_world_transforms(&world, view).unwrap();
let g = world.view_one::<&WorldTransform>(five_child).get().unwrap(); let g = world.view_one::<&WorldTransform>(five_child).unwrap();
assert_eq!(**g, Transform::from_xyz(536.0, 102.0, 817.0)); assert_eq!(**g, Transform::from_xyz(536.0, 102.0, 817.0));
let g = world.view_one::<&WorldTransform>(thir_chi).get().unwrap(); let g = world.view_one::<&WorldTransform>(thir_chi).unwrap();
assert_eq!(**g, Transform::from_xyz(76.0, 110.0, 42.0)); assert_eq!(**g, Transform::from_xyz(76.0, 110.0, 42.0));
let g = world.view_one::<&WorldTransform>(four_child).get().unwrap(); let g = world.view_one::<&WorldTransform>(four_child).unwrap();
assert_eq!(**g, Transform::from_xyz(100.0, 171.0, 107.0)); assert_eq!(**g, Transform::from_xyz(100.0, 171.0, 107.0));
} }
} }

View File

@ -1,9 +1,11 @@
use lyra_engine::{ use lyra_engine::{
assets::{Image, ResourceManager}, assets::{Image, ResourceManager},
ecs::{ ecs::{
query::{Res, ResMut, View}, Commands, Component, Entity, World query::{Res, View, WorldTick},
relation::{ChildOf, RelationOriginComponent},
Commands, Component, Entity, World,
}, },
game::App, game::{App, GameStages},
gltf::Gltf, gltf::Gltf,
input::{ input::{
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
@ -18,8 +20,8 @@ use lyra_engine::{
ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN,
}, },
sprite::{ sprite::{
self, AtlasAnimations, AtlasSprite, Pivot, RelativeToTile, Sprite, SpriteAnimation, self, AtlasAnimations, AtlasSprite, Pivot, Sprite, SpriteAnimation, TextureAtlas, Tile,
TextureAtlas, TileMap, TileMapPlugin, TileMap, TileMapPlugin, TileMapPos,
}, },
DeltaTime, DeltaTime,
}; };
@ -27,7 +29,6 @@ use rand::{
distributions::{Distribution, WeightedIndex}, distributions::{Distribution, WeightedIndex},
Rng, Rng,
}; };
use tracing::debug;
#[async_std::main] #[async_std::main]
async fn main() { async fn main() {
@ -105,41 +106,21 @@ async fn main() {
.with_plugin(setup_scene_plugin) .with_plugin(setup_scene_plugin)
.with_plugin(action_handler_plugin) .with_plugin(action_handler_plugin)
.with_plugin(TileMapPlugin) .with_plugin(TileMapPlugin)
//.with_plugin(camera_debug_plugin)
.with_plugin(TopDown2dCameraPlugin) .with_plugin(TopDown2dCameraPlugin)
.with_system( .add_system_to_stage(
GameStages::Last,
"update_world_transforms", "update_world_transforms",
system_update_world_transforms, system_update_world_transforms,
&[], &[],
).with_system( )
"spawn_egg", .with_system("spawn_egg", system_spawn_egg, &[]);
system_spawn_egg,
&[],
).with_system(
"egg_location",
system_egg_location,
&[],
);
a.run(); a.run();
} }
fn setup_scene_plugin(app: &mut App) { fn setup_scene_plugin(app: &mut App) {
/* app.with_system(
"sprite_atlas_animation",
sprite::system_sprite_atlas_animation,
&[],
); */
let world = &mut app.world; let world = &mut app.world;
let resman = world.get_resource_mut::<ResourceManager>().unwrap(); let resman = world.get_resource_mut::<ResourceManager>().unwrap();
let cube_gltf = resman
.request::<Gltf>("../assets/cube-texture-embedded.gltf")
.unwrap();
cube_gltf.wait_recurse_dependencies_load().unwrap();
let cube_mesh = &cube_gltf.data_ref().unwrap().scenes[0];
let grass_tileset = resman let grass_tileset = resman
.request::<Image>("../assets/sprout_lands/Tilesets/Grass.png") .request::<Image>("../assets/sprout_lands/Tilesets/Grass.png")
.unwrap(); .unwrap();
@ -209,7 +190,7 @@ fn setup_scene_plugin(app: &mut App) {
}, },
Transform::from_xyz( Transform::from_xyz(
(map_size.x * tile_size.x) as f32 * 0.5, (map_size.x * tile_size.x) as f32 * 0.5,
(map_size.y * tile_size.y) as f32 * 0.5, (map_size.y * tile_size.y) as f32 * -0.5,
0.0, 0.0,
), ),
TopDown2dCamera { TopDown2dCamera {
@ -223,25 +204,13 @@ fn setup_scene_plugin(app: &mut App) {
struct GroundTileMap(Entity); struct GroundTileMap(Entity);
#[derive(Component)]
struct EggEntity;
fn system_egg_location(view: View<(&WorldTransform, &EggEntity)>) -> anyhow::Result<()> {
for (pos, _) in view.into_iter() {
println!("Found egg at world pos {:?}", **pos);
}
Ok(())
}
fn system_spawn_egg( fn system_spawn_egg(
mut commands: Commands, mut commands: Commands,
inputs: Res<ActionHandler>, inputs: Res<ActionHandler>,
tile_map: Res<GroundTileMap>, tile_map: Res<GroundTileMap>,
resman: Res<ResourceManager>, resman: Res<ResourceManager>,
wtick: WorldTick,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let debug_state = inputs.get_action_state("Debug").unwrap();
if inputs.was_action_just_pressed("Debug").unwrap() { if inputs.was_action_just_pressed("Debug").unwrap() {
let egg = resman let egg = resman
.request::<Image>("../assets/sprout_lands/Objects/Egg_item.png") .request::<Image>("../assets/sprout_lands/Objects/Egg_item.png")
@ -250,12 +219,14 @@ fn system_spawn_egg(
let x = rand::thread_rng().gen_range(0..32); let x = rand::thread_rng().gen_range(0..32);
let y = rand::thread_rng().gen_range(0..16); let y = rand::thread_rng().gen_range(0..16);
let rtt = RelativeToTile { let rtt = TileMapPos {
tilemap_entity: tile_map.0, tilemap_entity: tile_map.0,
position: UVec2::new(x, y), position: UVec2::new(x, y),
z_level: -9, z_level: 2,
}; };
//println!("Spawned egg at ({}, {}) on tick {}", x, y, **wtick);
commands.spawn(( commands.spawn((
Sprite { Sprite {
texture: egg, texture: egg,
@ -263,7 +234,6 @@ fn system_spawn_egg(
pivot: Pivot::TopLeft, pivot: Pivot::TopLeft,
}, },
rtt, rtt,
EggEntity
)); ));
} }