diff --git a/Sources/FirebladeECS/Family+Members.swift b/Sources/FirebladeECS/Family+Members.swift
index b305b86..a31ca49 100644
--- a/Sources/FirebladeECS/Family+Members.swift
+++ b/Sources/FirebladeECS/Family+Members.swift
@@ -5,55 +5,137 @@
// Created by Christian Treffs on 20.10.17.
//
-public protocol FamilyIterable {
- func forEachMember(_ applyToMember: (Entity) -> Void)
- func forEachMember(_ applyToMember: (Entity, A) -> Void) where A: Component
- func forEachMember(_ applyToMember: (Entity, A, B) -> Void) where A: Component, B: Component
- func forEachMember(_ applyToMember: (Entity, A, B, C) -> Void) where A: Component, B: Component, C: Component
- func forEachMember(_ applyToMember: (Entity, A, B, C, D) -> Void) where A: Component, B: Component, C: Component, D: Component
- func forEachMember(_ applyToMember: (Entity, A, B, C, D, E) -> Void) where A: Component, B: Component, C: Component, D: Component, E: Component
- func forEachMember(_ applyToMember: (Entity, A, B, C, D, E, F) -> Void) where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component
-
+extension Family {
+ public func iterateMembers(_ apply: @escaping (EntityIdentifier, () -> Entity) -> Void) {
+ memberIds.forEach { (entityId: EntityIdentifier) -> Void in
+ func getEntity() -> Entity {
+ return nexus.get(entity: entityId)
+ }
+ apply(entityId, getEntity)
+ }
+ }
}
-extension Family/*: FamilyIterable*/ {
- public func forEachMember(_ applyToMember: (Entity) -> Void) {
- members.forEach { applyToMember(nexus.get(entity: $0)!) }
- }
+extension Family {
- public func forEachMember(_ applyToMember: (Entity, () -> A?) -> Void) where A: Component {
- forEachMember { (entity: Entity) in
- applyToMember(entity, entity.component())
+ public func iterate(components _: A.Type, _ apply: @escaping (() -> Entity, () -> A?) -> Void)
+ where A: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent)
}
}
- public func forEachMember(_ applyToMember: (Entity, () -> A?, () -> B?) -> Void) where A: Component, B: Component {
- forEachMember { (entity: Entity) in
- applyToMember(entity, entity.component(), entity.component())
+ public func iterate(components _: A.Type, _: B.Type, _ apply: @escaping (() -> Entity, () -> A?, () -> B?) -> Void)
+ where A: Component, B: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent)
}
}
- public func forEachMember(_ applyToMember: (Entity, () -> A?, () -> B?, () -> C?) -> Void) where A: Component, B: Component, C: Component {
- forEachMember { (entity: Entity) in
- applyToMember(entity, entity.component(), entity.component(), entity.component())
+ public func iterate(components _: A.Type, _: B.Type, _: C.Type, _ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?) -> Void)
+ where A: Component, B: Component, C: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent, getComponent)
}
}
- public func forEachMember(_ applyToMember: (Entity, () -> A?, () -> B?, () -> C?, () -> D?) -> Void) where A: Component, B: Component, C: Component, D: Component {
- forEachMember { (entity: Entity) in
- applyToMember(entity, entity.component(), entity.component(), entity.component(), entity.component())
+ public func iterate(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?, () -> D?) -> Void)
+ where A: Component, B: Component, C: Component, D: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent, getComponent, getComponent)
+ }
+ }
+ public func iterate(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _: E.Type, _ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?, () -> D?, () -> E?) -> Void)
+ where A: Component, B: Component, C: Component, D: Component, E: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent, getComponent, getComponent, getComponent)
}
}
- public func forEachMember(_ applyToMember: (Entity, () -> A?, () -> B?, () -> C?, () -> D?, () -> E?) -> Void) where A: Component, B: Component, C: Component, D: Component, E: Component {
- forEachMember { (entity: Entity) in
- applyToMember(entity, entity.component(), entity.component(), entity.component(), entity.component(), entity.component())
+ public func iterate(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _: E.Type, _: F.Type,
+ _ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?, () -> D?, () -> E?, () -> F?) -> Void)
+ where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent, getComponent, getComponent, getComponent, getComponent)
+ }
+ }
+}
+
+extension Family {
+
+ public func iterate(_ apply: @escaping (() -> Entity, () -> A?) -> Void) where A: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent)
}
}
- public func forEachMember(_ applyToMember: (Entity, () -> A?, () -> B?, () -> C?, () -> D?, () -> E?, () -> F?) -> Void) where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
- forEachMember { (entity: Entity) in
- applyToMember(entity, entity.component(), entity.component(), entity.component(), entity.component(), entity.component(), entity.component())
+ public func iterate(_ apply: @escaping (() -> Entity, () -> A?, () -> B?) -> Void)
+ where A: Component, B: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent)
+ }
+ }
+
+ public func iterate(_ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?) -> Void)
+ where A: Component, B: Component, C: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent, getComponent)
+ }
+ }
+
+ public func iterate(_ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?, () -> D?) -> Void)
+ where A: Component, B: Component, C: Component, D: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent, getComponent, getComponent)
+ }
+ }
+
+ public func iterate(_ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?, () -> D?, () -> E?) -> Void)
+ where A: Component, B: Component, C: Component, D: Component, E: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent, getComponent, getComponent, getComponent)
+ }
+ }
+
+ public func iterate(_ apply: @escaping (() -> Entity, () -> A?, () -> B?, () -> C?, () -> D?, () -> E?, () -> F?) -> Void) where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
+ iterateMembers { (entityId, getEntityInstance) in
+ func getComponent() -> Z? where Z: Component {
+ return self.nexus.get(component: Z.identifier, for: entityId) as? Z
+ }
+ apply(getEntityInstance, getComponent, getComponent, getComponent, getComponent, getComponent, getComponent)
}
}
diff --git a/Sources/FirebladeECS/Family.swift b/Sources/FirebladeECS/Family.swift
index c524428..0ffde41 100644
--- a/Sources/FirebladeECS/Family.swift
+++ b/Sources/FirebladeECS/Family.swift
@@ -30,7 +30,10 @@ extension Family {
return nexus.isMember(entity, in: self)
}
- internal var members: EntitySet {
+ internal var members: LazyMapCollection>, Entity> {
+ return nexus.members(of: self)
+ }
+ internal var memberIds: EntityIdSet {
return nexus.members(of: self)
}
}
diff --git a/Sources/FirebladeECS/Nexus+Component.swift b/Sources/FirebladeECS/Nexus+Component.swift
index d18e3ff..481d51f 100644
--- a/Sources/FirebladeECS/Nexus+Component.swift
+++ b/Sources/FirebladeECS/Nexus+Component.swift
@@ -71,6 +71,13 @@ extension Nexus {
return get(hash)
}
+ public func get(component componentId: ComponentIdentifier, for entityId: EntityIdentifier) -> Component? {
+ let hash: EntityComponentHash = componentId.hashValue(using: entityId.index)
+ guard let componentIdx: ComponentIndex = componentIndexByEntityComponentHash[hash] else { return nil }
+ guard let uniformComponents: UniformComponents = componentsByType[componentId] else { return nil }
+ return uniformComponents[componentIdx]
+ }
+
fileprivate func get(_ hash: EntityComponentHash) -> C? where C: Component {
Log.info("GETTING: \(C.self)")
let componentId: ComponentIdentifier = C.identifier
diff --git a/Sources/FirebladeECS/Nexus+Entity.swift b/Sources/FirebladeECS/Nexus+Entity.swift
index fb5ecec..0fc534c 100644
--- a/Sources/FirebladeECS/Nexus+Entity.swift
+++ b/Sources/FirebladeECS/Nexus+Entity.swift
@@ -51,9 +51,7 @@ extension Nexus {
return isValid(entity: entityId)
}
- public func get(entity entityId: EntityIdentifier) -> Entity? {
- Log.info("GETTING ENTITY: \(entityId)")
- guard has(entity: entityId) else { return nil }
+ public func get(entity entityId: EntityIdentifier) -> Entity {
return entities[entityId.index]
}
diff --git a/Sources/FirebladeECS/Nexus+Family.swift b/Sources/FirebladeECS/Nexus+Family.swift
index f265539..fdbd5b2 100644
--- a/Sources/FirebladeECS/Nexus+Family.swift
+++ b/Sources/FirebladeECS/Nexus+Family.swift
@@ -33,11 +33,15 @@ extension Nexus {
return family.traits.isMatch(components: componentSet)
}
- public func members(of family: Family) -> EntitySet {
+ public func members(of family: Family) -> EntityIdSet {
let traitHash: FamilyTraitSetHash = family.traits.hashValue
return familyMembersByTraitHash[traitHash] ?? [] // FIXME: fail?
}
+ public func members(of family: Family) -> LazyMapCollection>, Entity> {
+ return members(of: family).lazy.flatMap { self.get(entity: $0) }
+ }
+
public func isMember(_ entity: Entity, in family: Family) -> Bool {
let traitHash: FamilyTraitSetHash = family.traits.hashValue
let entityId = entity.identifier
@@ -82,7 +86,7 @@ extension Nexus {
let (inserted, _) = familyMembersByTraitHash[traitHash]!.insert(entityId)
assert(inserted, "entity with id \(entityId) already in family")
} else {
- familyMembersByTraitHash[traitHash] = EntitySet(minimumCapacity: 2)
+ familyMembersByTraitHash[traitHash] = EntityIdSet(minimumCapacity: 2)
familyMembersByTraitHash[traitHash]!.insert(entityId)
}
diff --git a/Sources/FirebladeECS/Nexus.swift b/Sources/FirebladeECS/Nexus.swift
index 04de58d..3dd81f7 100644
--- a/Sources/FirebladeECS/Nexus.swift
+++ b/Sources/FirebladeECS/Nexus.swift
@@ -18,7 +18,7 @@ public typealias UniformComponents = ContiguousArray
public typealias ComponentIdentifiers = ContiguousArray
public typealias ComponentSet = Set
public typealias Entities = ContiguousArray
-public typealias EntitySet = Set
+public typealias EntityIdSet = Set
public typealias FamilyTraitSetHash = Int
public class Nexus {
@@ -47,7 +47,7 @@ public class Nexus {
var freeEntities: ContiguousArray
var familiyByTraitHash: [FamilyTraitSetHash: Family]
- var familyMembersByTraitHash: [FamilyTraitSetHash: EntitySet]
+ var familyMembersByTraitHash: [FamilyTraitSetHash: EntityIdSet]
var componentIdsSetByEntity: [EntityIndex: ComponentSet]
public init() {
@@ -67,7 +67,7 @@ public class Nexus {
extension Nexus {
func notify(_ event: Event) {
- Log.debug(event)
+ //Log.debug(event)
// TODO: implement
}
diff --git a/Tests/FirebladeECSTests/FamilyTests.swift b/Tests/FirebladeECSTests/FamilyTests.swift
index aed2203..d8853c8 100644
--- a/Tests/FirebladeECSTests/FamilyTests.swift
+++ b/Tests/FirebladeECSTests/FamilyTests.swift
@@ -77,11 +77,12 @@ class FamilyTests: XCTestCase {
var index: Int = 0
- family.forEachMember { (e: Entity, p: () -> Position!, v: () -> Velocity!, n: () -> Name?) in
+ family.iterate { (e: () -> Entity, p: () -> Position!, v: () -> Velocity!, n: () -> Name?) in
- p()!.x = 10
+ let pos: Position = p()
+ pos.x = 10
- print(e, p(), n())
+ print(e(), pos, n())
if index == 0 {
print(v())
}
@@ -89,9 +90,19 @@ class FamilyTests: XCTestCase {
index += 1
}
- family.forEachMember { (e: Entity, p: () -> Position!, v: () -> Velocity!, n: () -> Name?) in
+ family.iterate(components: Position.self, Velocity.self, Name.self) { (_, pos, vel, nm) in
+ let position: Position = pos()!
+ let velocity: Velocity = vel()!
+ let name: Name? = nm()
- print(e, p().x, n())
+ _ = position
+ _ = velocity
+ _ = name
+ }
+
+ family.iterate { (e: () -> Entity, p: () -> Position!, v: () -> Velocity!, n: () -> Name?) in
+
+ print(e(), p().x, n())
if index == 0 {
print(v())
}
@@ -101,4 +112,83 @@ class FamilyTests: XCTestCase {
}
+ func testMeasureFamilyIteration() {
+ let nexus = Nexus()
+ let number: Int = 10_000
+
+ for i in 0.. Entity, pos: () -> Position!, vel: () -> Velocity!, nm: () -> Name?) in
+ let name: Name? = nm()
+ let velocity: Velocity = vel()!
+ let position: Position = pos()!
+
+ _ = position
+ _ = velocity
+ _ = name
+ }
+ }
+
+ }
+
+ func testMeasureEntityIteration() {
+ let nexus = Nexus()
+ let number: Int = 10_000
+
+ for i in 0..