performance optimizations
This commit is contained in:
parent
f3c64d8dac
commit
8c38f76e5a
|
|
@ -68,7 +68,9 @@ public extension Entity {
|
|||
|
||||
@discardableResult
|
||||
public final func assign(_ components: Component...) -> Entity {
|
||||
components.forEach { assign($0) }
|
||||
for component: Component in components {
|
||||
assign(component)
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
extension Family {
|
||||
public func iterateMembers(_ apply: @escaping (EntityIdentifier) -> Void) {
|
||||
memberIds.forEach { (entityId: EntityIdentifier) -> Void in
|
||||
for entityId in memberIds {
|
||||
apply(entityId)
|
||||
}
|
||||
}
|
||||
|
|
@ -17,8 +17,7 @@ extension Family {
|
|||
|
||||
public func iterate<A>(components _: A.Type, _ apply: @escaping (EntityIdentifier, A?) -> Void)
|
||||
where A: Component {
|
||||
var iter = memberIds.makeIterator()
|
||||
while let entityId: EntityIdentifier = iter.next() {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
apply(entityId, a)
|
||||
}
|
||||
|
|
@ -26,8 +25,7 @@ extension Family {
|
|||
|
||||
public func iterate<A, B>(components _: A.Type, _: B.Type, _ apply: @escaping (EntityIdentifier, A?, B?) -> Void)
|
||||
where A: Component, B: Component {
|
||||
var iter = memberIds.makeIterator()
|
||||
while let entityId: EntityIdentifier = iter.next() {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
apply(entityId, a, b)
|
||||
|
|
@ -36,8 +34,7 @@ extension Family {
|
|||
|
||||
public func iterate<A, B, C>(components _: A.Type, _: B.Type, _: C.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?) -> Void)
|
||||
where A: Component, B: Component, C: Component {
|
||||
var iter = memberIds.makeIterator()
|
||||
while let entityId: EntityIdentifier = iter.next() {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let c: C? = self.nexus.get(for: entityId)
|
||||
|
|
@ -47,8 +44,7 @@ extension Family {
|
|||
|
||||
public func iterate<A, B, C, D>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?) -> Void)
|
||||
where A: Component, B: Component, C: Component, D: Component {
|
||||
var iter = memberIds.makeIterator()
|
||||
while let entityId: EntityIdentifier = iter.next() {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let c: C? = self.nexus.get(for: entityId)
|
||||
|
|
@ -58,8 +54,7 @@ extension Family {
|
|||
}
|
||||
public func iterate<A, B, C, D, E>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _: E.Type, _ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?) -> Void)
|
||||
where A: Component, B: Component, C: Component, D: Component, E: Component {
|
||||
var iter = memberIds.makeIterator()
|
||||
while let entityId: EntityIdentifier = iter.next() {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let c: C? = self.nexus.get(for: entityId)
|
||||
|
|
@ -72,8 +67,7 @@ extension Family {
|
|||
public func iterate<A, B, C, D, E, F>(components _: A.Type, _: B.Type, _: C.Type, _: D.Type, _: E.Type, _: F.Type,
|
||||
_ apply: @escaping (EntityIdentifier, A?, B?, C?, D?, E?, F?) -> Void)
|
||||
where A: Component, B: Component, C: Component, D: Component, E: Component, F: Component {
|
||||
var iter = memberIds.makeIterator()
|
||||
while let entityId: EntityIdentifier = iter.next() {
|
||||
for entityId in memberIds {
|
||||
let a: A? = self.nexus.get(for: entityId)
|
||||
let b: B? = self.nexus.get(for: entityId)
|
||||
let c: C? = self.nexus.get(for: entityId)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,12 @@ extension Nexus {
|
|||
let componentId = component.identifier
|
||||
let entityIdx = entity.identifier.index
|
||||
let hash: EntityComponentHash = componentId.hashValue(using: entityIdx)
|
||||
assert(!has(hash), "ComponentAdd collision: \(entityIdx) already has a component \(component)")
|
||||
/// test if component is already assigned
|
||||
guard !has(hash) else {
|
||||
report("ComponentAdd collision: \(entityIdx) already has a component \(component)")
|
||||
// TODO: replace component?! copy properties?!
|
||||
return
|
||||
}
|
||||
var newComponentIndex: ComponentIndex = ComponentIndex.invalid
|
||||
if componentsByType[componentId] != nil {
|
||||
newComponentIndex = componentsByType[componentId]!.count // TODO: get next free index
|
||||
|
|
@ -40,17 +45,11 @@ extension Nexus {
|
|||
}
|
||||
|
||||
// assigns the component id to the entity id
|
||||
// FIXME: expensive
|
||||
if componentIdsByEntity[entityIdx] != nil {
|
||||
let (inserted, _) = componentIdsSetByEntity[entityIdx]!.insert(componentId)
|
||||
assert(inserted)
|
||||
let newIndex = componentIdsByEntity[entityIdx]!.count
|
||||
componentIdsByEntity[entityIdx]!.insert(componentId, at: newIndex)
|
||||
componentIdsByEntityLookup[hash] = newIndex
|
||||
let endIndex: Int = componentIdsByEntity[entityIdx]!.count
|
||||
componentIdsByEntity[entityIdx]!.append(componentId) // Amortized O(1)
|
||||
componentIdsByEntityLookup[hash] = endIndex
|
||||
} else {
|
||||
componentIdsSetByEntity[entityIdx] = Set<ComponentIdentifier>(minimumCapacity: 2)
|
||||
let (inserted, _) = componentIdsSetByEntity[entityIdx]!.insert(componentId)
|
||||
assert(inserted)
|
||||
componentIdsByEntity[entityIdx] = ComponentIdentifiers(arrayLiteral: componentId)
|
||||
componentIdsByEntityLookup[hash] = 0
|
||||
}
|
||||
|
|
@ -60,7 +59,7 @@ extension Nexus {
|
|||
|
||||
// FIXME: this is costly for many families
|
||||
let entityId: EntityIdentifier = entity.identifier
|
||||
familiyByTraitHash.forEach { (_, family) in
|
||||
for (_, family) in familiyByTraitHash {
|
||||
update(membership: family, for: entityId)
|
||||
}
|
||||
|
||||
|
|
@ -111,13 +110,6 @@ extension Nexus {
|
|||
}
|
||||
|
||||
// MARK: unassign component
|
||||
|
||||
guard componentIdsSetByEntity[entityId.index]?.remove(componentId) != nil else {
|
||||
assert(false, "ComponentRemove failure: no component found to be removed in set")
|
||||
report("ComponentRemove failure: no component found to be removed in set")
|
||||
return false
|
||||
}
|
||||
|
||||
guard let removeIndex: ComponentIdsByEntityIndex = componentIdsByEntityLookup.removeValue(forKey: hash) else {
|
||||
assert(false, "ComponentRemove failure: no component found to be removed")
|
||||
report("ComponentRemove failure: no component found to be removed")
|
||||
|
|
@ -140,7 +132,7 @@ extension Nexus {
|
|||
}
|
||||
|
||||
// FIXME: this is costly for many families
|
||||
familiyByTraitHash.forEach { (_, family) in
|
||||
for (_, family) in familiyByTraitHash {
|
||||
update(membership: family, for: entityId)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,14 @@ extension Nexus {
|
|||
/// - noneComponents: none component type may appear in this family.
|
||||
/// - oneComponents: at least one of component types must appear in this family.
|
||||
/// - Returns: family with given traits.
|
||||
public func family(requiresAll allComponents: [Component.Type], excludesAll noneComponents: [Component.Type], needsAtLeastOne oneComponents: [Component.Type] = []) -> Family {
|
||||
|
||||
public func family(requiresAll allComponents: [Component.Type],
|
||||
excludesAll noneComponents: [Component.Type],
|
||||
needsAtLeastOne oneComponents: [Component.Type] = []) -> Family {
|
||||
let traits = FamilyTraitSet(requiresAll: allComponents, excludesAll: noneComponents, needsAtLeastOne: oneComponents)
|
||||
return family(with: traits)
|
||||
}
|
||||
|
||||
public func family(with traits: FamilyTraitSet) -> Family {
|
||||
guard let family: Family = get(family: traits) else {
|
||||
return create(family: traits)
|
||||
}
|
||||
|
|
@ -26,10 +30,12 @@ extension Nexus {
|
|||
|
||||
public func canBecomeMember(_ entity: Entity, in family: Family) -> Bool {
|
||||
let entityIdx: EntityIndex = entity.identifier.index
|
||||
guard let componentSet: ComponentSet = componentIdsSetByEntity[entityIdx] else {
|
||||
guard let componentIds: ComponentIdentifiers = componentIdsByEntity[entityIdx] else {
|
||||
assert(false, "no component set defined for entity: \(entity)")
|
||||
return false
|
||||
}
|
||||
// FIXME: may be a bottle neck
|
||||
let componentSet: ComponentSet = ComponentSet.init(componentIds)
|
||||
return family.traits.isMatch(components: componentSet)
|
||||
}
|
||||
|
||||
|
|
@ -64,8 +70,8 @@ extension Nexus {
|
|||
assert(replaced == nil, "Family with exact trait hash already exists: \(traitHash)")
|
||||
|
||||
// FIXME: this is costly for many entities
|
||||
entities.forEach {
|
||||
update(membership: family, for: $0.identifier)
|
||||
for entity: Entity in entities {
|
||||
update(membership: family, for: entity.identifier)
|
||||
}
|
||||
|
||||
notify(FamilyCreated(family: traits))
|
||||
|
|
@ -78,7 +84,9 @@ extension Nexus {
|
|||
|
||||
func update(membership family: Family, for entityId: EntityIdentifier) {
|
||||
let entityIdx: EntityIndex = entityId.index
|
||||
guard let componentsSet: ComponentSet = componentIdsSetByEntity[entityIdx] else { return }
|
||||
guard let componentIds: ComponentIdentifiers = componentIdsByEntity[entityIdx] else { return }
|
||||
// FIXME: bottle neck
|
||||
let componentsSet: ComponentSet = ComponentSet.init(componentIds)
|
||||
let isMember: Bool = family.isMember(entityId)
|
||||
let isMatch: Bool = family.traits.isMatch(components: componentsSet)
|
||||
switch (isMatch, isMember) {
|
||||
|
|
|
|||
|
|
@ -53,14 +53,12 @@ public class Nexus {
|
|||
var familiyByTraitHash: [FamilyTraitSetHash: Family]
|
||||
var trashMap: TraitEntityIdHashSet
|
||||
var familyMembersByTraitHash: [FamilyTraitSetHash: EntityIds]
|
||||
var componentIdsSetByEntity: [EntityIndex: ComponentSet]
|
||||
|
||||
public init() {
|
||||
entities = Entities()
|
||||
componentsByType = [:]
|
||||
componentIndexByEntityComponentHash = [:]
|
||||
componentIdsByEntity = [:]
|
||||
componentIdsSetByEntity = [:]
|
||||
componentIdsByEntityLookup = [:]
|
||||
freeEntities = ContiguousArray<EntityIdentifier>()
|
||||
familiyByTraitHash = [:]
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ class NexusTests: XCTestCase {
|
|||
|
||||
let p0 = Position(x: 1, y: 2)
|
||||
|
||||
e0.assign(p0)
|
||||
e0.assign(p0)
|
||||
|
||||
XCTAssert(e0.isValid)
|
||||
|
|
|
|||
Loading…
Reference in New Issue