Cleanup and refactor tests
This commit is contained in:
parent
c1a68300de
commit
fee1c2e52e
|
|
@ -19,6 +19,9 @@ let package = Package(
|
|||
dependencies: []),
|
||||
.testTarget(
|
||||
name: "FirebladeECSTests",
|
||||
dependencies: ["FirebladeECS"]),
|
||||
.testTarget(
|
||||
name: "FirebladeECSPerformanceTests",
|
||||
dependencies: ["FirebladeECS"])
|
||||
]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -52,11 +52,7 @@ public struct FamilyEntitiesAndComponents1<A>: EntityComponentsSequenceProtocol
|
|||
}
|
||||
|
||||
public mutating func next() -> (Entity, A)? {
|
||||
guard let entityId = memberIdsIterator.next() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard
|
||||
guard let entityId = memberIdsIterator.next(),
|
||||
let entity = nexus.get(entity: entityId),
|
||||
let compA: A = nexus.get(for: entityId)
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Christian Treffs on 30.10.17.
|
||||
//
|
||||
|
||||
public class UnorderedSparseSet<Element> {
|
||||
open class UnorderedSparseSet<Element> {
|
||||
public typealias Index = Int
|
||||
public typealias Key = Int
|
||||
|
||||
|
|
@ -14,8 +14,8 @@ public class UnorderedSparseSet<Element> {
|
|||
public let element: Element
|
||||
}
|
||||
|
||||
internal var dense: ContiguousArray<Entry>
|
||||
internal var sparse: [Index: Key]
|
||||
public private(set) var dense: ContiguousArray<Entry>
|
||||
public private(set) var sparse: [Index: Key]
|
||||
|
||||
public init() {
|
||||
sparse = [Index: Key]()
|
||||
|
|
@ -30,6 +30,7 @@ public class UnorderedSparseSet<Element> {
|
|||
public var isEmpty: Bool { return dense.isEmpty }
|
||||
public var capacity: Int { return sparse.count }
|
||||
|
||||
@inlinable
|
||||
public func contains(_ key: Key) -> Bool {
|
||||
return find(at: key) != nil
|
||||
}
|
||||
|
|
@ -58,6 +59,7 @@ public class UnorderedSparseSet<Element> {
|
|||
///
|
||||
/// - Parameter key: the key
|
||||
/// - Returns: the element or nil of key not found.
|
||||
@inlinable
|
||||
public func get(at key: Key) -> Element? {
|
||||
guard let (_, element) = find(at: key) else {
|
||||
return nil
|
||||
|
|
@ -66,6 +68,7 @@ public class UnorderedSparseSet<Element> {
|
|||
return element
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func get(unsafeAt key: Key) -> Element {
|
||||
return find(at: key).unsafelyUnwrapped.1
|
||||
}
|
||||
|
|
@ -108,7 +111,8 @@ public class UnorderedSparseSet<Element> {
|
|||
return dense.removeLast()
|
||||
}
|
||||
|
||||
private func find(at key: Key) -> (Int, Element)? {
|
||||
@inlinable
|
||||
public func find(at key: Key) -> (Int, Element)? {
|
||||
guard let denseIndex = sparse[key], denseIndex < count else {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// Base.swift
|
||||
// FirebladeECSTests
|
||||
//
|
||||
// Created by Christian Treffs on 09.10.17.
|
||||
//
|
||||
|
||||
import FirebladeECS
|
||||
|
||||
class EmptyComponent: Component { }
|
||||
|
||||
class Name: Component {
|
||||
var name: String
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
|
||||
class Position: Component {
|
||||
var x: Int
|
||||
var y: Int
|
||||
init(x: Int, y: Int) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
}
|
||||
}
|
||||
|
||||
class Velocity: Component {
|
||||
var a: Float
|
||||
init(a: Float) {
|
||||
self.a = a
|
||||
}
|
||||
}
|
||||
|
||||
class Party: Component {
|
||||
var partying: Bool
|
||||
init(partying: Bool) {
|
||||
self.partying = partying
|
||||
}
|
||||
}
|
||||
|
||||
class Color: Component {
|
||||
var r: UInt8 = 0
|
||||
var g: UInt8 = 0
|
||||
var b: UInt8 = 0
|
||||
}
|
||||
|
||||
class ExampleSystem {
|
||||
private let family: TypedFamily2<Position, Velocity>
|
||||
|
||||
init(nexus: Nexus) {
|
||||
family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: EmptyComponent.self)
|
||||
}
|
||||
|
||||
func update(deltaT: Double) {
|
||||
family.forEach { (position: Position, velocity: Velocity) in
|
||||
position.x *= 2
|
||||
velocity.a *= 2
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
final class SingleGameState: SingleComponent {
|
||||
var shouldQuit: Bool = false
|
||||
var playerHealth: Int = 67
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// ComponentPerformanceTests.swift
|
||||
// FirebladeECSPerformanceTests
|
||||
//
|
||||
// Created by Christian Treffs on 14.02.19.
|
||||
//
|
||||
|
||||
@testable import FirebladeECS
|
||||
import XCTest
|
||||
|
||||
class ComponentTests: XCTestCase {
|
||||
|
||||
func testMeasureStaticComponentIdentifier() {
|
||||
let number: Int = 10_000
|
||||
measure {
|
||||
for _ in 0..<number {
|
||||
let id = Position.identifier
|
||||
_ = id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testMeasureComponentIdentifier() {
|
||||
let number: Int = 10_000
|
||||
let pos = Position(x: 1, y: 2)
|
||||
measure {
|
||||
for _ in 0..<number {
|
||||
let id = pos.identifier
|
||||
_ = id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// HashingPerformanceTests.swift
|
||||
// FirebladeECSPerformanceTests
|
||||
//
|
||||
// Created by Christian Treffs on 14.02.19.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import FirebladeECS
|
||||
|
||||
class HashingPerformanceTests: XCTestCase {
|
||||
|
||||
func testMeasureCombineHash() {
|
||||
let a: Set<Int> = Set<Int>([14_561_291, 26_451_562, 34_562_182, 488_972_556, 5_128_426_962, 68_211_812])
|
||||
let b: Set<Int> = Set<Int>([1_083_838, 912_312, 83_333, 71_234_555, 4_343_234])
|
||||
let c: Set<Int> = Set<Int>([3_410_346_899_765, 90_000_002, 12_212_321, 71, 6_123_345_676_543])
|
||||
|
||||
let input: ContiguousArray<Int> = ContiguousArray<Int>(arrayLiteral: a.hashValue, b.hashValue, c.hashValue)
|
||||
measure {
|
||||
for _ in 0..<1_000_000 {
|
||||
let hashRes: Int = FirebladeECS.hash(combine: input)
|
||||
_ = hashRes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testMeasureSetOfSetHash() {
|
||||
let a: Set<Int> = Set<Int>([14_561_291, 26_451_562, 34_562_182, 488_972_556, 5_128_426_962, 68_211_812])
|
||||
let b: Set<Int> = Set<Int>([1_083_838, 912_312, 83_333, 71_234_555, 4_343_234])
|
||||
let c: Set<Int> = Set<Int>([3_410_346_899_765, 90_000_002, 12_212_321, 71, 6_123_345_676_543])
|
||||
|
||||
let input = Set<Set<Int>>(arrayLiteral: a, b, c)
|
||||
measure {
|
||||
for _ in 0..<1_000_000 {
|
||||
let hash: Int = input.hashValue
|
||||
_ = hash
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -31,6 +31,25 @@ class TypedFamilyPerformanceTests: XCTestCase {
|
|||
super.tearDown()
|
||||
}
|
||||
|
||||
func testMeasureTraitMatching() {
|
||||
|
||||
let a = nexus.create(entity: "a")
|
||||
a.assign(Position(x: 1, y: 2))
|
||||
a.assign(Name(name: "myName"))
|
||||
a.assign(Velocity(a: 3.14))
|
||||
a.assign(EmptyComponent())
|
||||
|
||||
let isMatch = nexus.family(requiresAll: Position.self, Velocity.self,
|
||||
excludesAll: Party.self)
|
||||
|
||||
measure {
|
||||
for _ in 0..<10_000 {
|
||||
let success = isMatch.canBecomeMember(a)
|
||||
XCTAssert(success)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testPerformanceTypedFamilyEntities() {
|
||||
let family = nexus.family(requires: Position.self, excludesAll: Party.self)
|
||||
|
||||
|
|
@ -10,33 +10,33 @@ import FirebladeECS
|
|||
class EmptyComponent: Component { }
|
||||
|
||||
class Name: Component {
|
||||
var name: String
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
var name: String
|
||||
init(name: String) {
|
||||
self.name = name
|
||||
}
|
||||
}
|
||||
|
||||
class Position: Component {
|
||||
var x: Int
|
||||
var y: Int
|
||||
init(x: Int, y: Int) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
}
|
||||
var x: Int
|
||||
var y: Int
|
||||
init(x: Int, y: Int) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
}
|
||||
}
|
||||
|
||||
class Velocity: Component {
|
||||
var a: Float
|
||||
init(a: Float) {
|
||||
self.a = a
|
||||
}
|
||||
var a: Float
|
||||
init(a: Float) {
|
||||
self.a = a
|
||||
}
|
||||
}
|
||||
|
||||
class Party: Component {
|
||||
var partying: Bool
|
||||
init(partying: Bool) {
|
||||
self.partying = partying
|
||||
}
|
||||
var partying: Bool
|
||||
init(partying: Bool) {
|
||||
self.partying = partying
|
||||
}
|
||||
}
|
||||
|
||||
class Color: Component {
|
||||
|
|
@ -45,27 +45,78 @@ class Color: Component {
|
|||
var b: UInt8 = 0
|
||||
}
|
||||
|
||||
class ExampleSystem {
|
||||
private let family: TypedFamily2<Position, Velocity>
|
||||
|
||||
init(nexus: Nexus) {
|
||||
family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: EmptyComponent.self)
|
||||
}
|
||||
|
||||
func update(deltaT: Double) {
|
||||
family.forEach { (position: Position, velocity: Velocity) in
|
||||
position.x *= 2
|
||||
velocity.a *= 2
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
final class SingleGameState: SingleComponent {
|
||||
var shouldQuit: Bool = false
|
||||
var playerHealth: Int = 67
|
||||
|
||||
}
|
||||
|
||||
|
||||
class ExampleSystem {
|
||||
private let family: TypedFamily2<Position, Velocity>
|
||||
|
||||
init(nexus: Nexus) {
|
||||
family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: EmptyComponent.self)
|
||||
}
|
||||
|
||||
func update(deltaT: Double) {
|
||||
family.forEach { (position: Position, velocity: Velocity) in
|
||||
position.x *= 2
|
||||
velocity.a *= 2
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class ColorSystem {
|
||||
|
||||
let nexus: Nexus
|
||||
lazy var colors = nexus.family(requires: Color.self)
|
||||
|
||||
init(nexus: Nexus) {
|
||||
self.nexus = nexus
|
||||
}
|
||||
|
||||
func update() {
|
||||
colors
|
||||
.forEach { (color: Color) in
|
||||
color.r = 1
|
||||
color.g = 2
|
||||
color.b = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PositionSystem {
|
||||
let positions: TypedFamily1<Position>
|
||||
|
||||
var velocity: Double = 4.0
|
||||
|
||||
init(nexus: Nexus) {
|
||||
positions = nexus.family(requires: Position.self)
|
||||
}
|
||||
|
||||
func randNorm() -> Double {
|
||||
return 4.0
|
||||
}
|
||||
|
||||
func update() {
|
||||
positions
|
||||
.forEach { [unowned self](pos: Position) in
|
||||
|
||||
let deltaX: Double = self.velocity * ((self.randNorm() * 2) - 1)
|
||||
let deltaY: Double = self.velocity * ((self.randNorm() * 2) - 1)
|
||||
let x = pos.x + Int(deltaX)
|
||||
let y = pos.y + Int(deltaY)
|
||||
|
||||
pos.x = x
|
||||
pos.y = y
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,16 +10,6 @@ import XCTest
|
|||
|
||||
class ComponentTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testComponentIdentifier() {
|
||||
let p1 = Position(x: 1, y: 2)
|
||||
XCTAssert(p1.identifier == Position.identifier)
|
||||
|
|
@ -30,25 +20,5 @@ class ComponentTests: XCTestCase {
|
|||
XCTAssert(Velocity.identifier != Position.identifier)
|
||||
}
|
||||
|
||||
func testMeasureStaticComponentIdentifier() {
|
||||
let number: Int = 10_000
|
||||
measure {
|
||||
for _ in 0..<number {
|
||||
let id = Position.identifier
|
||||
_ = id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testMeasureComponentIdentifier() {
|
||||
let number: Int = 10_000
|
||||
let pos = Position(x: 1, y: 2)
|
||||
measure {
|
||||
for _ in 0..<number {
|
||||
let id = pos.identifier
|
||||
_ = id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,16 +10,6 @@ import XCTest
|
|||
|
||||
class EntityTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testEntityIdentifierAndIndex() {
|
||||
|
||||
let min: EntityIndex = EntityIdentifier(EntityIdentifier.min).index
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ class FamilyTests: XCTestCase {
|
|||
super.tearDown()
|
||||
}
|
||||
|
||||
func createDefaultEntity(name: String?) {
|
||||
let e = nexus.create(entity: name)
|
||||
e.assign(Position(x: 1, y: 2))
|
||||
e.assign(Color())
|
||||
}
|
||||
|
||||
func testFamilyCreation() {
|
||||
|
||||
let family = nexus.family(requires: Position.self,
|
||||
|
|
@ -53,47 +59,30 @@ class FamilyTests: XCTestCase {
|
|||
func testFamilyAbandoned() {
|
||||
|
||||
XCTAssertEqual(nexus.familyMembersByTraits.keys.count, 0)
|
||||
|
||||
_ = nexus.family(requires: Position.self)
|
||||
|
||||
XCTAssertEqual(nexus.familyMembersByTraits.keys.count, 1)
|
||||
|
||||
let entity = nexus.create(entity: "eimer")
|
||||
entity.assign(Position(x: 1, y: 1))
|
||||
|
||||
XCTAssertEqual(nexus.familyMembersByTraits.keys.count, 1)
|
||||
|
||||
entity.remove(Position.self)
|
||||
|
||||
// FIXME: the family trait should vanish when no entity with revlevant component is present anymore
|
||||
|
||||
XCTAssertEqual(nexus.familyMembersByTraits.keys.count, 1)
|
||||
|
||||
nexus.destroy(entity: entity)
|
||||
|
||||
XCTAssertEqual(nexus.familyMembersByTraits.keys.count, 1)
|
||||
|
||||
}
|
||||
|
||||
func testFamilyLateMember() {
|
||||
|
||||
let eEarly = nexus.create(entity: "eary").assign(Position(x: 1, y: 2))
|
||||
|
||||
XCTAssertEqual(nexus.familyMembersByTraits.keys.count, 0)
|
||||
|
||||
let family = nexus.family(requires: Position.self)
|
||||
|
||||
XCTAssertEqual(nexus.familyMembersByTraits.keys.count, 1)
|
||||
|
||||
let eLate = nexus.create(entity: "late").assign(Position(x: 1, y: 2))
|
||||
|
||||
XCTAssertTrue(family.isMember(eEarly))
|
||||
XCTAssertTrue(family.isMember(eLate))
|
||||
|
||||
}
|
||||
|
||||
func testFamilyExchange() {
|
||||
|
||||
let number: Int = 10
|
||||
|
||||
for i in 0..<number {
|
||||
|
|
@ -153,12 +142,6 @@ class FamilyTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func createDefaultEntity(name: String?) {
|
||||
let e = nexus.create(entity: name)
|
||||
e.assign(Position(x: 1, y: 2))
|
||||
e.assign(Color())
|
||||
}
|
||||
|
||||
func testFamilyBulkDestroy() {
|
||||
let count = 10_000
|
||||
|
||||
|
|
|
|||
|
|
@ -54,23 +54,4 @@ class FamilyTraitsTests: XCTestCase {
|
|||
|
||||
}
|
||||
|
||||
func testMeasureTraitMatching() {
|
||||
|
||||
let a = nexus.create(entity: "a")
|
||||
a.assign(Position(x: 1, y: 2))
|
||||
a.assign(Name(name: "myName"))
|
||||
a.assign(Velocity(a: 3.14))
|
||||
a.assign(EmptyComponent())
|
||||
|
||||
let isMatch = nexus.family(requiresAll: Position.self, Velocity.self,
|
||||
excludesAll: Party.self)
|
||||
|
||||
measure {
|
||||
for _ in 0..<10_000 {
|
||||
let success = isMatch.canBecomeMember(a)
|
||||
XCTAssert(success)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,78 +9,47 @@
|
|||
import XCTest
|
||||
|
||||
class HashingTests: XCTestCase {
|
||||
|
||||
func testCollisionsInCritialRange() {
|
||||
|
||||
var hashSet: Set<Int> = Set<Int>()
|
||||
|
||||
var range: CountableRange<EntityIdentifier> = 0 ..< 1_000_000
|
||||
|
||||
let maxComponents: Int = 1000
|
||||
let components: [Int] = (0..<maxComponents).map { _ in makeComponent() }
|
||||
|
||||
var index: Int = 0
|
||||
while let eId: EntityIdentifier = range.popLast() {
|
||||
|
||||
let entityId: EntityIdentifier = eId
|
||||
let c = (index % maxComponents)
|
||||
index += 1
|
||||
|
||||
let cH: ComponentTypeHash = components[c]
|
||||
|
||||
let h: Int = EntityComponentHash.compose(entityId: entityId, componentTypeHash: cH)
|
||||
|
||||
let (collisionFree, _) = hashSet.insert(h)
|
||||
XCTAssert(collisionFree)
|
||||
|
||||
XCTAssert(EntityComponentHash.decompose(h, with: cH) == entityId)
|
||||
XCTAssert(EntityComponentHash.decompose(h, with: entityId) == cH)
|
||||
}
|
||||
}
|
||||
|
||||
func testMeasureCombineHash() {
|
||||
let a: Set<Int> = Set<Int>([14_561_291, 26_451_562, 34_562_182, 488_972_556, 5_128_426_962, 68_211_812])
|
||||
let b: Set<Int> = Set<Int>([1_083_838, 912_312, 83_333, 71_234_555, 4_343_234])
|
||||
let c: Set<Int> = Set<Int>([3_410_346_899_765, 90_000_002, 12_212_321, 71, 6_123_345_676_543])
|
||||
|
||||
let input: ContiguousArray<Int> = ContiguousArray<Int>(arrayLiteral: a.hashValue, b.hashValue, c.hashValue)
|
||||
measure {
|
||||
for _ in 0..<1_000_000 {
|
||||
let hashRes: Int = FirebladeECS.hash(combine: input)
|
||||
_ = hashRes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testMeasureSetOfSetHash() {
|
||||
let a: Set<Int> = Set<Int>([14_561_291, 26_451_562, 34_562_182, 488_972_556, 5_128_426_962, 68_211_812])
|
||||
let b: Set<Int> = Set<Int>([1_083_838, 912_312, 83_333, 71_234_555, 4_343_234])
|
||||
let c: Set<Int> = Set<Int>([3_410_346_899_765, 90_000_002, 12_212_321, 71, 6_123_345_676_543])
|
||||
|
||||
let input = Set<Set<Int>>(arrayLiteral: a, b, c)
|
||||
measure {
|
||||
for _ in 0..<1_000_000 {
|
||||
let hash: Int = input.hashValue
|
||||
_ = hash
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func makeComponent() -> Int {
|
||||
let upperBound: Int = 44
|
||||
let high = UInt(arc4random()) << UInt(upperBound)
|
||||
let low = UInt(arc4random())
|
||||
assert(high.leadingZeroBitCount < 64 - upperBound)
|
||||
assert(high.trailingZeroBitCount >= upperBound)
|
||||
assert(low.leadingZeroBitCount >= 32)
|
||||
assert(low.trailingZeroBitCount <= 32)
|
||||
let rand: UInt = high | low
|
||||
let cH = Int(bitPattern: rand)
|
||||
return cH
|
||||
}
|
||||
|
||||
func testCollisionsInCritialRange() {
|
||||
|
||||
var hashSet: Set<Int> = Set<Int>()
|
||||
|
||||
var range: CountableRange<EntityIdentifier> = 0 ..< 1_000_000
|
||||
|
||||
let maxComponents: Int = 1000
|
||||
let components: [Int] = (0..<maxComponents).map { _ in makeComponent() }
|
||||
|
||||
var index: Int = 0
|
||||
while let eId: EntityIdentifier = range.popLast() {
|
||||
|
||||
let entityId: EntityIdentifier = eId
|
||||
let c = (index % maxComponents)
|
||||
index += 1
|
||||
|
||||
let cH: ComponentTypeHash = components[c]
|
||||
|
||||
let h: Int = EntityComponentHash.compose(entityId: entityId, componentTypeHash: cH)
|
||||
|
||||
let (collisionFree, _) = hashSet.insert(h)
|
||||
XCTAssert(collisionFree)
|
||||
|
||||
XCTAssert(EntityComponentHash.decompose(h, with: cH) == entityId)
|
||||
XCTAssert(EntityComponentHash.decompose(h, with: entityId) == cH)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - helper
|
||||
extension HashingTests {
|
||||
|
||||
func makeComponent() -> Int {
|
||||
let upperBound: Int = 44
|
||||
let high = UInt(arc4random()) << UInt(upperBound)
|
||||
let low = UInt(arc4random())
|
||||
assert(high.leadingZeroBitCount < 64 - upperBound)
|
||||
assert(high.trailingZeroBitCount >= upperBound)
|
||||
assert(low.leadingZeroBitCount >= 32)
|
||||
assert(low.trailingZeroBitCount <= 32)
|
||||
let rand: UInt = high | low
|
||||
let cH = Int(bitPattern: rand)
|
||||
return cH
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,51 +128,3 @@ class SystemsTests: XCTestCase {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
class ColorSystem {
|
||||
|
||||
let nexus: Nexus
|
||||
lazy var colors = nexus.family(requires: Color.self)
|
||||
|
||||
init(nexus: Nexus) {
|
||||
self.nexus = nexus
|
||||
}
|
||||
|
||||
func update() {
|
||||
colors
|
||||
.forEach { (color: Color) in
|
||||
color.r = 1
|
||||
color.g = 2
|
||||
color.b = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PositionSystem {
|
||||
let positions: TypedFamily1<Position>
|
||||
|
||||
var velocity: Double = 4.0
|
||||
|
||||
init(nexus: Nexus) {
|
||||
positions = nexus.family(requires: Position.self)
|
||||
}
|
||||
|
||||
func randNorm() -> Double {
|
||||
return 4.0
|
||||
}
|
||||
|
||||
func update() {
|
||||
positions
|
||||
.forEach { [unowned self](pos: Position) in
|
||||
|
||||
let deltaX: Double = self.velocity * ((self.randNorm() * 2) - 1)
|
||||
let deltaY: Double = self.velocity * ((self.randNorm() * 2) - 1)
|
||||
let x = pos.x + Int(deltaX)
|
||||
let y = pos.y + Int(deltaY)
|
||||
|
||||
pos.x = x
|
||||
pos.y = y
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue