Optimized component lookup

This commit is contained in:
Christian Treffs 2017-10-16 09:22:52 +02:00
parent 669fb374d7
commit 130a5a8edd
2 changed files with 36 additions and 11 deletions

View File

@ -17,7 +17,7 @@ extension Nexus {
}
public func count(components entityId: EntityIdentifier) -> Int {
switch componentIdsByEntityIdx[entityId.index] {
switch componentIdsByEntity[entityId.index] {
case .some(let componentIds):
return componentIds.count
case .none:
@ -39,11 +39,15 @@ extension Nexus {
componentsByType[componentId] = UniformComponents(arrayLiteral: component)
}
if componentIdsByEntityIdx[entityIdx] != nil {
componentIdsByEntityIdx[entityIdx]!.append(componentId)
// assigns the component id to the entity id
if componentIdsByEntity[entityIdx] != nil {
let newIndex = componentIdsByEntity[entityIdx]!.count
componentIdsByEntity[entityIdx]!.insert(componentId, at: newIndex)
componentIdsByEntityLookup[hash] = newIndex
} else {
componentIdsByEntityIdx[entityIdx] = ComponentIdentifiers()
componentIdsByEntityIdx[entityIdx]!.append(componentId)
componentIdsByEntity[entityIdx] = ComponentIdentifiers()
componentIdsByEntity[entityIdx]!.insert(componentId, at: 0)
componentIdsByEntityLookup[hash] = 0
}
// assign entity / component to index
@ -66,13 +70,14 @@ extension Nexus {
}
public func get(components entityId: EntityIdentifier) -> ComponentIdentifiers? {
return componentIdsByEntityIdx[entityId.index]
return componentIdsByEntity[entityId.index]
}
@discardableResult
public func remove(component componentId: ComponentIdentifier, from entityId: EntityIdentifier) -> Bool {
let hash: EntityComponentHash = componentId.hashValue(using: entityId.index)
// MARK: delete component instance
guard let componentIdx: ComponentIndex = componentIndexByEntityComponentHash.removeValue(forKey: hash) else {
report("ComponentRemove failure: entity \(entityId) has no component \(componentId)")
return false
@ -84,18 +89,28 @@ extension Nexus {
return false
}
// FIXME: this is expensive
guard let removeIndex: Int = get(components: entityId)?.index(where: { $0 == componentId }) else {
// MARK: unassign component
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")
return false
}
guard componentIdsByEntityIdx[entityId.index]?.remove(at: removeIndex) != nil else {
guard componentIdsByEntity[entityId.index]?.remove(at: removeIndex) != nil else {
assert(false, "ComponentRemove failure: nothing was removed")
report("ComponentRemove failure: nothing was removed")
return false
}
// relocate remaining indices pointing in the componentsByEntity map
if let remainingComponents = componentIdsByEntity[entityId.index] {
// FIXME: may be expensive but is cheap for small entities
for (index, compId) in remainingComponents.enumerated() {
let cHash: EntityComponentHash = compId.hashValue(using: entityId.index)
componentIdsByEntityLookup[cHash] = index
}
}
notify(ComponentRemoved(component: componentId, from: entityId))
return true
}

View File

@ -4,11 +4,14 @@
//
// Created by Christian Treffs on 09.10.17.
//
/// entity id ^ component identifier hash
public typealias EntityComponentHash = Int
public typealias ComponentIndex = Int
public extension ComponentIndex {
static let invalid: ComponentIndex = Int.min
}
public typealias ComponentIdsByEntityIndex = Int
public typealias UniformComponents = ContiguousArray<Component>
public typealias ComponentIdentifiers = ContiguousArray<ComponentIdentifier>
@ -28,7 +31,13 @@ public class Nexus {
/// - Value: each element is an index pointing to the component instance index in the componentsByType map.
var componentIndexByEntityComponentHash: [EntityComponentHash: ComponentIndex]
var componentIdsByEntityIdx: [EntityIndex: ComponentIdentifiers]
/// - Key: entity id as index
/// - Value: each element is a component identifier associated with this entity
var componentIdsByEntity: [EntityIndex: ComponentIdentifiers]
/// - Key 'entity id' - 'component type' hash that uniquely links both
/// - Value: each element is an index pointing to the component identifier per entity in the componentIdsByEntity map
var componentIdsByEntityLookup: [EntityComponentHash: ComponentIdsByEntityIndex]
var freeEntities: ContiguousArray<EntityIdentifier>
@ -36,7 +45,8 @@ public class Nexus {
entities = Entities()
componentsByType = [:]
componentIndexByEntityComponentHash = [:]
componentIdsByEntityIdx = [:]
componentIdsByEntity = [:]
componentIdsByEntityLookup = [:]
freeEntities = ContiguousArray<EntityIdentifier>()
}