Fix Changed<T> by rewriting ecs `Filter`s, position `TileMapPos` entities with ChildOf relations
This commit is contained in:
parent
418765d595
commit
5a0e06f94d
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,9 +92,3 @@ 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;
|
|
||||||
}
|
|
|
@ -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;
|
||||||
}
|
} */
|
|
@ -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> {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -44,9 +44,3 @@ 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;
|
|
||||||
}
|
|
|
@ -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};
|
||||||
|
|
|
@ -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,)+) {
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
@ -173,3 +173,17 @@ 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 { () }
|
||||||
|
}
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 _,
|
||||||
grid.y as _,
|
// expand the grid downwards so 0,0 is top left of the tilemap
|
||||||
|
-(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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
},
|
},
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue