From ae283feab4e5cd0e813ce30778f3eb7f0da74daf Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Thu, 6 Aug 2020 15:53:12 +0200 Subject: [PATCH 1/3] Remove obsolete relatives implementation --- Sources/FirebladeECS/Entity.swift | 28 ---------- Sources/FirebladeECS/Family.swift | 55 ------------------- .../FamilyRequirementsManaging.swift | 3 - Sources/FirebladeECS/Nexus+Entity.swift | 2 - Sources/FirebladeECS/Nexus+SceneGraph.swift | 55 ------------------- Sources/FirebladeECS/Nexus.swift | 8 --- 6 files changed, 151 deletions(-) delete mode 100644 Sources/FirebladeECS/Nexus+SceneGraph.swift diff --git a/Sources/FirebladeECS/Entity.swift b/Sources/FirebladeECS/Entity.swift index 89fcd6d..d5a290e 100644 --- a/Sources/FirebladeECS/Entity.swift +++ b/Sources/FirebladeECS/Entity.swift @@ -102,34 +102,6 @@ public struct Entity { nexus.destroy(entity: self) } - /// Add an entity as child. - /// - Parameter entity: The child entity. - @discardableResult - @available(*, deprecated, message: "This will be removed in the next minor update.") - public func addChild(_ entity: Entity) -> Bool { - nexus.addChild(entity, to: self) - } - - /// Remove entity as child. - /// - Parameter entity: The child entity. - @discardableResult - @available(*, deprecated, message: "This will be removed in the next minor update.") - public func removeChild(_ entity: Entity) -> Bool { - nexus.removeChild(entity, from: self) - } - - /// Removes all children from this entity. - @available(*, deprecated, message: "This will be removed in the next minor update.") - public func removeAllChildren() { - nexus.removeAllChildren(from: self) - } - - /// Returns the number of children for this entity. - @available(*, deprecated, message: "This will be removed in the next minor update.") - public var numChildren: Int { - nexus.numChildren(for: self) - } - /// Returns an iterator over all components of this entity. @inlinable public func makeComponentsIterator() -> ComponentsIterator { diff --git a/Sources/FirebladeECS/Family.swift b/Sources/FirebladeECS/Family.swift index e154dc9..4ab2fd3 100644 --- a/Sources/FirebladeECS/Family.swift +++ b/Sources/FirebladeECS/Family.swift @@ -130,61 +130,6 @@ extension Family { extension Family.EntityComponentIterator: LazySequenceProtocol { } -// MARK: - relatives iterator - -extension Family { - @inlinable - public func descendRelatives(from root: Entity) -> RelativesIterator { - RelativesIterator(family: self, root: root) - } - - public struct RelativesIterator: IteratorProtocol { - @usableFromInline unowned let nexus: Nexus - @usableFromInline let familyTraits: FamilyTraitSet - - @usableFromInline var relatives: ContiguousArray<(EntityIdentifier, EntityIdentifier)> - - public init(family: Family, root: Entity) { - self.nexus = family.nexus - 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.childrenByParentEntity[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? { - guard let (parentId, childId) = relatives.popLast() else { - return nil - } - return R.relativesDescending(nexus: nexus, parentId: parentId, childId: childId) - } - } -} - -extension Family.RelativesIterator: LazySequenceProtocol { } - // MARK: - member creation extension Family { /// Create a new entity with components required by this family. diff --git a/Sources/FirebladeECS/FamilyRequirementsManaging.swift b/Sources/FirebladeECS/FamilyRequirementsManaging.swift index b3605f4..a19396a 100644 --- a/Sources/FirebladeECS/FamilyRequirementsManaging.swift +++ b/Sources/FirebladeECS/FamilyRequirementsManaging.swift @@ -9,7 +9,6 @@ public protocol FamilyRequirementsManaging { associatedtype Components associatedtype ComponentTypes associatedtype EntityAndComponents - associatedtype RelativesDescending init(_ types: ComponentTypes) @@ -17,7 +16,5 @@ public protocol FamilyRequirementsManaging { static func components(nexus: Nexus, entityId: EntityIdentifier) -> Components static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> EntityAndComponents - static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> RelativesDescending - static func createMember(nexus: Nexus, components: Components) -> Entity } diff --git a/Sources/FirebladeECS/Nexus+Entity.swift b/Sources/FirebladeECS/Nexus+Entity.swift index 7e12e80..d6146bd 100644 --- a/Sources/FirebladeECS/Nexus+Entity.swift +++ b/Sources/FirebladeECS/Nexus+Entity.swift @@ -60,8 +60,6 @@ extension Nexus { return false } - removeAllChildren(from: entityId) - if removeAll(components: entityId) { update(familyMembership: entityId) } diff --git a/Sources/FirebladeECS/Nexus+SceneGraph.swift b/Sources/FirebladeECS/Nexus+SceneGraph.swift deleted file mode 100644 index 0e2f914..0000000 --- a/Sources/FirebladeECS/Nexus+SceneGraph.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// Nexus+SceneGraph.swift -// -// -// Created by Christian Treffs on 30.09.19. -// - -extension Nexus { - @available(*, deprecated, message: "This will be removed in the next minor update.") - public final func addChild(_ child: Entity, to parent: Entity) -> Bool { - let inserted: Bool - if childrenByParentEntity[parent.identifier] == nil { - childrenByParentEntity[parent.identifier] = [child.identifier] - inserted = true - } else { - let (isNewMember, _) = childrenByParentEntity[parent.identifier]!.insert(child.identifier) - inserted = isNewMember - } - if inserted { - delegate?.nexusEvent(ChildAdded(parent: parent.identifier, child: child.identifier)) - } - return inserted - } - - @available(*, deprecated, message: "This will be removed in the next minor update.") - public final func removeChild(_ child: Entity, from parent: Entity) -> Bool { - removeChild(child.identifier, from: parent.identifier) - } - - @available(*, deprecated, message: "This will be removed in the next minor update.") - @discardableResult - public final func removeChild(_ child: EntityIdentifier, from parent: EntityIdentifier) -> Bool { - let removed: Bool = childrenByParentEntity[parent]?.remove(child) != nil - if removed { - delegate?.nexusEvent(ChildRemoved(parent: parent, child: child)) - } - return removed - } - - @available(*, deprecated, message: "This will be removed in the next minor update.") - public final func removeAllChildren(from parent: Entity) { - self.removeAllChildren(from: parent.identifier) - } - - @available(*, deprecated, message: "This will be removed in the next minor update.") - public final func removeAllChildren(from parentId: EntityIdentifier) { - childrenByParentEntity[parentId]?.forEach { removeChild($0, from: parentId) } - return childrenByParentEntity[parentId] = nil - } - - @available(*, deprecated, message: "This will be removed in the next minor update.") - public final func numChildren(for entity: Entity) -> Int { - childrenByParentEntity[entity.identifier]?.count ?? 0 - } -} diff --git a/Sources/FirebladeECS/Nexus.swift b/Sources/FirebladeECS/Nexus.swift index d40da02..cd293e1 100644 --- a/Sources/FirebladeECS/Nexus.swift +++ b/Sources/FirebladeECS/Nexus.swift @@ -23,10 +23,6 @@ public final class Nexus { /// Each element is a component identifier associated with this entity. @usableFromInline final var componentIdsByEntity: [EntityIdentifier: Set] - /// - Key: A parent entity id. - /// - Value: Adjacency Set of all associated children. - @usableFromInline final var childrenByParentEntity: [EntityIdentifier: Set] - /// - Key: FamilyTraitSet aka component types that make up one distinct family. /// - Value: Tightly packed EntityIdentifiers that represent the association of an entity to the family. @usableFromInline final var familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet] @@ -41,7 +37,6 @@ public final class Nexus { componentsByEntity: [:], entityIdGenerator: EntityIdentifierGenerator(), familyMembersByTraits: [:], - childrenByParentEntity: [:], codingStrategy: DefaultCodingStrategy()) } @@ -50,13 +45,11 @@ public final class Nexus { componentsByEntity: [EntityIdentifier: Set], entityIdGenerator: EntityIdentifierGenerator, familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet], - childrenByParentEntity: [EntityIdentifier: Set], codingStrategy: CodingStrategy) { self.entityStorage = entityStorage self.componentsByType = componentsByType self.componentIdsByEntity = componentsByEntity self.familyMembersByTraits = familyMembersByTraits - self.childrenByParentEntity = childrenByParentEntity self.entityIdGenerator = entityIdGenerator self.codingStrategy = codingStrategy } @@ -71,7 +64,6 @@ public final class Nexus { componentsByType.removeAll() componentIdsByEntity.removeAll() familyMembersByTraits.removeAll() - childrenByParentEntity.removeAll() } } From aeab748362efe89cae9b8c794f7d455bcc567018 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Thu, 6 Aug 2020 15:53:27 +0200 Subject: [PATCH 2/3] Remove obsolete relatives tests --- Tests/FirebladeECSTests/SceneGraphTests.swift | 132 ------------------ Tests/FirebladeECSTests/XCTestManifests.swift | 14 -- 2 files changed, 146 deletions(-) delete mode 100644 Tests/FirebladeECSTests/SceneGraphTests.swift diff --git a/Tests/FirebladeECSTests/SceneGraphTests.swift b/Tests/FirebladeECSTests/SceneGraphTests.swift deleted file mode 100644 index 730efce..0000000 --- a/Tests/FirebladeECSTests/SceneGraphTests.swift +++ /dev/null @@ -1,132 +0,0 @@ -// -// SceneGraphTests.swift -// FirebladeECSTests -// -// Created by Christian Treffs on 30.09.19. -// - -import FirebladeECS -import XCTest - -@available(*, deprecated, message: "This will be removed in the next minor update.") -class SceneGraphTests: XCTestCase { - var nexus: Nexus! - - override func setUp() { - super.setUp() - nexus = Nexus() - } - - override func tearDown() { - super.tearDown() - nexus = nil - } - - func testAddChild() { - let nttParrent = nexus.createEntity() - let nttChild1 = nexus.createEntity() - XCTAssertEqual(nttParrent.numChildren, 0) - XCTAssertTrue(nttParrent.addChild(nttChild1)) - XCTAssertEqual(nttParrent.numChildren, 1) - XCTAssertFalse(nttParrent.addChild(nttChild1)) - XCTAssertEqual(nttParrent.numChildren, 1) - } - - func testRemoveChild() { - let nttParrent = nexus.createEntity() - let nttChild1 = nexus.createEntity() - - XCTAssertEqual(nttParrent.numChildren, 0) - XCTAssertTrue(nttParrent.addChild(nttChild1)) - XCTAssertEqual(nttParrent.numChildren, 1) - XCTAssertTrue(nttParrent.removeChild(nttChild1)) - XCTAssertEqual(nttParrent.numChildren, 0) - XCTAssertFalse(nttParrent.removeChild(nttChild1)) - XCTAssertEqual(nttParrent.numChildren, 0) - XCTAssertTrue(nttParrent.addChild(nttChild1)) - XCTAssertEqual(nttParrent.numChildren, 1) - } - - func testRemoveAllChildren() { - let nttParrent = nexus.createEntity() - let nttChild1 = nexus.createEntity() - let nttChild2 = nexus.createEntity() - - XCTAssertEqual(nttParrent.numChildren, 0) - nttParrent.addChild(nttChild1) - nttParrent.addChild(nttChild2) - XCTAssertEqual(nttParrent.numChildren, 2) - - nttParrent.removeAllChildren() - XCTAssertEqual(nttParrent.numChildren, 0) - } - - func testDescendRelativesSimple() { - let nttParrent = nexus.createEntity(with: Position(x: 1, y: 1)) - let child1Pos = Position(x: 2, y: 2) - let nttChild1 = nexus.createEntity(with: child1Pos) - - nttParrent.addChild(nttChild1) - - let family = nexus.family(requires: Position.self) - - var counter: Int = 0 - - XCTAssertEqual(child1Pos.x, 2) - XCTAssertEqual(child1Pos.y, 2) - - family - .descendRelatives(from: nttParrent) - .forEach { (parent: Position, child: Position) in - defer { counter += 1 } - - child.x += parent.x - child.y += parent.y - } - - XCTAssertEqual(counter, 1) - XCTAssertEqual(child1Pos.x, 3) - XCTAssertEqual(child1Pos.y, 3) - } - - func testDescendRelativesOnlyFamilyMembers() { - let otherComponents: [Component] = [Position(x: 0, y: 0), Velocity(a: 0), Party(partying: true), Color(), Name(name: "")] - - func addChild(to parent: Entity, index: Int) -> Entity { - let randComp = otherComponents.randomElement()! - let badChild = nexus.createEntity(with: randComp) - let child = nexus.createEntity(with: Index(index: index)) - parent.addChild(child) - parent.addChild(badChild) - return child - } - - let root = nexus.createEntity(with: Index(index: 0)) - - var parent: Entity = root - for i in 1..<10 { - parent = addChild(to: parent, index: i) - } - - XCTAssertEqual(nexus.numEntities, 19) - - var parentSum: Int = 0 - var childSum: Int = 0 - - var lastIndex: Int = -1 - - nexus - .family(requires: Index.self) - .descendRelatives(from: root) - .forEach { (parent: Index, child: Index) in - XCTAssertEqual(parent.index + 1, child.index) - XCTAssertGreaterThan(parent.index, lastIndex) - lastIndex = parent.index - parentSum += parent.index - childSum += child.index - } - - XCTAssertEqual(parentSum, 36) - XCTAssertEqual(childSum, 45) - } -} diff --git a/Tests/FirebladeECSTests/XCTestManifests.swift b/Tests/FirebladeECSTests/XCTestManifests.swift index 66c786a..ea23498 100644 --- a/Tests/FirebladeECSTests/XCTestManifests.swift +++ b/Tests/FirebladeECSTests/XCTestManifests.swift @@ -235,19 +235,6 @@ extension NexusTests { ] } -extension SceneGraphTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__SceneGraphTests = [ - ("testAddChild", testAddChild), - ("testDescendRelativesOnlyFamilyMembers", testDescendRelativesOnlyFamilyMembers), - ("testDescendRelativesSimple", testDescendRelativesSimple), - ("testRemoveAllChildren", testRemoveAllChildren), - ("testRemoveChild", testRemoveChild) - ] -} - extension SingleTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` @@ -310,7 +297,6 @@ public func __allTests() -> [XCTestCaseEntry] { testCase(FamilyTraitsTests.__allTests__FamilyTraitsTests), testCase(HashingTests.__allTests__HashingTests), testCase(NexusTests.__allTests__NexusTests), - testCase(SceneGraphTests.__allTests__SceneGraphTests), testCase(SingleTests.__allTests__SingleTests), testCase(SparseSetTests.__allTests__SparseSetTests), testCase(SystemsTests.__allTests__SystemsTests) From d3500953ef92f9611558a8a9d9fe3fc4e40d8075 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Thu, 6 Aug 2020 15:53:43 +0200 Subject: [PATCH 3/3] Update README --- README.md | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/README.md b/README.md index 975bb48..e08d0bd 100644 --- a/README.md +++ b/README.md @@ -203,37 +203,6 @@ class GameLogicSystem { ``` -### 👫 Relatives (deprecated) - -This ECS implementation provides an integrated way of creating a [directed acyclic graph (DAG)](https://en.wikipedia.org/wiki/Directed_acyclic_graph) hierarchy of entities by forming parent-child relationships. Entities can become children of a parent entity. In family terms they become **relatives**. Families provide iteration over these relationships. -The entity hierarchy implementation does not use an additional component therefore keeping the hierarchy intact over different component-families. -This feature is especially useful for implementing a [scene graph](https://en.wikipedia.org/wiki/Scene_graph). - -```swift -// create entities with 0 to n components -let parent: Entity = nexus.createEntity(with: Position(x: 1, y: 1), SomeOtherComponent(...)) -let child: Entity = nexus.createEntity(with: Position(x: 2, y: 2)) -let child2: Entity = nexus.createEntity(with: Position(x: 3, y: 3), MySpecialComponent(...)) - -// create relationships between entities -parent.addChild(child) -child.addChild(child2) -// or remove them -// parent.removeChild(child) - -// iterate over component families descending the graph -nexus.family(requires: Position.self) - .descendRelatives(from: parent) // provide the start entity (aka root "node") - .forEach { (parent: Position, child: Position) in - // parent: the current parent component - // child: the current child component - - // update your components hierarchically - child.x += parent.x - child.y += parent.y - } -``` - ### 🔗 Serialization