Finish basic scene graph implementation

This commit is contained in:
Christian Treffs 2019-10-01 07:06:00 +02:00
parent 8958d96687
commit 71a319fe27
1 changed files with 35 additions and 8 deletions

View File

@ -134,25 +134,52 @@ extension Family.EntityComponentIterator: LazySequenceProtocol { }
// MARK: - relatives iterator // MARK: - relatives iterator
extension Family { extension Family {
@inlinable public var descendRelatives: RelativesIterator { @inlinable
return RelativesIterator(family: self) public func descendRelatives(from root: Entity) -> RelativesIterator {
return RelativesIterator(family: self, root: root)
} }
public struct RelativesIterator: IteratorProtocol { public struct RelativesIterator: IteratorProtocol {
@usableFromInline var memberIdsIterator: UnorderedSparseSetIterator<EntityIdentifier>
@usableFromInline unowned let nexus: Nexus @usableFromInline unowned let nexus: Nexus
@usableFromInline let familyTraits: FamilyTraitSet
public init(family: Family<R>) { @usableFromInline var relatives: [(EntityIdentifier, EntityIdentifier)]
public init(family: Family<R>, root: Entity) {
self.nexus = family.nexus self.nexus = family.nexus
memberIdsIterator = family.memberIds.makeIterator() self.familyTraits = family.traits
// FIXME: this is not the most efficient way to aggregate all parent child tuples
// Problems:
// - allocates new memory
// - needs to be build on every iteration
// - relies on isMember check
self.relatives = []
self.relatives.reserveCapacity(family.memberIds.count)
aggregateRelativesBreathFirst(root.identifier)
relatives.reverse()
}
mutating func aggregateRelativesBreathFirst(_ parent: EntityIdentifier) {
guard let children = nexus.parentChildrenMap[parent] else {
return
}
children
.compactMap { child in
guard nexus.isMember(child, in: familyTraits) else {
return nil
}
relatives.append((parent, child))
return child
}
.forEach { aggregateRelativesBreathFirst($0) }
} }
public mutating func next() -> R.RelativesDescending? { public mutating func next() -> R.RelativesDescending? {
guard let parentId = memberIdsIterator.next() else { guard let (parentId, childId) = relatives.popLast() else {
return nil return nil
} }
return R.relativesDescending(nexus: nexus, parentId: parentId, childId: childId)
return nil
} }
} }
} }