Refine multiple component creation
This commit is contained in:
parent
242f7993d6
commit
96ef53cf6d
|
|
@ -22,31 +22,9 @@ extension Nexus {
|
||||||
}
|
}
|
||||||
|
|
||||||
public final func assign(component: Component, to entity: Entity) {
|
public final func assign(component: Component, to entity: Entity) {
|
||||||
let componentId: ComponentIdentifier = component.identifier
|
|
||||||
let entityId: EntityIdentifier = entity.identifier
|
let entityId: EntityIdentifier = entity.identifier
|
||||||
|
assign(component: component, entityId: entityId)
|
||||||
// test if component is already assigned
|
delegate?.nexusEvent(ComponentAdded(component: component.identifier, toEntity: entity.identifier))
|
||||||
guard !has(componentId: componentId, entityId: entityId) else {
|
|
||||||
delegate?.nexusNonFatalError("ComponentAdd collision: \(entityId) already has a component \(component)")
|
|
||||||
assertionFailure("ComponentAdd collision: \(entityId) already has a component \(component)")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// add component instances to uniform component stores
|
|
||||||
if componentsByType[componentId] == nil {
|
|
||||||
componentsByType[componentId] = ManagedContiguousArray<Component>()
|
|
||||||
}
|
|
||||||
componentsByType[componentId]?.insert(component, at: entityId.id)
|
|
||||||
|
|
||||||
// assigns the component id to the entity id
|
|
||||||
if componentIdsByEntity[entityId] == nil {
|
|
||||||
componentIdsByEntity[entityId] = Set<ComponentIdentifier>()
|
|
||||||
}
|
|
||||||
componentIdsByEntity[entityId]?.insert(componentId) //, at: componentId.hashValue)
|
|
||||||
|
|
||||||
update(familyMembership: entityId)
|
|
||||||
|
|
||||||
delegate?.nexusEvent(ComponentAdded(component: componentId, toEntity: entity.identifier))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final func assign<C>(component: C, to entity: Entity) where C: Component {
|
public final func assign<C>(component: C, to entity: Entity) where C: Component {
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,14 @@ extension Nexus {
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func createEntity(with components: Component...) -> Entity {
|
public func createEntity(with components: Component...) -> Entity {
|
||||||
let newEntity = createEntity()
|
let newEntity = createEntity()
|
||||||
components.forEach { newEntity.assign($0) }
|
assign(components: components, to: newEntity.identifier)
|
||||||
return newEntity
|
return newEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
public func createEntity<C>(with components: C) -> Entity where C: Collection, C.Element == Component {
|
public func createEntity<C>(with components: C) -> Entity where C: Collection, C.Element == Component {
|
||||||
let entity = self.createEntity()
|
let entity = self.createEntity()
|
||||||
components.forEach { entity.assign($0) }
|
assign(components: components, to: entity.identifier)
|
||||||
return entity
|
return entity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
//
|
|
||||||
// Nexus+FamilyUpdate.swift
|
|
||||||
// FirebladeECS
|
|
||||||
//
|
|
||||||
// Created by Christian Treffs on 14.02.19.
|
|
||||||
//
|
|
||||||
|
|
||||||
extension Nexus {
|
|
||||||
/// will be called on family init
|
|
||||||
final func onFamilyInit(traits: FamilyTraitSet) {
|
|
||||||
guard familyMembersByTraits[traits] == nil else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
familyMembersByTraits[traits] = UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>()
|
|
||||||
update(familyMembership: traits)
|
|
||||||
}
|
|
||||||
|
|
||||||
final func update(familyMembership traits: FamilyTraitSet) {
|
|
||||||
// FIXME: iterating all entities is costly for many entities
|
|
||||||
var iter = entityStorage.makeIterator()
|
|
||||||
while let entityId = iter.next() {
|
|
||||||
update(membership: traits, for: entityId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final func update(familyMembership entityId: EntityIdentifier) {
|
|
||||||
// FIXME: iterating all families is costly for many families
|
|
||||||
var iter = familyMembersByTraits.keys.makeIterator()
|
|
||||||
while let traits = iter.next() {
|
|
||||||
update(membership: traits, for: entityId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final func update(membership traits: FamilyTraitSet, for entityId: EntityIdentifier) {
|
|
||||||
guard let componentIds = componentIdsByEntity[entityId] else {
|
|
||||||
// no components - so skip
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let isMember: Bool = self.isMember(entity: entityId, inFamilyWithTraits: traits)
|
|
||||||
if !exists(entity: entityId) && isMember {
|
|
||||||
remove(entityWithId: entityId, fromFamilyWithTraits: traits)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let isMatch: Bool = traits.isMatch(components: componentIds)
|
|
||||||
|
|
||||||
switch (isMatch, isMember) {
|
|
||||||
case (true, false):
|
|
||||||
add(entityWithId: entityId, toFamilyWithTraits: traits)
|
|
||||||
delegate?.nexusEvent(FamilyMemberAdded(member: entityId, toFamily: traits))
|
|
||||||
|
|
||||||
case (false, true):
|
|
||||||
remove(entityWithId: entityId, fromFamilyWithTraits: traits)
|
|
||||||
delegate?.nexusEvent(FamilyMemberRemoved(member: entityId, from: traits))
|
|
||||||
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final func add(entityWithId entityId: EntityIdentifier, toFamilyWithTraits traits: FamilyTraitSet) {
|
|
||||||
familyMembersByTraits[traits]!.insert(entityId, at: entityId.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
final func remove(entityWithId entityId: EntityIdentifier, fromFamilyWithTraits traits: FamilyTraitSet) {
|
|
||||||
familyMembersByTraits[traits]!.remove(at: entityId.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
//
|
||||||
|
// Nexus+Internal.swift
|
||||||
|
// FirebladeECS
|
||||||
|
//
|
||||||
|
// Created by Christian Treffs on 14.02.19.
|
||||||
|
//
|
||||||
|
|
||||||
|
extension Nexus {
|
||||||
|
func assign<C>(components: C, to entityId: EntityIdentifier) where C: Collection, C.Element == Component {
|
||||||
|
var iter = components.makeIterator()
|
||||||
|
while let component = iter.next() {
|
||||||
|
let componentId = component.identifier
|
||||||
|
// test if component is already assigned
|
||||||
|
guard !has(componentId: componentId, entityId: entityId) else {
|
||||||
|
delegate?.nexusNonFatalError("ComponentAdd collision: \(entityId) already has a component \(component)")
|
||||||
|
assertionFailure("ComponentAdd collision: \(entityId) already has a component \(component)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// add component instances to uniform component stores
|
||||||
|
insertComponentInstance(component, componentId, entityId)
|
||||||
|
|
||||||
|
// assigns the component id to the entity id
|
||||||
|
assign(componentId, entityId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update entity membership
|
||||||
|
update(familyMembership: entityId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assign(component: Component, entityId: EntityIdentifier) {
|
||||||
|
let componentId = component.identifier
|
||||||
|
|
||||||
|
// test if component is already assigned
|
||||||
|
guard !has(componentId: componentId, entityId: entityId) else {
|
||||||
|
delegate?.nexusNonFatalError("ComponentAdd collision: \(entityId) already has a component \(component)")
|
||||||
|
assertionFailure("ComponentAdd collision: \(entityId) already has a component \(component)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// add component instances to uniform component stores
|
||||||
|
insertComponentInstance(component, componentId, entityId)
|
||||||
|
|
||||||
|
// assigns the component id to the entity id
|
||||||
|
assign(componentId, entityId)
|
||||||
|
|
||||||
|
// Update entity membership
|
||||||
|
update(familyMembership: entityId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func insertComponentInstance(_ component: Component, _ componentId: ComponentIdentifier, _ entityId: EntityIdentifier) {
|
||||||
|
if componentsByType[componentId] == nil {
|
||||||
|
componentsByType[componentId] = ManagedContiguousArray<Component>()
|
||||||
|
}
|
||||||
|
componentsByType[componentId]?.insert(component, at: entityId.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assign(_ componentId: ComponentIdentifier, _ entityId: EntityIdentifier) {
|
||||||
|
if componentIdsByEntity[entityId] == nil {
|
||||||
|
componentIdsByEntity[entityId] = Set<ComponentIdentifier>(arrayLiteral: componentId)
|
||||||
|
} else {
|
||||||
|
componentIdsByEntity[entityId]?.insert(componentId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assign(_ componentIds: Set<ComponentIdentifier>, _ entityId: EntityIdentifier) {
|
||||||
|
if componentIdsByEntity[entityId] == nil {
|
||||||
|
componentIdsByEntity[entityId] = componentIds
|
||||||
|
} else {
|
||||||
|
componentIdsByEntity[entityId]?.formUnion(componentIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(familyMembership entityId: EntityIdentifier) {
|
||||||
|
// FIXME: iterating all families is costly for many families
|
||||||
|
// FIXME: this could be parallelized
|
||||||
|
var iter = familyMembersByTraits.keys.makeIterator()
|
||||||
|
while let traits = iter.next() {
|
||||||
|
update(membership: traits, for: entityId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// will be called on family init
|
||||||
|
func onFamilyInit(traits: FamilyTraitSet) {
|
||||||
|
guard familyMembersByTraits[traits] == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
familyMembersByTraits[traits] = UnorderedSparseSet<EntityIdentifier, EntityIdentifier.Id>()
|
||||||
|
update(familyMembership: traits)
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(familyMembership traits: FamilyTraitSet) {
|
||||||
|
// FIXME: iterating all entities is costly for many entities
|
||||||
|
var iter = entityStorage.makeIterator()
|
||||||
|
while let entityId = iter.next() {
|
||||||
|
update(membership: traits, for: entityId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(membership traits: FamilyTraitSet, for entityId: EntityIdentifier) {
|
||||||
|
guard let componentIds = componentIdsByEntity[entityId] else {
|
||||||
|
// no components - so skip
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let isMember: Bool = self.isMember(entity: entityId, inFamilyWithTraits: traits)
|
||||||
|
if !exists(entity: entityId) && isMember {
|
||||||
|
remove(entityWithId: entityId, fromFamilyWithTraits: traits)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let isMatch: Bool = traits.isMatch(components: componentIds)
|
||||||
|
|
||||||
|
switch (isMatch, isMember) {
|
||||||
|
case (true, false):
|
||||||
|
add(entityWithId: entityId, toFamilyWithTraits: traits)
|
||||||
|
delegate?.nexusEvent(FamilyMemberAdded(member: entityId, toFamily: traits))
|
||||||
|
|
||||||
|
case (false, true):
|
||||||
|
remove(entityWithId: entityId, fromFamilyWithTraits: traits)
|
||||||
|
delegate?.nexusEvent(FamilyMemberRemoved(member: entityId, from: traits))
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(entityWithId entityId: EntityIdentifier, toFamilyWithTraits traits: FamilyTraitSet) {
|
||||||
|
familyMembersByTraits[traits]!.insert(entityId, at: entityId.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func remove(entityWithId entityId: EntityIdentifier, fromFamilyWithTraits traits: FamilyTraitSet) {
|
||||||
|
familyMembersByTraits[traits]!.remove(at: entityId.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue