add EntityStateMachine
This commit is contained in:
parent
acc2a0feff
commit
a17fbea014
|
|
@ -6,7 +6,7 @@ public typealias ComponentInitializable = Component & EmptyInitializable
|
||||||
|
|
||||||
public protocol ComponentProvider {
|
public protocol ComponentProvider {
|
||||||
var identifier: AnyHashable { get }
|
var identifier: AnyHashable { get }
|
||||||
func getComponent<C>() -> C? where C: Component
|
func getComponent() -> Component
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
@ -24,8 +24,8 @@ extension ComponentInstanceProvider: ComponentProvider {
|
||||||
ObjectIdentifier(instance)
|
ObjectIdentifier(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getComponent<C>() -> C? where C : Component {
|
public func getComponent() -> Component {
|
||||||
instance as? C
|
instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,8 +42,8 @@ public struct ComponentTypeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ComponentTypeProvider: ComponentProvider {
|
extension ComponentTypeProvider: ComponentProvider {
|
||||||
public func getComponent<C>() -> C? where C: Component {
|
public func getComponent() -> Component {
|
||||||
componentType.init() as? C
|
componentType.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,8 +70,8 @@ public class ComponentSingletonProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ComponentSingletonProvider: ComponentProvider {
|
extension ComponentSingletonProvider: ComponentProvider {
|
||||||
public func getComponent<C>() -> C? where C: Component {
|
public func getComponent() -> Component {
|
||||||
instance as? C
|
instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,8 +96,8 @@ extension DynamicComponentProvider: ComponentProvider {
|
||||||
ObjectIdentifier(closure)
|
ObjectIdentifier(closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getComponent<C>() -> C? where C: Component {
|
public func getComponent() -> Component {
|
||||||
closure.closure() as? C
|
closure.closure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,8 +109,15 @@ public class EntityState {
|
||||||
public init() { }
|
public init() { }
|
||||||
|
|
||||||
public func add<C: ComponentInitializable>(_ type: C.Type) -> StateComponentMapping {
|
public func add<C: ComponentInitializable>(_ type: C.Type) -> StateComponentMapping {
|
||||||
StateComponentMapping(creatingState: self,
|
StateComponentMapping(creatingState: self, type: type)
|
||||||
type: type)
|
}
|
||||||
|
|
||||||
|
public func get<C: ComponentInitializable>(_ type: C.Type) -> ComponentProvider? {
|
||||||
|
providers[type.identifier]
|
||||||
|
}
|
||||||
|
|
||||||
|
public func has<C: ComponentInitializable>(_ type: C.Type) -> Bool {
|
||||||
|
providers[type.identifier] != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|
@ -165,3 +172,66 @@ public class StateComponentMapping {
|
||||||
creatingState.providers[componentType.identifier] = provider
|
creatingState.providers[componentType.identifier] = provider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
|
public class EntityStateMachine {
|
||||||
|
private var states: [String: EntityState]
|
||||||
|
|
||||||
|
private var currentState: EntityState?
|
||||||
|
|
||||||
|
public var entity: Entity
|
||||||
|
|
||||||
|
public init(entity: Entity) {
|
||||||
|
self.entity = entity
|
||||||
|
states = [:]
|
||||||
|
}
|
||||||
|
|
||||||
|
public func addState(name: String, state: EntityState) -> Self {
|
||||||
|
states[name] = state
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
public func createState(name: String) -> EntityState {
|
||||||
|
let state = EntityState()
|
||||||
|
states[name] = state
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
public func changeState(name: String) {
|
||||||
|
guard let newState = states[name] else {
|
||||||
|
fatalError("Entity state '\(name)' doesn't exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
if newState === currentState {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var toAdd: [ComponentIdentifier: ComponentProvider]
|
||||||
|
if let currentState = currentState {
|
||||||
|
toAdd = .init()
|
||||||
|
for t in newState.providers {
|
||||||
|
toAdd[t.key] = t.value
|
||||||
|
}
|
||||||
|
|
||||||
|
for t in currentState.providers {
|
||||||
|
if let other = toAdd[t.key], let current = currentState.providers[t.key],
|
||||||
|
current.identifier == other.identifier {
|
||||||
|
toAdd[t.key] = nil
|
||||||
|
} else {
|
||||||
|
entity.remove(t.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toAdd = newState.providers
|
||||||
|
}
|
||||||
|
|
||||||
|
for t in toAdd {
|
||||||
|
guard let component = toAdd[t.key]?.getComponent() else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entity.assign(component)
|
||||||
|
}
|
||||||
|
currentState = newState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ class ComponentInstanceProviderTests: XCTestCase {
|
||||||
func testProviderReturnsTheInstance() {
|
func testProviderReturnsTheInstance() {
|
||||||
let instance = MockComponent(value: .max)
|
let instance = MockComponent(value: .max)
|
||||||
let provider1 = ComponentInstanceProvider(instance: instance)
|
let provider1 = ComponentInstanceProvider(instance: instance)
|
||||||
let providedComponent: MockComponent? = provider1.getComponent()
|
let providedComponent = provider1.getComponent() as? MockComponent
|
||||||
XCTAssertTrue(providedComponent === instance)
|
XCTAssertTrue(providedComponent === instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,14 +34,14 @@ class ComponentInstanceProviderTests: XCTestCase {
|
||||||
class ComponentTypeProviderTests: XCTestCase {
|
class ComponentTypeProviderTests: XCTestCase {
|
||||||
func testProviderReturnsAnInstanceOfType() {
|
func testProviderReturnsAnInstanceOfType() {
|
||||||
let provider = ComponentTypeProvider(type: MockComponent.self)
|
let provider = ComponentTypeProvider(type: MockComponent.self)
|
||||||
let component: MockComponent? = provider.getComponent()
|
let component = provider.getComponent() as? MockComponent
|
||||||
XCTAssertNotNil(component)
|
XCTAssertNotNil(component)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProviderReturnsNewInstanceEachTime() {
|
func testProviderReturnsNewInstanceEachTime() {
|
||||||
let provider = ComponentTypeProvider(type: MockComponent.self)
|
let provider = ComponentTypeProvider(type: MockComponent.self)
|
||||||
let component1: MockComponent? = provider.getComponent()
|
let component1 = provider.getComponent() as? MockComponent
|
||||||
let component2: MockComponent? = provider.getComponent()
|
let component2 = provider.getComponent() as? MockComponent
|
||||||
XCTAssertFalse(component1 === component2)
|
XCTAssertFalse(component1 === component2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,14 +78,14 @@ class ComponentTypeProviderTests: XCTestCase {
|
||||||
class ComponentSingletonProviderTests: XCTestCase {
|
class ComponentSingletonProviderTests: XCTestCase {
|
||||||
func testProviderReturnsAnInstanceOfType() {
|
func testProviderReturnsAnInstanceOfType() {
|
||||||
let provider = ComponentSingletonProvider(type: MockComponent.self)
|
let provider = ComponentSingletonProvider(type: MockComponent.self)
|
||||||
let component: MockComponent? = provider.getComponent()
|
let component = provider.getComponent() as? MockComponent
|
||||||
XCTAssertNotNil(component)
|
XCTAssertNotNil(component)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProviderReturnsSameInstanceEachTime() {
|
func testProviderReturnsSameInstanceEachTime() {
|
||||||
let provider = ComponentSingletonProvider(type: MockComponent.self)
|
let provider = ComponentSingletonProvider(type: MockComponent.self)
|
||||||
let component1: MockComponent? = provider.getComponent()
|
let component1 = provider.getComponent() as? MockComponent
|
||||||
let component2: MockComponent? = provider.getComponent()
|
let component2 = provider.getComponent() as? MockComponent
|
||||||
XCTAssertTrue(component1 === component2)
|
XCTAssertTrue(component1 === component2)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +124,7 @@ class DynamicComponentProviderTests: XCTestCase {
|
||||||
let instance = MockComponent(value: 0)
|
let instance = MockComponent(value: 0)
|
||||||
let providerMethod = DynamicComponentProvider.Closure { instance }
|
let providerMethod = DynamicComponentProvider.Closure { instance }
|
||||||
let provider = DynamicComponentProvider(closure: providerMethod)
|
let provider = DynamicComponentProvider(closure: providerMethod)
|
||||||
let component: MockComponent? = provider.getComponent()
|
let component = provider.getComponent() as? MockComponent
|
||||||
XCTAssertTrue(component === instance)
|
XCTAssertTrue(component === instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,3 +153,7 @@ class DynamicComponentProviderTests: XCTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EntityStateMachineTests: XCTestCase {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue