From 9f3e239aefd7dce7b2e0b4d8e61c37f747adfd8e Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 15:50:43 +0900 Subject: [PATCH 01/42] add Commands --- Sources/ECS/Commands/Command.swift | 8 +++-- Sources/ECS/Commands/Commands.swift | 20 +++++++++++-- Sources/ECS/Commands/CommandsBuffer.swift | 36 ++++++++++++++++++++++- Sources/ECS/Commands/World+Commands.swift | 12 ++++++-- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/Sources/ECS/Commands/Command.swift b/Sources/ECS/Commands/Command.swift index 123598b..b71115e 100644 --- a/Sources/ECS/Commands/Command.swift +++ b/Sources/ECS/Commands/Command.swift @@ -1,8 +1,12 @@ // -// File.swift +// Command.swift // // // Created by rrbox on 2023/08/09. // -import Foundation +open class Command { + open func runCommand(in world: World) { + + } +} diff --git a/Sources/ECS/Commands/Commands.swift b/Sources/ECS/Commands/Commands.swift index 123598b..b746201 100644 --- a/Sources/ECS/Commands/Commands.swift +++ b/Sources/ECS/Commands/Commands.swift @@ -1,8 +1,24 @@ // -// File.swift +// Commands.swift // // // Created by rrbox on 2023/08/09. // -import Foundation +final public class Commands: SystemParameter { + var commandQueue = [Command]() + + /// Commands では, World への登録時には何もしません. + public static func register(to worldBuffer: WorldBuffer) { + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> Commands? { + worldBuffer.commandsBuffer.commands() + } + + /// CommandQueue にコマンドを追加します. + public func push(command: Command) { + self.commandQueue.append(command) + } +} diff --git a/Sources/ECS/Commands/CommandsBuffer.swift b/Sources/ECS/Commands/CommandsBuffer.swift index 4554040..9bce8e3 100644 --- a/Sources/ECS/Commands/CommandsBuffer.swift +++ b/Sources/ECS/Commands/CommandsBuffer.swift @@ -1,8 +1,42 @@ // -// Commands+WorldBuffer.swift +// CommandsBuffer.swift // // // Created by rrbox on 2023/08/10. // import Foundation + +class CommandsBuffer { + class CommandsRegistry: BufferElement { + let commands: Commands + init(commands: Commands) { + self.commands = commands + super.init() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + } + let buffer: Buffer + + init(buffer: Buffer) { + self.buffer = buffer + } + + func commands() -> Commands? { + self.buffer.component(ofType: CommandsRegistry.self)?.commands + } + + func setCommands(_ commands: Commands) { + self.buffer.addComponent(CommandsRegistry(commands: commands)) + } +} + +// WorldBuffer + Commands +extension WorldBuffer { + var commandsBuffer: CommandsBuffer { + CommandsBuffer(buffer: self) + } +} diff --git a/Sources/ECS/Commands/World+Commands.swift b/Sources/ECS/Commands/World+Commands.swift index 175c602..4ebbca9 100644 --- a/Sources/ECS/Commands/World+Commands.swift +++ b/Sources/ECS/Commands/World+Commands.swift @@ -1,8 +1,16 @@ // -// File.swift +// World+Commands.swift // // // Created by rrbox on 2023/08/11. // -import Foundation +extension World { + func applyCommands() { + let commands = self.worldBuffer.commandsBuffer.commands()! + for command in commands.commandQueue { + command.runCommand(in: self) + } + commands.commandQueue = [] + } +} From ba5a6649bddbdbf01c6783f1760f86d9e13b99b7 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:31:45 +0900 Subject: [PATCH 02/42] add Entity commands --- .../Commands/AddComponentCommand.swift | 21 +++++++++++++++++-- .../Commands/DespawnCommand.swift | 14 +++++++++++-- .../Commands/RemoveComponentCommand.swift | 14 +++++++++++-- .../Commands/SpawnCommand.swift | 17 +++++++++++++-- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift b/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift index e94d427..c4714ae 100644 --- a/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift @@ -1,8 +1,25 @@ // -// File.swift +// AddComponentCommand.swift // // // Created by rrbox on 2023/08/10. // -import Foundation +class AddComponent: Command { + let entity: Entity + let componnet: ComponentType + + init(entity: Entity, componnet: ComponentType) { + self.entity = entity + self.componnet = componnet + } + + override func runCommand(in world: World) { + guard let componentRef = world.entities[self.entity]? + .component(ofType: ComponentRef.self) else { + world.entities[self.entity]?.addComponent(ComponentRef(component: self.componnet)) + return + } + componentRef.value = self.componnet + } +} diff --git a/Sources/ECS/EntityCommands/Commands/DespawnCommand.swift b/Sources/ECS/EntityCommands/Commands/DespawnCommand.swift index e94d427..d994854 100644 --- a/Sources/ECS/EntityCommands/Commands/DespawnCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/DespawnCommand.swift @@ -1,8 +1,18 @@ // -// File.swift +// DespawnCommand.swift // // // Created by rrbox on 2023/08/10. // -import Foundation +class DespawnCommand: Command { + let entity: Entity + + init(entity: Entity) { + self.entity = entity + } + + override func runCommand(in world: World) { + world.despawn(entity: self.entity) + } +} diff --git a/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift b/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift index e94d427..f117178 100644 --- a/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift @@ -1,8 +1,18 @@ // -// File.swift +// RemoveComponentCommand.swift // // // Created by rrbox on 2023/08/10. // -import Foundation +class RemoveComponent: Command { + let entity: Entity + + init(entity: Entity, componentType type: ComponentType.Type) { + self.entity = entity + } + + override func runCommand(in world: World) { + world.entities[self.entity]?.removeComponent(ofType: ComponentRef.self) + } +} diff --git a/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift b/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift index e94d427..566c1b5 100644 --- a/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift @@ -1,8 +1,21 @@ // -// File.swift +// SpawnCommand.swift // // // Created by rrbox on 2023/08/10. // -import Foundation +class SpawnCommand: Command { + let id: Entity + let value: Archetype + + init(id: Entity, value: Archetype) { + self.id = id + self.value = value + } + + override func runCommand(in world: World) { + world.push(entity: self.id, value: self.value) + } +} + From c6f819b394cef79c53c5be78870b4e303901e169 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:32:25 +0900 Subject: [PATCH 03/42] add EntityCommnads's methods --- .../Commands+EntityCommands.swift | 21 +++++++++++++++++-- .../ECS/EntityCommands/EntityCommands.swift | 20 +++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Sources/ECS/EntityCommands/Commands+EntityCommands.swift b/Sources/ECS/EntityCommands/Commands+EntityCommands.swift index e94d427..e4f84b2 100644 --- a/Sources/ECS/EntityCommands/Commands+EntityCommands.swift +++ b/Sources/ECS/EntityCommands/Commands+EntityCommands.swift @@ -1,8 +1,25 @@ // -// File.swift +// Commands+EntityCommands.swift // // // Created by rrbox on 2023/08/10. // -import Foundation +public extension Commands { + /// Entity を取得して変更を加えます + func entity(_ entity: Entity) -> EntityCommands? { + return EntityCommands(entity: entity, commands: self) + } + + /// Entity を追加して変更を加えます. + func spawn() -> EntityCommands { + let entity = Entity() + self.commandQueue.append(SpawnCommand(id: entity, value: Archetype())) + return EntityCommands(entity: entity, commands: self) + } + + /// Entity を削除します. + func despawn(entity: Entity) { + self.commandQueue.append(DespawnCommand(entity: entity)) + } +} diff --git a/Sources/ECS/EntityCommands/EntityCommands.swift b/Sources/ECS/EntityCommands/EntityCommands.swift index b591aa4..dfef972 100644 --- a/Sources/ECS/EntityCommands/EntityCommands.swift +++ b/Sources/ECS/EntityCommands/EntityCommands.swift @@ -6,7 +6,7 @@ // final public class EntityCommands { - public let entity: Entity + let entity: Entity let commands: Commands init(entity: Entity, commands: Commands) { @@ -14,8 +14,26 @@ final public class EntityCommands { self.commands = commands } + /// Commands で操作した Entity を受け取ります. + /// - Returns: ID としての Entity をそのまま返します. public func id() -> Entity { self.entity } + /// Entity に Component を追加します. + /// - Parameter component: 追加するコンポーネントを指定します. + /// - Returns: Entity component のビルダーです. + @discardableResult public func addComponent(_ component: ComponentType) -> EntityCommands { + self.commands.commandQueue.append(AddComponent(entity: self.entity, componnet: component)) + return self + } + + /// Entity から Component を削除します. + /// - Parameter type: 削除する Component の型を指定します. + /// - Returns: Entity component のビルダーです. + @discardableResult public func removeComponent(ofType type: ComponentType.Type) -> EntityCommands { + self.commands.commandQueue.append(RemoveComponent(entity: self.entity, componentType: ComponentType.self)) + return self + } + } From 730d89cf5e3f5b6d4fe38163c4a33b769ee3bf76 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:33:15 +0900 Subject: [PATCH 04/42] add system parameter protocol --- Sources/ECS/SystemParameter/SystemParameter.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/ECS/SystemParameter/SystemParameter.swift b/Sources/ECS/SystemParameter/SystemParameter.swift index e94d427..d05c5c4 100644 --- a/Sources/ECS/SystemParameter/SystemParameter.swift +++ b/Sources/ECS/SystemParameter/SystemParameter.swift @@ -1,8 +1,12 @@ // -// File.swift +// SystemParameter.swift // // // Created by rrbox on 2023/08/10. // -import Foundation +public protocol SystemParameter: AnyObject { + static func register(to worldBuffer: WorldBuffer) + static func getParameter(from worldBuffer: WorldBuffer) -> Self? +} + From 7958aef42c76feb7a9460c85822092f30682e23a Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:34:01 +0900 Subject: [PATCH 05/42] add implement of world --- Sources/ECS/World/World.swift | 9 +++++++-- Sources/ECS/World/WorldBuffer.swift | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Sources/ECS/World/World.swift b/Sources/ECS/World/World.swift index 7bcb18e..b5a5653 100644 --- a/Sources/ECS/World/World.swift +++ b/Sources/ECS/World/World.swift @@ -6,7 +6,12 @@ // final public class World { - public init() { - + var entities: [Entity: Archetype] + public let worldBuffer: WorldBuffer + + init(entities: [Entity: Archetype], worldBuffer: WorldBuffer) { + self.entities = entities + self.worldBuffer = worldBuffer } + } diff --git a/Sources/ECS/World/WorldBuffer.swift b/Sources/ECS/World/WorldBuffer.swift index de89dee..09b2e81 100644 --- a/Sources/ECS/World/WorldBuffer.swift +++ b/Sources/ECS/World/WorldBuffer.swift @@ -10,4 +10,3 @@ import GameplayKit final public class WorldBuffer: GKEntity { } - From 467fb2118898fe5aff6d15003905edd9594c0f54 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:38:41 +0900 Subject: [PATCH 06/42] add Chunk --- Sources/ECS/Chunk/AddChunk.swift | 8 ----- Sources/ECS/Chunk/Chunk.swift | 7 ++-- Sources/ECS/Chunk/ChunkBuffer.swift | 32 +++++++++++++++++- Sources/ECS/Chunk/Spawn+Chunk.swift | 51 ++++++++++++++--------------- 4 files changed, 61 insertions(+), 37 deletions(-) delete mode 100644 Sources/ECS/Chunk/AddChunk.swift diff --git a/Sources/ECS/Chunk/AddChunk.swift b/Sources/ECS/Chunk/AddChunk.swift deleted file mode 100644 index 175c602..0000000 --- a/Sources/ECS/Chunk/AddChunk.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// File.swift -// -// -// Created by rrbox on 2023/08/11. -// - -import Foundation diff --git a/Sources/ECS/Chunk/Chunk.swift b/Sources/ECS/Chunk/Chunk.swift index 175c602..1b77103 100644 --- a/Sources/ECS/Chunk/Chunk.swift +++ b/Sources/ECS/Chunk/Chunk.swift @@ -1,8 +1,11 @@ // -// File.swift +// Chunk.swift // // // Created by rrbox on 2023/08/11. // -import Foundation +public class Chunk { + func spawn(entity: Entity, value: Archetype) {} + func despawn(entity: Entity) {} +} diff --git a/Sources/ECS/Chunk/ChunkBuffer.swift b/Sources/ECS/Chunk/ChunkBuffer.swift index 175c602..84b3101 100644 --- a/Sources/ECS/Chunk/ChunkBuffer.swift +++ b/Sources/ECS/Chunk/ChunkBuffer.swift @@ -1,8 +1,38 @@ // -// File.swift +// ChunkBuffer.swift // // // Created by rrbox on 2023/08/11. // import Foundation + +/// Chunk を種類別で格納します +class ChunkBuffer { + class ChunkRegistry: BufferElement { + let chunk: ChunkType + init(chunk: ChunkType) { + self.chunk = chunk + super.init() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + } + + let buffer: Buffer + init(buffer: Buffer) { + self.buffer = buffer + } + + func chunk(ofType type: ChunkType.Type) -> ChunkType? { + self.buffer.component(ofType: ChunkRegistry.self)?.chunk + } +} + +extension WorldBuffer { + var chunkBuffer: ChunkBuffer { + ChunkBuffer(buffer: self) + } +} diff --git a/Sources/ECS/Chunk/Spawn+Chunk.swift b/Sources/ECS/Chunk/Spawn+Chunk.swift index 322e460..008ade4 100644 --- a/Sources/ECS/Chunk/Spawn+Chunk.swift +++ b/Sources/ECS/Chunk/Spawn+Chunk.swift @@ -6,45 +6,44 @@ // /// Chunk を種類関係なく格納するためのコンポーネントです. -class ChunkEntityInterface { - class Command { - func apply(chunks: [Chunk]) { - - } - } -// var entityQueue = [(Entity, Archetype)]() - var spawnEntityQueue = [(Entity, Archetype)]() - var despawnEntityQueue = [Entity]() +class ChunkEntityInterface: BufferElement { + /// entity が spawn されてから component が完全に挿入されるまでの間, entity を queue に保管します. + /// + /// Entity が ``Commands/spawn()`` され, ``EntityCommands/addComponent(_:)`` されるまでの間, Entity は実際には Chunk に反映されず, + var prespawnedEntityQueue = [(Entity, Archetype)]() var chunks = [Chunk]() + /// chunk を追加します + func add(chunk: Chunk) { + self.chunks.append(chunk) + } + /// World に entity が追加された時に実行します. /// /// entity が queue に追加され、フレームの終わりに全ての chunk に entity を反映します. - func spawn(entity: Entity, value: Archetype) { - self.spawnEntityQueue.append((entity, value)) + func push(entity: Entity, value: Archetype) { + self.prespawnedEntityQueue.append((entity, value)) } - /// World から entity が削除される時に実行します. + /// Spawn 処理された entity を, 実際に chunk に追加します. /// - /// フレームの終わりに全ての chunk から entity をさ削除します. - func despawn(_ entity: Entity) { - self.despawnEntityQueue.append(entity) - } - - /// フレーム終了時、 enqueue された entity を全ての chunk に追加します. + /// Component が完全に追加された後にこの処理を呼び出すことで, Entity の Component の有無が Chunk に反映されるようになります. func applyEntityQueue() { - for (entity, value) in self.spawnEntityQueue { - for chunk in self.chunks { + for (entity, value) in prespawnedEntityQueue { + for chunk in chunks { chunk.spawn(entity: entity, value: value) } } - for entity in self.despawnEntityQueue { - for chunk in self.chunks { - chunk.despawn(entity: entity) - } + self.prespawnedEntityQueue = [] + } + + /// World から entity が削除される時に実行します. + /// + /// フレームの終わりに全ての chunk から entity を削除します. + func despawn(entity: Entity) { + for chunk in chunks { + chunk.despawn(entity: entity) } - self.spawnEntityQueue = [] - self.despawnEntityQueue = [] } } From 30858cf3930611717d69f5589ff144cb0cd3f228 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:39:05 +0900 Subject: [PATCH 07/42] add queries --- Sources/ECS/Query/Query.swift | 38 ++++++++++++++++++++++++++++-- Sources/ECS/Query/Query2.swift | 39 +++++++++++++++++++++++++++++-- Sources/ECS/Query/Query3.swift | 40 ++++++++++++++++++++++++++++++-- Sources/ECS/Query/Query4.swift | 41 +++++++++++++++++++++++++++++++-- Sources/ECS/Query/Query5.swift | 42 ++++++++++++++++++++++++++++++++-- 5 files changed, 190 insertions(+), 10 deletions(-) diff --git a/Sources/ECS/Query/Query.swift b/Sources/ECS/Query/Query.swift index 307b616..2f9d271 100644 --- a/Sources/ECS/Query/Query.swift +++ b/Sources/ECS/Query/Query.swift @@ -1,8 +1,42 @@ // -// File.swift +// Query.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +final public class Query: Chunk, SystemParameter { + var components = [Entity: ComponentRef]() + + override func spawn(entity: Entity, value: Archetype) { + guard let componentRef = value.component(ofType: ComponentRef.self) else { return } + self.components[entity] = componentRef + } + + override func despawn(entity: Entity) { + self.components.removeValue(forKey: entity) + } + + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. + public func update(_ execute: (Entity, inout ComponentType) -> ()) { + for (entity, _) in self.components { + execute(entity, &self.components[entity]!.value) + } + } + + public static func register(to worldBuffer: WorldBuffer) { + guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { + return + } + + let queryRegistory = Self() + + worldBuffer.chunkBuffer.addChunk(queryRegistory) + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> Self? { + worldBuffer.chunkBuffer.chunk(ofType: Self.self) + } + +} diff --git a/Sources/ECS/Query/Query2.swift b/Sources/ECS/Query/Query2.swift index 307b616..1acdd63 100644 --- a/Sources/ECS/Query/Query2.swift +++ b/Sources/ECS/Query/Query2.swift @@ -1,8 +1,43 @@ // -// File.swift +// Query2.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +final public class Query2: Chunk, SystemParameter { + var components = [Entity: (ComponentRef, ComponentRef)]() + + override func spawn(entity: Entity, value: Archetype) { + guard let c0 = value.component(ofType: ComponentRef.self) else { return } + guard let c1 = value.component(ofType: ComponentRef.self) else { return } + self.components[entity] = (c0, c1) + } + + override func despawn(entity: Entity) { + self.components.removeValue(forKey: entity) + } + + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. + public func update(_ execute: (Entity, inout C0, inout C1) -> ()) { + for (entity, _) in self.components { + execute(entity, &self.components[entity]!.0.value, &self.components[entity]!.1.value) + } + } + + public static func register(to worldBuffer: WorldBuffer) { + guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { + return + } + + let queryRegistory = Self() + + worldBuffer.chunkBuffer.addChunk(queryRegistory) + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> Self? { + worldBuffer.chunkBuffer.chunk(ofType: Self.self) + } + +} diff --git a/Sources/ECS/Query/Query3.swift b/Sources/ECS/Query/Query3.swift index 307b616..5c90ffe 100644 --- a/Sources/ECS/Query/Query3.swift +++ b/Sources/ECS/Query/Query3.swift @@ -1,8 +1,44 @@ // -// File.swift +// Query3.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +final public class Query3: Chunk, SystemParameter { + var components = [Entity: (ComponentRef, ComponentRef, ComponentRef)]() + + override func spawn(entity: Entity, value: Archetype) { + guard let c0 = value.component(ofType: ComponentRef.self) else { return } + guard let c1 = value.component(ofType: ComponentRef.self) else { return } + guard let c2 = value.component(ofType: ComponentRef.self) else { return } + self.components[entity] = (c0, c1, c2) + } + + override func despawn(entity: Entity) { + self.components.removeValue(forKey: entity) + } + + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. + public func update(_ execute: (Entity, inout C0, inout C1, inout C2) -> ()) { + for (entity, _) in self.components { + execute(entity, &self.components[entity]!.0.value, &self.components[entity]!.1.value, &self.components[entity]!.2.value) + } + } + + public static func register(to worldBuffer: WorldBuffer) { + guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { + return + } + + let queryRegistory = Self() + + worldBuffer.chunkBuffer.addChunk(queryRegistory) + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> Self? { + worldBuffer.chunkBuffer.chunk(ofType: Self.self) + } + +} diff --git a/Sources/ECS/Query/Query4.swift b/Sources/ECS/Query/Query4.swift index 307b616..bd5b37d 100644 --- a/Sources/ECS/Query/Query4.swift +++ b/Sources/ECS/Query/Query4.swift @@ -1,8 +1,45 @@ // -// File.swift +// Query4.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +final public class Query4: Chunk, SystemParameter { + var components = [Entity: (ComponentRef, ComponentRef, ComponentRef, ComponentRef)]() + + override func spawn(entity: Entity, value: Archetype) { + guard let c0 = value.component(ofType: ComponentRef.self) else { return } + guard let c1 = value.component(ofType: ComponentRef.self) else { return } + guard let c2 = value.component(ofType: ComponentRef.self) else { return } + guard let c3 = value.component(ofType: ComponentRef.self) else { return } + self.components[entity] = (c0, c1, c2, c3) + } + + override func despawn(entity: Entity) { + self.components.removeValue(forKey: entity) + } + + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. + public func update(_ execute: (Entity, inout C0, inout C1, inout C2, inout C3) -> ()) { + for (entity, _) in self.components { + execute(entity, &self.components[entity]!.0.value, &self.components[entity]!.1.value, &self.components[entity]!.2.value, &self.components[entity]!.3.value) + } + } + + public static func register(to worldBuffer: WorldBuffer) { + guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { + return + } + + let queryRegistory = Self() + + worldBuffer.chunkBuffer.addChunk(queryRegistory) + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> Self? { + worldBuffer.chunkBuffer.chunk(ofType: Self.self) + } + +} diff --git a/Sources/ECS/Query/Query5.swift b/Sources/ECS/Query/Query5.swift index 307b616..d0fab4c 100644 --- a/Sources/ECS/Query/Query5.swift +++ b/Sources/ECS/Query/Query5.swift @@ -1,8 +1,46 @@ // -// File.swift +// Query5.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +final public class Query5: Chunk, SystemParameter { + var components = [Entity: (ComponentRef, ComponentRef, ComponentRef, ComponentRef, ComponentRef)]() + + override func spawn(entity: Entity, value: Archetype) { + guard let c0 = value.component(ofType: ComponentRef.self) else { return } + guard let c1 = value.component(ofType: ComponentRef.self) else { return } + guard let c2 = value.component(ofType: ComponentRef.self) else { return } + guard let c3 = value.component(ofType: ComponentRef.self) else { return } + guard let c4 = value.component(ofType: ComponentRef.self) else { return } + self.components[entity] = (c0, c1, c2, c3, c4) + } + + override func despawn(entity: Entity) { + self.components.removeValue(forKey: entity) + } + + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. + public func update(_ execute: (Entity, inout C0, inout C1, inout C2, inout C3, inout C4) -> ()) { + for (entity, _) in self.components { + execute(entity, &self.components[entity]!.0.value, &self.components[entity]!.1.value, &self.components[entity]!.2.value, &self.components[entity]!.3.value, &self.components[entity]!.4.value) + } + } + + public static func register(to worldBuffer: WorldBuffer) { + guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { + return + } + + let queryRegistory = Self() + + worldBuffer.chunkBuffer.addChunk(queryRegistory) + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> Self? { + worldBuffer.chunkBuffer.chunk(ofType: Self.self) + } + +} From 008cd9caf1b3e8b0e4fd36b6d35912f95fdebd44 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:39:22 +0900 Subject: [PATCH 08/42] add resource --- Sources/ECS/Resource/Commands+Resource.swift | 23 ++++++++++++++-- Sources/ECS/Resource/Resource.swift | 28 +++++++++++++++++++- Sources/ECS/Resource/ResourceBuffer.swift | 23 ++++++++++++++-- Sources/ECS/Resource/World+Resource.swift | 12 +++++++-- 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/Sources/ECS/Resource/Commands+Resource.swift b/Sources/ECS/Resource/Commands+Resource.swift index 307b616..a6bddc8 100644 --- a/Sources/ECS/Resource/Commands+Resource.swift +++ b/Sources/ECS/Resource/Commands+Resource.swift @@ -1,8 +1,27 @@ // -// File.swift +// Commands+Resource.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +class AddResource: Command { + let resrouce: T + + init(resrouce: T) { + self.resrouce = resrouce + } + + override func runCommand(in world: World) { + world.addResource(self.resrouce) + } +} + +public extension Commands { + /// world に対して resource を追加します. + /// + /// resource はフレームの終了直前に追加されます. + func addResource(_ resource: T) { + self.push(command: AddResource(resrouce: resource)) + } +} diff --git a/Sources/ECS/Resource/Resource.swift b/Sources/ECS/Resource/Resource.swift index 307b616..506c274 100644 --- a/Sources/ECS/Resource/Resource.swift +++ b/Sources/ECS/Resource/Resource.swift @@ -1,8 +1,34 @@ // -// File.swift +// Resource.swift // // // Created by rrbox on 2023/08/12. // import Foundation + +public protocol ResourceProtocol { + +} + +final public class Resource: BufferElement, SystemParameter { + public var resource: T + + init(_ resource: T) { + self.resource = resource + super.init() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public static func register(to worldBuffer: WorldBuffer) { + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> Resource? { + worldBuffer.resourceBuffer.resource(ofType: T.self) + } + +} diff --git a/Sources/ECS/Resource/ResourceBuffer.swift b/Sources/ECS/Resource/ResourceBuffer.swift index 307b616..779477e 100644 --- a/Sources/ECS/Resource/ResourceBuffer.swift +++ b/Sources/ECS/Resource/ResourceBuffer.swift @@ -1,8 +1,27 @@ // -// File.swift +// ResourceBuffer.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +class ResourceBuffer { + let buffer: Buffer + init(buffer: Buffer) { + self.buffer = buffer + } + + func addResource(_ resource: T) { + self.buffer.addComponent(Resource(resource)) + } + + func resource(ofType type: T.Type) -> Resource? { + self.buffer.component(ofType: Resource.self) + } +} + +extension WorldBuffer { + var resourceBuffer: ResourceBuffer { + ResourceBuffer(buffer: self) + } +} diff --git a/Sources/ECS/Resource/World+Resource.swift b/Sources/ECS/Resource/World+Resource.swift index 307b616..ae39bad 100644 --- a/Sources/ECS/Resource/World+Resource.swift +++ b/Sources/ECS/Resource/World+Resource.swift @@ -1,8 +1,16 @@ // -// File.swift +// World+Resource.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public extension World { + /// world に resource を追加します. + /// + /// ``Commands/addResource(_:)`` とは異なり, resource はこのメソッドが実行されてすぐに追加されます. + @discardableResult func addResource(_ resource: T) -> World { + self.worldBuffer.resourceBuffer.addResource(resource) + return self + } +} From d71707748d3be23163d6dc0d7f6facb5f42c6207 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:39:48 +0900 Subject: [PATCH 09/42] add system plug in API --- Sources/ECS/System/SystemBuffer.swift | 20 +++++++++++++------- Sources/ECS/System/World+SystemBuffer.swift | 17 +++++++++++++++-- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Sources/ECS/System/SystemBuffer.swift b/Sources/ECS/System/SystemBuffer.swift index 8cc7f7b..b257c3b 100644 --- a/Sources/ECS/System/SystemBuffer.swift +++ b/Sources/ECS/System/SystemBuffer.swift @@ -9,28 +9,34 @@ open class SystemExecute { } -final class SystemRegisotry: BufferElement { - var systems = [Execute]() -} - class SystemBuffer { + final class SystemRegisotry: BufferElement { + var systems = [Execute]() + } + let buffer: Buffer init(buffer: Buffer) { self.buffer = buffer } - func plugInSystems(ofType: System.Type) -> [System] { + func systems(ofType: System.Type) -> [System] { self.buffer.component(ofType: SystemRegisotry.self)!.systems } - func registerPlugIn(ofType type: System.Type) { + func registerSystemRegistry(ofType type: System.Type) { self.buffer.addComponent(SystemRegisotry.init()) } - func addPlugInSystem(_ system: System, as type: System.Type) { + func addSystem(_ system: System, as type: System.Type) { self.buffer .component(ofType: SystemRegisotry.self)! .systems .append(system) } } + +extension WorldBuffer { + var systemBuffer: SystemBuffer { + SystemBuffer(buffer: self) + } +} diff --git a/Sources/ECS/System/World+SystemBuffer.swift b/Sources/ECS/System/World+SystemBuffer.swift index 307b616..e1e7202 100644 --- a/Sources/ECS/System/World+SystemBuffer.swift +++ b/Sources/ECS/System/World+SystemBuffer.swift @@ -1,8 +1,21 @@ // -// File.swift +// World+SystemBuffer.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public extension World { + @discardableResult func registerSystemRegistry(ofType type: System.Type) -> World { + self.worldBuffer.systemBuffer.registerSystemRegistry(ofType: System.self) + return self + } + + /// World に system を追加します. + /// + /// system を追加する前に, ``World/registerSystemRegistry(ofType:)`` で system を保持するためのメモリ領域を確保する必要があります. + @discardableResult func addSystem(_ system: System, as type: System.Type) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: System.self) + return self + } +} From ecffd6a4f50b6932bd0b5492984cfe49d7cdee49 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:40:13 +0900 Subject: [PATCH 10/42] add update systems --- Sources/ECS/UpdateSystem/Resources.swift | 10 +++++- Sources/ECS/UpdateSystem/UpdateExecute.swift | 8 +++-- Sources/ECS/UpdateSystem/UpdateSystem.swift | 30 ++++++++++++++-- Sources/ECS/UpdateSystem/UpdateSystem2.swift | 31 ++++++++++++++-- Sources/ECS/UpdateSystem/UpdateSystem3.swift | 32 +++++++++++++++-- Sources/ECS/UpdateSystem/UpdateSystem4.swift | 33 +++++++++++++++-- Sources/ECS/UpdateSystem/UpdateSystem5.swift | 35 +++++++++++++++++-- .../UpdateSystem/UpdateSystemProtocols.swift | 32 +++++++++++++++-- 8 files changed, 196 insertions(+), 15 deletions(-) diff --git a/Sources/ECS/UpdateSystem/Resources.swift b/Sources/ECS/UpdateSystem/Resources.swift index 307b616..18ee54e 100644 --- a/Sources/ECS/UpdateSystem/Resources.swift +++ b/Sources/ECS/UpdateSystem/Resources.swift @@ -1,8 +1,16 @@ // -// File.swift +// Resources.swift // // // Created by rrbox on 2023/08/12. // import Foundation + +public struct CurrentTime: ResourceProtocol { + public let value: TimeInterval +} + +public struct DeltaTime: ResourceProtocol { + public let value: TimeInterval +} diff --git a/Sources/ECS/UpdateSystem/UpdateExecute.swift b/Sources/ECS/UpdateSystem/UpdateExecute.swift index 307b616..3d8f600 100644 --- a/Sources/ECS/UpdateSystem/UpdateExecute.swift +++ b/Sources/ECS/UpdateSystem/UpdateExecute.swift @@ -1,8 +1,12 @@ // -// File.swift +// UpdateExecute.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public class UpdateExecute: SystemExecute { + func update(worldBuffer: WorldBuffer) { + + } +} diff --git a/Sources/ECS/UpdateSystem/UpdateSystem.swift b/Sources/ECS/UpdateSystem/UpdateSystem.swift index 307b616..1ddcf18 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem.swift @@ -1,8 +1,34 @@ // -// File.swift +// UpdateSystem.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol UpdateSystemProtocol: SystemProtocol, UpdateExecute { + +} + +final public class UpdateSystem: UpdateExecute, UpdateSystemProtocol { + let execute: (Parameter) -> () + + init(execute: @escaping (Parameter) -> Void) { + self.execute = execute + } + + override func update(worldBuffer: WorldBuffer) { + self.execute(Parameter.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addUpdateSystem(_ system: System) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: UpdateExecute.self) + System.Parameter.register(to: self.worldBuffer) + return self + } + + @discardableResult func addUpdateSystem(_ execute: @escaping (Parameter) -> ()) -> World { + self.addUpdateSystem(UpdateSystem(execute: execute)) + } +} diff --git a/Sources/ECS/UpdateSystem/UpdateSystem2.swift b/Sources/ECS/UpdateSystem/UpdateSystem2.swift index 307b616..008f189 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem2.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem2.swift @@ -1,8 +1,35 @@ // -// File.swift +// UpdateSystem2.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol UpdateSystemProtocol2: SystemProtocol2, UpdateExecute { + +} + +final public class UpdateSystem2: UpdateExecute, UpdateSystemProtocol2 { + let execute: (P0, P1) -> () + + init(execute: @escaping (P0, P1) -> Void) { + self.execute = execute + } + + override func update(worldBuffer: WorldBuffer) { + self.execute(P0.getParameter(from: worldBuffer)!, P1.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addUpdateSystem(_ system: System) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: UpdateExecute.self) + System.P0.register(to: self.worldBuffer) + System.P1.register(to: self.worldBuffer) + return self + } + + @discardableResult func addUpdateSystem(_ execute: @escaping (P0, P1) -> ()) -> World { + self.addUpdateSystem(UpdateSystem2(execute: execute)) + } +} diff --git a/Sources/ECS/UpdateSystem/UpdateSystem3.swift b/Sources/ECS/UpdateSystem/UpdateSystem3.swift index 307b616..2c4a0a8 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem3.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem3.swift @@ -1,8 +1,36 @@ // -// File.swift +// UpdateSystem3.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol UpdateSystemProtocol3: SystemProtocol3, UpdateExecute { + +} + +final public class UpdateSystem3: UpdateExecute, UpdateSystemProtocol3 { + let execute: (P0, P1, P2) -> () + + init(execute: @escaping (P0, P1, P2) -> Void) { + self.execute = execute + } + + override func update(worldBuffer: WorldBuffer) { + self.execute(P0.getParameter(from: worldBuffer)!, P1.getParameter(from: worldBuffer)!, P2.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addUpdateSystem(_ system: System) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: UpdateExecute.self) + System.P0.register(to: self.worldBuffer) + System.P1.register(to: self.worldBuffer) + System.P2.register(to: self.worldBuffer) + return self + } + + @discardableResult func addUpdateSystem(_ execute: @escaping (P0, P1, P2) -> ()) -> World { + self.addUpdateSystem(UpdateSystem3(execute: execute)) + } +} diff --git a/Sources/ECS/UpdateSystem/UpdateSystem4.swift b/Sources/ECS/UpdateSystem/UpdateSystem4.swift index 307b616..6626028 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem4.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem4.swift @@ -1,8 +1,37 @@ // -// File.swift +// UpdateSystem4.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol UpdateSystemProtocol4: SystemProtocol4, UpdateExecute { + +} + +final public class UpdateSystem4: UpdateExecute, UpdateSystemProtocol4 { + let execute: (P0, P1, P2, P3) -> () + + init(execute: @escaping (P0, P1, P2, P3) -> Void) { + self.execute = execute + } + + override func update(worldBuffer: WorldBuffer) { + self.execute(P0.getParameter(from: worldBuffer)!, P1.getParameter(from: worldBuffer)!, P2.getParameter(from: worldBuffer)!, P3.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addUpdateSystem(_ system: System) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: UpdateExecute.self) + System.P0.register(to: self.worldBuffer) + System.P1.register(to: self.worldBuffer) + System.P2.register(to: self.worldBuffer) + System.P3.register(to: self.worldBuffer) + return self + } + + @discardableResult func addUpdateSystem(_ execute: @escaping (P0, P1, P2, P3) -> ()) -> World { + self.addUpdateSystem(UpdateSystem4(execute: execute)) + } +} diff --git a/Sources/ECS/UpdateSystem/UpdateSystem5.swift b/Sources/ECS/UpdateSystem/UpdateSystem5.swift index 307b616..5819c79 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem5.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem5.swift @@ -1,8 +1,39 @@ // -// File.swift +// UpdateSystem5.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol UpdateSystemProtocol5: SystemProtocol5, UpdateExecute { + +} + +final public class UpdateSystem5: UpdateExecute, UpdateSystemProtocol5 { + let execute: (P0, P1, P2, P3, P4) -> () + + init(execute: @escaping (P0, P1, P2, P3, P4) -> Void) { + self.execute = execute + } + + override func update(worldBuffer: WorldBuffer) { + self.execute(P0.getParameter(from: worldBuffer)!, P1.getParameter(from: worldBuffer)!, P2.getParameter(from: worldBuffer)!, P3.getParameter(from: worldBuffer)!, P4.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addUpdateSystem(_ system: System) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: UpdateExecute.self) + System.P0.register(to: self.worldBuffer) + System.P1.register(to: self.worldBuffer) + System.P2.register(to: self.worldBuffer) + System.P3.register(to: self.worldBuffer) + System.P4.register(to: self.worldBuffer) + return self + } + + @discardableResult func addUpdateSystem(_ execute: @escaping (P0, P1, P2, P3, P4) -> ()) -> World { + self.addUpdateSystem(UpdateSystem5(execute: execute)) + } +} + diff --git a/Sources/ECS/UpdateSystem/UpdateSystemProtocols.swift b/Sources/ECS/UpdateSystem/UpdateSystemProtocols.swift index 307b616..b6590d2 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystemProtocols.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystemProtocols.swift @@ -1,8 +1,36 @@ // -// File.swift +// UpdateSystemProtocols.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol SystemProtocol { + associatedtype Parameter: SystemParameter +} + +public protocol SystemProtocol2 { + associatedtype P0: SystemParameter + associatedtype P1: SystemParameter +} + +public protocol SystemProtocol3 { + associatedtype P0: SystemParameter + associatedtype P1: SystemParameter + associatedtype P2: SystemParameter +} + +public protocol SystemProtocol4 { + associatedtype P0: SystemParameter + associatedtype P1: SystemParameter + associatedtype P2: SystemParameter + associatedtype P3: SystemParameter +} + +public protocol SystemProtocol5 { + associatedtype P0: SystemParameter + associatedtype P1: SystemParameter + associatedtype P2: SystemParameter + associatedtype P3: SystemParameter + associatedtype P4: SystemParameter +} From b9229093f1a33461b3c2b6aed7d00995ed4b522a Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:40:33 +0900 Subject: [PATCH 11/42] add methods of world --- Sources/ECS/WorldMethods/World+Init.swift | 22 +++++++++++++++++++-- Sources/ECS/WorldMethods/World+Spawn.swift | 6 +++--- Sources/ECS/WorldMethods/World+Update.swift | 20 ++++++++++++++++++- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Sources/ECS/WorldMethods/World+Init.swift b/Sources/ECS/WorldMethods/World+Init.swift index 175c602..02ae531 100644 --- a/Sources/ECS/WorldMethods/World+Init.swift +++ b/Sources/ECS/WorldMethods/World+Init.swift @@ -1,8 +1,26 @@ // -// File.swift +// WorldInit.swift // // // Created by rrbox on 2023/08/11. // -import Foundation + +public extension World { + convenience init() { + self.init(entities: [:], worldBuffer: WorldBuffer()) + + // chunk buffer に chunk entity interface を追加します. + self.worldBuffer.chunkBuffer.setUpChunkBuffer() + + // resource buffer に 時間関係の resource を追加します. + self.worldBuffer.resourceBuffer.addResource(CurrentTime(value: 0)) + self.worldBuffer.resourceBuffer.addResource(DeltaTime(value: 0)) + + // world buffer に update system を保持する領域を確保します. + self.worldBuffer.systemBuffer.registerSystemRegistry(ofType: UpdateExecute.self) + + // world buffer に commands の初期値を設定します. + self.worldBuffer.commandsBuffer.setCommands(Commands()) + } +} diff --git a/Sources/ECS/WorldMethods/World+Spawn.swift b/Sources/ECS/WorldMethods/World+Spawn.swift index 275d8bc..dd1b6b4 100644 --- a/Sources/ECS/WorldMethods/World+Spawn.swift +++ b/Sources/ECS/WorldMethods/World+Spawn.swift @@ -9,12 +9,12 @@ extension World { /// Entity を登録します. /// /// ``Commands/spawn()`` が実行された後, フレームが終了するタイミングでこの関数が実行されます. - /// entity へのコンポーネントの登録などは, spawn の後に行われます. - func spawn(entity: Entity, value: Archetype) { + /// entity へのコンポーネントの登録などは, push の後に行われます. + func push(entity: Entity, value: Archetype) { self.entities[entity] = value self.worldBuffer .chunkBuffer - .spawn(entity: entity, value: value) + .push(entity: entity, value: value) } /// Entity を削除します. diff --git a/Sources/ECS/WorldMethods/World+Update.swift b/Sources/ECS/WorldMethods/World+Update.swift index 307b616..9cc7f3f 100644 --- a/Sources/ECS/WorldMethods/World+Update.swift +++ b/Sources/ECS/WorldMethods/World+Update.swift @@ -1,8 +1,26 @@ // -// File.swift +// World+Update.swift // // // Created by rrbox on 2023/08/12. // import Foundation + +public extension World { + func update(currentTime: TimeInterval) { + let lastTime = self.worldBuffer.resourceBuffer.resource(ofType: CurrentTime.self)!.resource.value + + self.worldBuffer.resourceBuffer.resource(ofType: DeltaTime.self)?.resource = DeltaTime(value: currentTime - lastTime) + + for system in self.worldBuffer.systemBuffer.systems(ofType: UpdateExecute.self) { + system.update(worldBuffer: self.worldBuffer) + } + + self.applyCommands() + // apply commands の際に push された entity を chunk に割り振ります. + self.worldBuffer.chunkBuffer.applyEntityQueue() + + self.worldBuffer.resourceBuffer.resource(ofType: CurrentTime.self)?.resource = CurrentTime(value: currentTime) + } +} From 7b9173853b70a739f4b7d3b45f6a1d8d437df0aa Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sat, 12 Aug 2023 16:41:05 +0900 Subject: [PATCH 12/42] update pachage.swift --- Package.swift | 68 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/Package.swift b/Package.swift index d3d46eb..6ad8646 100644 --- a/Package.swift +++ b/Package.swift @@ -35,6 +35,23 @@ extension Module { static let scrollPlugInTests = Module(name: "ScrollPlugInTests") } +extension Target { + static func target(module: Module, dependencies: [Module]) -> Target { + .target( + name: module.name, + dependencies: dependencies.map { $0.dependency }, + path: module.path) + } + + static func testTarget(module: Module, dependencies: [Module]) -> Target { + .testTarget( + name: module.name, + dependencies: dependencies.map { $0.dependency }, + path: module.path + ) + } +} + let package = Package( name: "ECS_Swift", products: [ @@ -60,45 +77,40 @@ let package = Package( // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( - name: Module.ecs.name, + module: .ecs, dependencies: []), .target( - name: Module.keyboard.name, - dependencies: [Module.ecs.dependency], - path: Module.keyboard.path), + module: .keyboard, + dependencies: [.ecs]), .target( - name: Module.mouse.name, - dependencies: [Module.ecs.dependency], - path: Module.mouse.path), + module: .mouse, + dependencies: [.ecs]), .target( - name: Module.objectLink.name, - dependencies: [Module.ecs.dependency], - path: Module.objectLink.path), + module: .objectLink, + dependencies: [.ecs]), .target( - name: Module.scene.name, - dependencies: [Module.ecs.dependency], - path: Module.scene.path), + module: .scene, + dependencies: [.ecs]), .target( - name: Module.scroll.name, - dependencies: [Module.ecs.dependency], - path: Module.scroll.path), + module: .scroll, + dependencies: [.ecs]), .testTarget( - name: Module.ecs_swiftTests.name, - dependencies: [Module.ecs.dependency]), + module: .ecs_swiftTests, + dependencies: [.ecs]), .testTarget( - name: Module.keyBoardPlugInTests.name, - dependencies: [Module.keyboard.dependency]), + module: .keyBoardPlugInTests, + dependencies: [.keyboard]), .testTarget( - name: Module.mousePlugInTests.name, - dependencies: [Module.mouse.dependency]), + module: .mousePlugInTests, + dependencies: [.mouse]), .testTarget( - name: Module.objectLinkPlugInTests.name, - dependencies: [Module.objectLink.dependency]), + module: .objectLinkPlugInTests, + dependencies: [.objectLink]), .testTarget( - name: Module.scenePlugInTests.name, - dependencies: [Module.scene.dependency]), + module: .scenePlugInTests, + dependencies: [.scene]), .testTarget( - name: Module.scrollPlugInTests.name, - dependencies: [Module.scroll.dependency]), + module: .scrollPlugInTests, + dependencies: [.scroll]), ] ) From 3dd3b67c41d886e1c977f680f6df981818b65582 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:27:00 +0900 Subject: [PATCH 13/42] add files --- ...Chunk.swift => ChunkEntityInterface.swift} | 0 Sources/ECS/Event/EventStreaming/Event.swift | 8 +++++ .../Event/EventStreaming/EventBuffer.swift | 8 +++++ .../ECS/Event/EventStreaming/EventQueue.swift | 8 +++++ .../Event/EventStreaming/EventReader.swift | 10 ++++++ .../Event/EventStreaming/EventWriter.swift | 8 +++++ .../EventStreaming/World+EventStreamer.swift | 8 +++++ .../ECS/Event/EventSystem/EventSystem.swift | 8 +++++ .../ECS/Event/EventSystem/EventSystem2.swift | 8 +++++ .../ECS/Event/EventSystem/EventSystem3.swift | 8 +++++ .../ECS/Event/EventSystem/EventSystem4.swift | 8 +++++ .../ECS/Event/EventSystem/EventSystem5.swift | 8 +++++ .../EventSystem/EventSystemExecute.swift | 8 +++++ Sources/ECS/SetUpSystem/SetUpSystem.swift | 8 +++++ Sources/ECS/SetUpSystem/SetUpSystem2.swift | 8 +++++ Sources/ECS/SetUpSystem/SetUpSystem3.swift | 8 +++++ Sources/ECS/SetUpSystem/SetUpSystem4.swift | 8 +++++ Sources/ECS/SetUpSystem/SetUpSystem5.swift | 8 +++++ .../ECS/SetUpSystem/SetUpSystemCommons.swift | 8 +++++ .../SetUpSystem/SetUpsystemParameters.swift | 8 +++++ .../SystemProtocols.swift} | 0 .../WorldMethods/World+EntityCommands.swift | 8 +++++ Sources/ECS/WorldMethods/World+SetUp.swift | 8 +++++ Tests/ecs-swiftTests/EventTests.swift | 35 +++++++++++++++++++ Tests/ecs-swiftTests/Mocks/Components.swift | 8 +++++ ...ReourceTests.swift => ResourceTests.swift} | 0 26 files changed, 213 insertions(+) rename Sources/ECS/Chunk/{Spawn+Chunk.swift => ChunkEntityInterface.swift} (100%) create mode 100644 Sources/ECS/Event/EventStreaming/Event.swift create mode 100644 Sources/ECS/Event/EventStreaming/EventBuffer.swift create mode 100644 Sources/ECS/Event/EventStreaming/EventQueue.swift create mode 100644 Sources/ECS/Event/EventStreaming/EventReader.swift create mode 100644 Sources/ECS/Event/EventStreaming/EventWriter.swift create mode 100644 Sources/ECS/Event/EventStreaming/World+EventStreamer.swift create mode 100644 Sources/ECS/Event/EventSystem/EventSystem.swift create mode 100644 Sources/ECS/Event/EventSystem/EventSystem2.swift create mode 100644 Sources/ECS/Event/EventSystem/EventSystem3.swift create mode 100644 Sources/ECS/Event/EventSystem/EventSystem4.swift create mode 100644 Sources/ECS/Event/EventSystem/EventSystem5.swift create mode 100644 Sources/ECS/Event/EventSystem/EventSystemExecute.swift create mode 100644 Sources/ECS/SetUpSystem/SetUpSystem.swift create mode 100644 Sources/ECS/SetUpSystem/SetUpSystem2.swift create mode 100644 Sources/ECS/SetUpSystem/SetUpSystem3.swift create mode 100644 Sources/ECS/SetUpSystem/SetUpSystem4.swift create mode 100644 Sources/ECS/SetUpSystem/SetUpSystem5.swift create mode 100644 Sources/ECS/SetUpSystem/SetUpSystemCommons.swift create mode 100644 Sources/ECS/SetUpSystem/SetUpsystemParameters.swift rename Sources/ECS/{UpdateSystem/UpdateSystemProtocols.swift => System/SystemProtocols.swift} (100%) create mode 100644 Sources/ECS/WorldMethods/World+EntityCommands.swift create mode 100644 Sources/ECS/WorldMethods/World+SetUp.swift create mode 100644 Tests/ecs-swiftTests/EventTests.swift create mode 100644 Tests/ecs-swiftTests/Mocks/Components.swift rename Tests/ecs-swiftTests/{ReourceTests.swift => ResourceTests.swift} (100%) diff --git a/Sources/ECS/Chunk/Spawn+Chunk.swift b/Sources/ECS/Chunk/ChunkEntityInterface.swift similarity index 100% rename from Sources/ECS/Chunk/Spawn+Chunk.swift rename to Sources/ECS/Chunk/ChunkEntityInterface.swift diff --git a/Sources/ECS/Event/EventStreaming/Event.swift b/Sources/ECS/Event/EventStreaming/Event.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventStreaming/Event.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventStreaming/EventBuffer.swift b/Sources/ECS/Event/EventStreaming/EventBuffer.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventStreaming/EventBuffer.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventStreaming/EventQueue.swift b/Sources/ECS/Event/EventStreaming/EventQueue.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventStreaming/EventQueue.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventStreaming/EventReader.swift b/Sources/ECS/Event/EventStreaming/EventReader.swift new file mode 100644 index 0000000..b37b4f1 --- /dev/null +++ b/Sources/ECS/Event/EventStreaming/EventReader.swift @@ -0,0 +1,10 @@ +// +// EventReader.swift +// +// +// Created by rrbox on 2023/08/14. +// + +public struct EventReader { + public let value: T +} diff --git a/Sources/ECS/Event/EventStreaming/EventWriter.swift b/Sources/ECS/Event/EventStreaming/EventWriter.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventStreaming/EventWriter.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventStreaming/World+EventStreamer.swift b/Sources/ECS/Event/EventStreaming/World+EventStreamer.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventStreaming/World+EventStreamer.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventSystem/EventSystem.swift b/Sources/ECS/Event/EventSystem/EventSystem.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventSystem/EventSystem.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventSystem/EventSystem2.swift b/Sources/ECS/Event/EventSystem/EventSystem2.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventSystem/EventSystem2.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventSystem/EventSystem3.swift b/Sources/ECS/Event/EventSystem/EventSystem3.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventSystem/EventSystem3.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventSystem/EventSystem4.swift b/Sources/ECS/Event/EventSystem/EventSystem4.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventSystem/EventSystem4.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventSystem/EventSystem5.swift b/Sources/ECS/Event/EventSystem/EventSystem5.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventSystem/EventSystem5.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/Event/EventSystem/EventSystemExecute.swift b/Sources/ECS/Event/EventSystem/EventSystemExecute.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/Event/EventSystem/EventSystemExecute.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/SetUpSystem/SetUpSystem.swift b/Sources/ECS/SetUpSystem/SetUpSystem.swift new file mode 100644 index 0000000..307b616 --- /dev/null +++ b/Sources/ECS/SetUpSystem/SetUpSystem.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/12. +// + +import Foundation diff --git a/Sources/ECS/SetUpSystem/SetUpSystem2.swift b/Sources/ECS/SetUpSystem/SetUpSystem2.swift new file mode 100644 index 0000000..307b616 --- /dev/null +++ b/Sources/ECS/SetUpSystem/SetUpSystem2.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/12. +// + +import Foundation diff --git a/Sources/ECS/SetUpSystem/SetUpSystem3.swift b/Sources/ECS/SetUpSystem/SetUpSystem3.swift new file mode 100644 index 0000000..307b616 --- /dev/null +++ b/Sources/ECS/SetUpSystem/SetUpSystem3.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/12. +// + +import Foundation diff --git a/Sources/ECS/SetUpSystem/SetUpSystem4.swift b/Sources/ECS/SetUpSystem/SetUpSystem4.swift new file mode 100644 index 0000000..307b616 --- /dev/null +++ b/Sources/ECS/SetUpSystem/SetUpSystem4.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/12. +// + +import Foundation diff --git a/Sources/ECS/SetUpSystem/SetUpSystem5.swift b/Sources/ECS/SetUpSystem/SetUpSystem5.swift new file mode 100644 index 0000000..307b616 --- /dev/null +++ b/Sources/ECS/SetUpSystem/SetUpSystem5.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/12. +// + +import Foundation diff --git a/Sources/ECS/SetUpSystem/SetUpSystemCommons.swift b/Sources/ECS/SetUpSystem/SetUpSystemCommons.swift new file mode 100644 index 0000000..307b616 --- /dev/null +++ b/Sources/ECS/SetUpSystem/SetUpSystemCommons.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/12. +// + +import Foundation diff --git a/Sources/ECS/SetUpSystem/SetUpsystemParameters.swift b/Sources/ECS/SetUpSystem/SetUpsystemParameters.swift new file mode 100644 index 0000000..307b616 --- /dev/null +++ b/Sources/ECS/SetUpSystem/SetUpsystemParameters.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/12. +// + +import Foundation diff --git a/Sources/ECS/UpdateSystem/UpdateSystemProtocols.swift b/Sources/ECS/System/SystemProtocols.swift similarity index 100% rename from Sources/ECS/UpdateSystem/UpdateSystemProtocols.swift rename to Sources/ECS/System/SystemProtocols.swift diff --git a/Sources/ECS/WorldMethods/World+EntityCommands.swift b/Sources/ECS/WorldMethods/World+EntityCommands.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Sources/ECS/WorldMethods/World+EntityCommands.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Sources/ECS/WorldMethods/World+SetUp.swift b/Sources/ECS/WorldMethods/World+SetUp.swift new file mode 100644 index 0000000..307b616 --- /dev/null +++ b/Sources/ECS/WorldMethods/World+SetUp.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/12. +// + +import Foundation diff --git a/Tests/ecs-swiftTests/EventTests.swift b/Tests/ecs-swiftTests/EventTests.swift new file mode 100644 index 0000000..dc20e38 --- /dev/null +++ b/Tests/ecs-swiftTests/EventTests.swift @@ -0,0 +1,35 @@ +// +// EventTests.swift +// +// +// Created by rrbox on 2023/08/13. +// + +import XCTest + +final class EventTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/Tests/ecs-swiftTests/Mocks/Components.swift b/Tests/ecs-swiftTests/Mocks/Components.swift new file mode 100644 index 0000000..e46c664 --- /dev/null +++ b/Tests/ecs-swiftTests/Mocks/Components.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import Foundation diff --git a/Tests/ecs-swiftTests/ReourceTests.swift b/Tests/ecs-swiftTests/ResourceTests.swift similarity index 100% rename from Tests/ecs-swiftTests/ReourceTests.swift rename to Tests/ecs-swiftTests/ResourceTests.swift From 60c32337bf6644304c3f7802da802383c15ec5af Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:29:54 +0900 Subject: [PATCH 14/42] add macos version --- Package.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Package.swift b/Package.swift index 6ad8646..6229763 100644 --- a/Package.swift +++ b/Package.swift @@ -54,6 +54,7 @@ extension Target { let package = Package( name: "ECS_Swift", + platforms: [.macOS(.v10_15)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( From 0cfed82961d9f668f2297e06fa70841287ab5d63 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:48:25 +0900 Subject: [PATCH 15/42] change Archetype to EntityRecord --- Sources/ECS/Chunk/Chunk.swift | 2 +- Sources/ECS/Chunk/ChunkBuffer+.swift | 4 ++-- Sources/ECS/Chunk/ChunkEntityInterface.swift | 16 +++++++++------- Sources/ECS/Commons/Types.swift | 2 +- .../EntityCommands/Commands+EntityCommands.swift | 2 +- .../EntityCommands/Commands/SpawnCommand.swift | 8 ++++---- Sources/ECS/Query/Query.swift | 4 ++-- Sources/ECS/Query/Query2.swift | 6 +++--- Sources/ECS/Query/Query3.swift | 8 ++++---- Sources/ECS/Query/Query4.swift | 10 +++++----- Sources/ECS/Query/Query5.swift | 12 ++++++------ Sources/ECS/WorldMethods/World+Spawn.swift | 8 ++++---- 12 files changed, 42 insertions(+), 40 deletions(-) diff --git a/Sources/ECS/Chunk/Chunk.swift b/Sources/ECS/Chunk/Chunk.swift index 1b77103..07c5558 100644 --- a/Sources/ECS/Chunk/Chunk.swift +++ b/Sources/ECS/Chunk/Chunk.swift @@ -6,6 +6,6 @@ // public class Chunk { - func spawn(entity: Entity, value: Archetype) {} + func spawn(entity: Entity, entityRecord: EntityRecord) {} func despawn(entity: Entity) {} } diff --git a/Sources/ECS/Chunk/ChunkBuffer+.swift b/Sources/ECS/Chunk/ChunkBuffer+.swift index cc38989..3be80bb 100644 --- a/Sources/ECS/Chunk/ChunkBuffer+.swift +++ b/Sources/ECS/Chunk/ChunkBuffer+.swift @@ -15,8 +15,8 @@ extension ChunkBuffer { self.buffer.component(ofType: ChunkEntityInterface.self)!.add(chunk: chunk) } - func push(entity: Entity, value: Archetype) { - self.buffer.component(ofType: ChunkEntityInterface.self)!.push(entity: entity, value: value) + func push(entity: Entity, entityRecord: EntityRecord) { + self.buffer.component(ofType: ChunkEntityInterface.self)!.push(entity: entity, entityRecord: entityRecord) } func applyEntityQueue() { diff --git a/Sources/ECS/Chunk/ChunkEntityInterface.swift b/Sources/ECS/Chunk/ChunkEntityInterface.swift index 008ade4..1315fbb 100644 --- a/Sources/ECS/Chunk/ChunkEntityInterface.swift +++ b/Sources/ECS/Chunk/ChunkEntityInterface.swift @@ -1,16 +1,18 @@ // -// Spawn+Chunk.swift +// ChunkEntityInterface.swift // // // Created by rrbox on 2023/08/11. // /// Chunk を種類関係なく格納するためのコンポーネントです. +/// +/// Entity の変更を全ての Chunk に反映させる目的で使用されます. class ChunkEntityInterface: BufferElement { /// entity が spawn されてから component が完全に挿入されるまでの間, entity を queue に保管します. /// /// Entity が ``Commands/spawn()`` され, ``EntityCommands/addComponent(_:)`` されるまでの間, Entity は実際には Chunk に反映されず, - var prespawnedEntityQueue = [(Entity, Archetype)]() + var prespawnedEntityQueue = [(Entity, EntityRecord)]() var chunks = [Chunk]() /// chunk を追加します @@ -21,17 +23,17 @@ class ChunkEntityInterface: BufferElement { /// World に entity が追加された時に実行します. /// /// entity が queue に追加され、フレームの終わりに全ての chunk に entity を反映します. - func push(entity: Entity, value: Archetype) { - self.prespawnedEntityQueue.append((entity, value)) + func push(entity: Entity, entityRecord: EntityRecord) { + self.prespawnedEntityQueue.append((entity, entityRecord)) } /// Spawn 処理された entity を, 実際に chunk に追加します. /// /// Component が完全に追加された後にこの処理を呼び出すことで, Entity の Component の有無が Chunk に反映されるようになります. func applyEntityQueue() { - for (entity, value) in prespawnedEntityQueue { - for chunk in chunks { - chunk.spawn(entity: entity, value: value) + for (entity, entityRecord) in prespawnedEntityQueue { + for chunk in self.chunks { + chunk.spawn(entity: entity, entityRecord: entityRecord) } } self.prespawnedEntityQueue = [] diff --git a/Sources/ECS/Commons/Types.swift b/Sources/ECS/Commons/Types.swift index ac44a2f..2f955bd 100644 --- a/Sources/ECS/Commons/Types.swift +++ b/Sources/ECS/Commons/Types.swift @@ -7,7 +7,7 @@ import GameplayKit -public typealias Archetype = GKEntity +public typealias EntityRecord = GKEntity public typealias ArchetypeComponent = GKComponent public typealias Buffer = GKEntity public typealias BufferElement = GKComponent diff --git a/Sources/ECS/EntityCommands/Commands+EntityCommands.swift b/Sources/ECS/EntityCommands/Commands+EntityCommands.swift index e4f84b2..591ca45 100644 --- a/Sources/ECS/EntityCommands/Commands+EntityCommands.swift +++ b/Sources/ECS/EntityCommands/Commands+EntityCommands.swift @@ -14,7 +14,7 @@ public extension Commands { /// Entity を追加して変更を加えます. func spawn() -> EntityCommands { let entity = Entity() - self.commandQueue.append(SpawnCommand(id: entity, value: Archetype())) + self.commandQueue.append(SpawnCommand(id: entity, entityRecord: EntityRecord())) return EntityCommands(entity: entity, commands: self) } diff --git a/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift b/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift index 566c1b5..143eec2 100644 --- a/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift @@ -7,15 +7,15 @@ class SpawnCommand: Command { let id: Entity - let value: Archetype + let entityRecord: EntityRecord - init(id: Entity, value: Archetype) { + init(id: Entity, entityRecord: EntityRecord) { self.id = id - self.value = value + self.entityRecord = entityRecord } override func runCommand(in world: World) { - world.push(entity: self.id, value: self.value) + world.push(entity: self.id, entityRecord: self.entityRecord) } } diff --git a/Sources/ECS/Query/Query.swift b/Sources/ECS/Query/Query.swift index 2f9d271..ca07824 100644 --- a/Sources/ECS/Query/Query.swift +++ b/Sources/ECS/Query/Query.swift @@ -8,8 +8,8 @@ final public class Query: Chunk, SystemParameter { var components = [Entity: ComponentRef]() - override func spawn(entity: Entity, value: Archetype) { - guard let componentRef = value.component(ofType: ComponentRef.self) else { return } + override func spawn(entity: Entity, entityRecord: EntityRecord) { + guard let componentRef = entityRecord.component(ofType: ComponentRef.self) else { return } self.components[entity] = componentRef } diff --git a/Sources/ECS/Query/Query2.swift b/Sources/ECS/Query/Query2.swift index 1acdd63..4c035f3 100644 --- a/Sources/ECS/Query/Query2.swift +++ b/Sources/ECS/Query/Query2.swift @@ -8,9 +8,9 @@ final public class Query2: Chunk, SystemParameter { var components = [Entity: (ComponentRef, ComponentRef)]() - override func spawn(entity: Entity, value: Archetype) { - guard let c0 = value.component(ofType: ComponentRef.self) else { return } - guard let c1 = value.component(ofType: ComponentRef.self) else { return } + override func spawn(entity: Entity, entityRecord: EntityRecord) { + guard let c0 = entityRecord.component(ofType: ComponentRef.self), + let c1 = entityRecord.component(ofType: ComponentRef.self) else { return } self.components[entity] = (c0, c1) } diff --git a/Sources/ECS/Query/Query3.swift b/Sources/ECS/Query/Query3.swift index 5c90ffe..bae18b9 100644 --- a/Sources/ECS/Query/Query3.swift +++ b/Sources/ECS/Query/Query3.swift @@ -8,10 +8,10 @@ final public class Query3: Chunk, SystemParameter { var components = [Entity: (ComponentRef, ComponentRef, ComponentRef)]() - override func spawn(entity: Entity, value: Archetype) { - guard let c0 = value.component(ofType: ComponentRef.self) else { return } - guard let c1 = value.component(ofType: ComponentRef.self) else { return } - guard let c2 = value.component(ofType: ComponentRef.self) else { return } + override func spawn(entity: Entity, entityRecord: EntityRecord) { + guard let c0 = entityRecord.component(ofType: ComponentRef.self), + let c1 = entityRecord.component(ofType: ComponentRef.self), + let c2 = entityRecord.component(ofType: ComponentRef.self) else { return } self.components[entity] = (c0, c1, c2) } diff --git a/Sources/ECS/Query/Query4.swift b/Sources/ECS/Query/Query4.swift index bd5b37d..1230447 100644 --- a/Sources/ECS/Query/Query4.swift +++ b/Sources/ECS/Query/Query4.swift @@ -8,11 +8,11 @@ final public class Query4: Chunk, SystemParameter { var components = [Entity: (ComponentRef, ComponentRef, ComponentRef, ComponentRef)]() - override func spawn(entity: Entity, value: Archetype) { - guard let c0 = value.component(ofType: ComponentRef.self) else { return } - guard let c1 = value.component(ofType: ComponentRef.self) else { return } - guard let c2 = value.component(ofType: ComponentRef.self) else { return } - guard let c3 = value.component(ofType: ComponentRef.self) else { return } + override func spawn(entity: Entity, entityRecord: EntityRecord) { + guard let c0 = entityRecord.component(ofType: ComponentRef.self), + let c1 = entityRecord.component(ofType: ComponentRef.self), + let c2 = entityRecord.component(ofType: ComponentRef.self), + let c3 = entityRecord.component(ofType: ComponentRef.self) else { return } self.components[entity] = (c0, c1, c2, c3) } diff --git a/Sources/ECS/Query/Query5.swift b/Sources/ECS/Query/Query5.swift index d0fab4c..f5f74fc 100644 --- a/Sources/ECS/Query/Query5.swift +++ b/Sources/ECS/Query/Query5.swift @@ -8,12 +8,12 @@ final public class Query5: Chunk, SystemParameter { var components = [Entity: (ComponentRef, ComponentRef, ComponentRef, ComponentRef, ComponentRef)]() - override func spawn(entity: Entity, value: Archetype) { - guard let c0 = value.component(ofType: ComponentRef.self) else { return } - guard let c1 = value.component(ofType: ComponentRef.self) else { return } - guard let c2 = value.component(ofType: ComponentRef.self) else { return } - guard let c3 = value.component(ofType: ComponentRef.self) else { return } - guard let c4 = value.component(ofType: ComponentRef.self) else { return } + override func spawn(entity: Entity, entityRecord: EntityRecord) { + guard let c0 = entityRecord.component(ofType: ComponentRef.self), + let c1 = entityRecord.component(ofType: ComponentRef.self), + let c2 = entityRecord.component(ofType: ComponentRef.self), + let c3 = entityRecord.component(ofType: ComponentRef.self), + let c4 = entityRecord.component(ofType: ComponentRef.self) else { return } self.components[entity] = (c0, c1, c2, c3, c4) } diff --git a/Sources/ECS/WorldMethods/World+Spawn.swift b/Sources/ECS/WorldMethods/World+Spawn.swift index dd1b6b4..9ba0f2b 100644 --- a/Sources/ECS/WorldMethods/World+Spawn.swift +++ b/Sources/ECS/WorldMethods/World+Spawn.swift @@ -10,18 +10,18 @@ extension World { /// /// ``Commands/spawn()`` が実行された後, フレームが終了するタイミングでこの関数が実行されます. /// entity へのコンポーネントの登録などは, push の後に行われます. - func push(entity: Entity, value: Archetype) { - self.entities[entity] = value + func push(entity: Entity, entityRecord: EntityRecord) { + self.entities.insert(entity: entity, entityRecord: entityRecord) self.worldBuffer .chunkBuffer - .push(entity: entity, value: value) + .push(entity: entity, entityRecord: entityRecord) } /// Entity を削除します. /// /// ``Commands/despawn()`` が実行された後, フレームが終了するタイミングでこの関数が実行されます. func despawn(entity: Entity) { - self.entities.removeValue(forKey: entity) + self.entities.remove(entity: entity) self.worldBuffer .chunkBuffer .despawn(entity: entity) From c6b52ede26d1664ea490d06bc523a94268ed9374 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:54:17 +0900 Subject: [PATCH 16/42] add struct Entities --- Sources/ECS/World/World.swift | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Sources/ECS/World/World.swift b/Sources/ECS/World/World.swift index b5a5653..0e8b81d 100644 --- a/Sources/ECS/World/World.swift +++ b/Sources/ECS/World/World.swift @@ -5,12 +5,28 @@ // Created by rrbox on 2023/08/06. // +public struct Entities { + var sequence: [Entity: EntityRecord] + + public mutating func insert(entity: Entity, entityRecord: EntityRecord) { + self.sequence[entity] = entityRecord + } + + public mutating func remove(entity: Entity) { + self.sequence.removeValue(forKey: entity) + } + + public mutating func entityRecord(forEntity entity: Entity) -> EntityRecord? { + self.sequence[entity] + } +} + final public class World { - var entities: [Entity: Archetype] + var entities: Entities public let worldBuffer: WorldBuffer - init(entities: [Entity: Archetype], worldBuffer: WorldBuffer) { - self.entities = entities + init(entities: [Entity: EntityRecord], worldBuffer: WorldBuffer) { + self.entities = Entities(sequence: entities) self.worldBuffer = worldBuffer } From cf57929784d3213b98db0c900f0ed56a3ea5088a Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Wed, 16 Aug 2023 20:41:48 +0900 Subject: [PATCH 17/42] add Chunk/applyCurrentState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新しく仕様変更する, addComponent, removeComponent のための変更です. --- Sources/ECS/Chunk/Chunk.swift | 1 + Sources/ECS/Chunk/ChunkBuffer+.swift | 5 +++++ Sources/ECS/Chunk/ChunkEntityInterface.swift | 8 +++++++- Sources/ECS/Query/Query.swift | 8 ++++++++ Sources/ECS/Query/Query2.swift | 10 ++++++++++ Sources/ECS/Query/Query3.swift | 10 ++++++++++ Sources/ECS/Query/Query4.swift | 11 +++++++++++ Sources/ECS/Query/Query5.swift | 12 ++++++++++++ 8 files changed, 64 insertions(+), 1 deletion(-) diff --git a/Sources/ECS/Chunk/Chunk.swift b/Sources/ECS/Chunk/Chunk.swift index 07c5558..3c2f7e4 100644 --- a/Sources/ECS/Chunk/Chunk.swift +++ b/Sources/ECS/Chunk/Chunk.swift @@ -8,4 +8,5 @@ public class Chunk { func spawn(entity: Entity, entityRecord: EntityRecord) {} func despawn(entity: Entity) {} + func applyCurrentState(_ entityRecord: EntityRecord, forEntity entity: Entity) {} } diff --git a/Sources/ECS/Chunk/ChunkBuffer+.swift b/Sources/ECS/Chunk/ChunkBuffer+.swift index 3be80bb..88dd8bf 100644 --- a/Sources/ECS/Chunk/ChunkBuffer+.swift +++ b/Sources/ECS/Chunk/ChunkBuffer+.swift @@ -27,4 +27,9 @@ extension ChunkBuffer { self.buffer.component(ofType: ChunkEntityInterface.self)!.despawn(entity: entity) } + // entity を最新の状態に更新します. + func applyCurrentState(_ entityRecord: EntityRecord, forEntity entity: Entity) { + self.buffer.component(ofType: ChunkEntityInterface.self)!.applyCurrentState(entityRecord, forEntity: entity) + } + } diff --git a/Sources/ECS/Chunk/ChunkEntityInterface.swift b/Sources/ECS/Chunk/ChunkEntityInterface.swift index 1315fbb..b4dccbf 100644 --- a/Sources/ECS/Chunk/ChunkEntityInterface.swift +++ b/Sources/ECS/Chunk/ChunkEntityInterface.swift @@ -43,9 +43,15 @@ class ChunkEntityInterface: BufferElement { /// /// フレームの終わりに全ての chunk から entity を削除します. func despawn(entity: Entity) { - for chunk in chunks { + for chunk in self.chunks { chunk.despawn(entity: entity) } } + func applyCurrentState(_ entityRecord: EntityRecord, forEntity entity: Entity) { + for chunk in self.chunks { + chunk.applyCurrentState(entityRecord, forEntity: entity) + } + } + } diff --git a/Sources/ECS/Query/Query.swift b/Sources/ECS/Query/Query.swift index ca07824..5ab71e4 100644 --- a/Sources/ECS/Query/Query.swift +++ b/Sources/ECS/Query/Query.swift @@ -17,6 +17,14 @@ final public class Query: Chunk, SystemParameter { self.components.removeValue(forKey: entity) } + override func applyCurrentState(_ entityRecord: EntityRecord, forEntity entity: Entity) { + guard let componentRef = entityRecord.component(ofType: ComponentRef.self) else { + self.components.removeValue(forKey: entity) + return + } + self.components[entity] = componentRef + } + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. public func update(_ execute: (Entity, inout ComponentType) -> ()) { for (entity, _) in self.components { diff --git a/Sources/ECS/Query/Query2.swift b/Sources/ECS/Query/Query2.swift index 4c035f3..5d23edf 100644 --- a/Sources/ECS/Query/Query2.swift +++ b/Sources/ECS/Query/Query2.swift @@ -18,6 +18,16 @@ final public class Query2: Chunk, SystemParameter self.components.removeValue(forKey: entity) } + override func applyCurrentState(_ entityRecord: EntityRecord, forEntity entity: Entity) { + guard let c0 = entityRecord.component(ofType: ComponentRef.self), + let c1 = entityRecord.component(ofType: ComponentRef.self) else { + self.components.removeValue(forKey: entity) + return + } + self.components[entity] = (c0, c1) + + } + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. public func update(_ execute: (Entity, inout C0, inout C1) -> ()) { for (entity, _) in self.components { diff --git a/Sources/ECS/Query/Query3.swift b/Sources/ECS/Query/Query3.swift index bae18b9..be734e6 100644 --- a/Sources/ECS/Query/Query3.swift +++ b/Sources/ECS/Query/Query3.swift @@ -19,6 +19,16 @@ final public class Query3: Chunk, S self.components.removeValue(forKey: entity) } + override func applyCurrentState(_ entityRecord: EntityRecord, forEntity entity: Entity) { + guard let c0 = entityRecord.component(ofType: ComponentRef.self), + let c1 = entityRecord.component(ofType: ComponentRef.self), + let c2 = entityRecord.component(ofType: ComponentRef.self) else { + self.components.removeValue(forKey: entity) + return + } + self.components[entity] = (c0, c1, c2) + } + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. public func update(_ execute: (Entity, inout C0, inout C1, inout C2) -> ()) { for (entity, _) in self.components { diff --git a/Sources/ECS/Query/Query4.swift b/Sources/ECS/Query/Query4.swift index 1230447..7592dfd 100644 --- a/Sources/ECS/Query/Query4.swift +++ b/Sources/ECS/Query/Query4.swift @@ -20,6 +20,17 @@ final public class Query4.self), + let c1 = entityRecord.component(ofType: ComponentRef.self), + let c2 = entityRecord.component(ofType: ComponentRef.self), + let c3 = entityRecord.component(ofType: ComponentRef.self) else { + self.components.removeValue(forKey: entity) + return + } + self.components[entity] = (c0, c1, c2, c3) + } + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. public func update(_ execute: (Entity, inout C0, inout C1, inout C2, inout C3) -> ()) { for (entity, _) in self.components { diff --git a/Sources/ECS/Query/Query5.swift b/Sources/ECS/Query/Query5.swift index f5f74fc..541e7eb 100644 --- a/Sources/ECS/Query/Query5.swift +++ b/Sources/ECS/Query/Query5.swift @@ -21,6 +21,18 @@ final public class Query5.self), + let c1 = entityRecord.component(ofType: ComponentRef.self), + let c2 = entityRecord.component(ofType: ComponentRef.self), + let c3 = entityRecord.component(ofType: ComponentRef.self), + let c4 = entityRecord.component(ofType: ComponentRef.self) else { + self.components.removeValue(forKey: entity) + return + } + self.components[entity] = (c0, c1, c2, c3, c4) + } + /// Query で指定した Component を持つ entity を world から取得し, イテレーションします. public func update(_ execute: (Entity, inout C0, inout C1, inout C2, inout C3, inout C4) -> ()) { for (entity, _) in self.components { From c7e67208aa551b30511ce892f37309736399e32b Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 17 Aug 2023 18:00:43 +0900 Subject: [PATCH 18/42] =?UTF-8?q?change:=20addComponent,=20removeComponent?= =?UTF-8?q?=20=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89=E5=AE=9F=E8=A1=8C?= =?UTF-8?q?=E5=BE=8C=E3=81=AB=20applyCurrentState=20=E3=82=92=E5=AE=9F?= =?UTF-8?q?=E8=A1=8C=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E5=A4=89?= =?UTF-8?q?=E6=9B=B4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commands/AddComponentCommand.swift | 7 +----- .../Commands/RemoveComponentCommand.swift | 2 +- .../WorldMethods/World+EntityCommands.swift | 22 +++++++++++++++++-- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift b/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift index c4714ae..4b33102 100644 --- a/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift @@ -15,11 +15,6 @@ class AddComponent: Command { } override func runCommand(in world: World) { - guard let componentRef = world.entities[self.entity]? - .component(ofType: ComponentRef.self) else { - world.entities[self.entity]?.addComponent(ComponentRef(component: self.componnet)) - return - } - componentRef.value = self.componnet + world.addComponent(self.componnet, forEntity: self.entity) } } diff --git a/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift b/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift index f117178..5db0a66 100644 --- a/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift @@ -13,6 +13,6 @@ class RemoveComponent: Command { } override func runCommand(in world: World) { - world.entities[self.entity]?.removeComponent(ofType: ComponentRef.self) + world.removeComponent(ofType: ComponentType.self, fromEntity: self.entity) } } diff --git a/Sources/ECS/WorldMethods/World+EntityCommands.swift b/Sources/ECS/WorldMethods/World+EntityCommands.swift index e46c664..5b4d0b2 100644 --- a/Sources/ECS/WorldMethods/World+EntityCommands.swift +++ b/Sources/ECS/WorldMethods/World+EntityCommands.swift @@ -1,8 +1,26 @@ // -// File.swift +// World+EntityCommands.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +extension World { + /// Entity に Component を追加します. + func addComponent(_ component: ComponentType, forEntity entity: Entity) { + let archetype = self.entities.entityRecord(forEntity: entity)! + if let componentRef = archetype.component(ofType: ComponentRef.self) { + componentRef.value = component + } + archetype.addComponent(ComponentRef(component: component)) + self.worldBuffer.chunkBuffer.applyCurrentState(archetype, forEntity: entity) + } + + /// Entity から Component を削除します. + func removeComponent(ofType type: ComponentType.Type, fromEntity entity: Entity) { + let archetype = self.entities.entityRecord(forEntity: entity)! + archetype.removeComponent(ofType: ComponentRef.self) + self.worldBuffer.chunkBuffer.applyCurrentState(archetype, forEntity: entity) + } +} + From 6f8f31c5dec139c84d6d4a8edf0480244c935fe4 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 17 Aug 2023 19:51:15 +0900 Subject: [PATCH 19/42] add: set up system --- Sources/ECS/SetUpSystem/SetUpSystem.swift | 30 +++++++++++++- Sources/ECS/SetUpSystem/SetUpSystem2.swift | 33 +++++++++++++++- Sources/ECS/SetUpSystem/SetUpSystem3.swift | 35 ++++++++++++++++- Sources/ECS/SetUpSystem/SetUpSystem4.swift | 37 +++++++++++++++++- Sources/ECS/SetUpSystem/SetUpSystem5.swift | 39 ++++++++++++++++++- .../ECS/SetUpSystem/SetUpSystemCommons.swift | 10 ++++- .../SetUpSystem/SetUpsystemParameters.swift | 10 ++++- Sources/ECS/WorldMethods/World+Init.swift | 4 +- Sources/ECS/WorldMethods/World+SetUp.swift | 12 +++++- 9 files changed, 193 insertions(+), 17 deletions(-) diff --git a/Sources/ECS/SetUpSystem/SetUpSystem.swift b/Sources/ECS/SetUpSystem/SetUpSystem.swift index 307b616..af91e40 100644 --- a/Sources/ECS/SetUpSystem/SetUpSystem.swift +++ b/Sources/ECS/SetUpSystem/SetUpSystem.swift @@ -1,8 +1,34 @@ // -// File.swift +// SetUpSystem.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol SetUpSystemProtocol: SystemProtocol, SetUpExecute { + +} + +final public class SetUpSystem: SetUpExecute, SetUpSystemProtocol { + let execute: (Parameter) -> () + + public init(_ execute: @escaping (Parameter) -> ()) { + self.execute = execute + } + + override func setUp(worldBuffer: WorldBuffer) { + self.execute(Parameter.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addSetUpSystem(_ system: System) -> World { + self.addSystem(system, as: SetUpExecute.self) + System.Parameter.register(to: self.worldBuffer) + return self + } + + @discardableResult func addSetUpSystem(_ execute: @escaping (Parameter) -> ()) -> World { + self.addSetUpSystem(SetUpSystem(execute)) + } +} diff --git a/Sources/ECS/SetUpSystem/SetUpSystem2.swift b/Sources/ECS/SetUpSystem/SetUpSystem2.swift index 307b616..c20287c 100644 --- a/Sources/ECS/SetUpSystem/SetUpSystem2.swift +++ b/Sources/ECS/SetUpSystem/SetUpSystem2.swift @@ -1,8 +1,37 @@ // -// File.swift +// SetUpSystem2.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol SetUpSystemProtocol2: SystemProtocol2, SetUpExecute { + +} + +final public class SetUpSystem2: SetUpExecute, SetUpSystemProtocol2 { + let execute: (P0, P1) -> () + + public init(_ execute: @escaping (P0, P1) -> ()) { + self.execute = execute + } + + override func setUp(worldBuffer: WorldBuffer) { + self.execute( + P0.getParameter(from: worldBuffer)!, + P1.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addSetUpSystem(_ system: System) -> World { + self.addSystem(system, as: SetUpExecute.self) + System.P0.register(to: self.worldBuffer) + System.P1.register(to: self.worldBuffer) + return self + } + + @discardableResult func addSetUpSystem(_ execute: @escaping (P0, P1) -> ()) -> World { + self.addSetUpSystem(SetUpSystem2(execute)) + } +} diff --git a/Sources/ECS/SetUpSystem/SetUpSystem3.swift b/Sources/ECS/SetUpSystem/SetUpSystem3.swift index 307b616..ad99ea5 100644 --- a/Sources/ECS/SetUpSystem/SetUpSystem3.swift +++ b/Sources/ECS/SetUpSystem/SetUpSystem3.swift @@ -1,8 +1,39 @@ // -// File.swift +// SetUpSystem3.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol SetUpSystemProtocol3: SystemProtocol3, SetUpExecute { + +} + +final public class SetUpSystem3: SetUpExecute, SetUpSystemProtocol3 { + let execute: (P0, P1, P2) -> () + + public init(_ execute: @escaping (P0, P1, P2) -> ()) { + self.execute = execute + } + + override func setUp(worldBuffer: WorldBuffer) { + self.execute( + P0.getParameter(from: worldBuffer)!, + P1.getParameter(from: worldBuffer)!, + P2.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addSetUpSystem(_ system: System) -> World { + self.addSystem(system, as: SetUpExecute.self) + System.P0.register(to: self.worldBuffer) + System.P1.register(to: self.worldBuffer) + System.P2.register(to: self.worldBuffer) + return self + } + + @discardableResult func addSetUpSystem(_ execute: @escaping (P0, P1, P2) -> ()) -> World { + self.addSetUpSystem(SetUpSystem3(execute)) + } +} diff --git a/Sources/ECS/SetUpSystem/SetUpSystem4.swift b/Sources/ECS/SetUpSystem/SetUpSystem4.swift index 307b616..bdb1cde 100644 --- a/Sources/ECS/SetUpSystem/SetUpSystem4.swift +++ b/Sources/ECS/SetUpSystem/SetUpSystem4.swift @@ -1,8 +1,41 @@ // -// File.swift +// SetUpSystem4.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol SetUpSystemProtocol4: SystemProtocol4, SetUpExecute { + +} + +final public class SetUpSystem4: SetUpExecute, SetUpSystemProtocol4 { + let execute: (P0, P1, P2, P3) -> () + + public init(_ execute: @escaping (P0, P1, P2, P3) -> ()) { + self.execute = execute + } + + override func setUp(worldBuffer: WorldBuffer) { + self.execute( + P0.getParameter(from: worldBuffer)!, + P1.getParameter(from: worldBuffer)!, + P2.getParameter(from: worldBuffer)!, + P3.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addSetUpSystem(_ system: System) -> World { + self.addSystem(system, as: SetUpExecute.self) + System.P0.register(to: self.worldBuffer) + System.P1.register(to: self.worldBuffer) + System.P2.register(to: self.worldBuffer) + System.P3.register(to: self.worldBuffer) + return self + } + + @discardableResult func addSetUpSystem(_ execute: @escaping (P0, P1, P2, P3) -> ()) -> World { + self.addSetUpSystem(SetUpSystem4(execute)) + } +} diff --git a/Sources/ECS/SetUpSystem/SetUpSystem5.swift b/Sources/ECS/SetUpSystem/SetUpSystem5.swift index 307b616..8e7868f 100644 --- a/Sources/ECS/SetUpSystem/SetUpSystem5.swift +++ b/Sources/ECS/SetUpSystem/SetUpSystem5.swift @@ -1,8 +1,43 @@ // -// File.swift +// SetUpSystem5.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol SetUpSystemProtocol5: SystemProtocol5, SetUpExecute { + +} + +final public class SetUpSystem5: SetUpExecute, SetUpSystemProtocol5 { + let execute: (P0, P1, P2, P3, P4) -> () + + public init(_ execute: @escaping (P0, P1, P2, P3, P4) -> ()) { + self.execute = execute + } + + override func setUp(worldBuffer: WorldBuffer) { + self.execute( + P0.getParameter(from: worldBuffer)!, + P1.getParameter(from: worldBuffer)!, + P2.getParameter(from: worldBuffer)!, + P3.getParameter(from: worldBuffer)!, + P4.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addSetUpSystem(_ system: System) -> World { + self.addSystem(system, as: SetUpExecute.self) + System.P0.register(to: self.worldBuffer) + System.P1.register(to: self.worldBuffer) + System.P2.register(to: self.worldBuffer) + System.P3.register(to: self.worldBuffer) + System.P4.register(to: self.worldBuffer) + return self + } + + @discardableResult func addSetUpSystem(_ execute: @escaping (P0, P1, P2, P3, P4) -> ()) -> World { + self.addSetUpSystem(SetUpSystem5(execute)) + } +} diff --git a/Sources/ECS/SetUpSystem/SetUpSystemCommons.swift b/Sources/ECS/SetUpSystem/SetUpSystemCommons.swift index 307b616..19b3467 100644 --- a/Sources/ECS/SetUpSystem/SetUpSystemCommons.swift +++ b/Sources/ECS/SetUpSystem/SetUpSystemCommons.swift @@ -1,8 +1,14 @@ // -// File.swift +// SetUpSystemCommons.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public protocol SetUpSystemParameter: SystemParameter { + +} + +public class SetUpExecute: SystemExecute { + func setUp(worldBuffer: WorldBuffer) {} +} diff --git a/Sources/ECS/SetUpSystem/SetUpsystemParameters.swift b/Sources/ECS/SetUpSystem/SetUpsystemParameters.swift index 307b616..4776cec 100644 --- a/Sources/ECS/SetUpSystem/SetUpsystemParameters.swift +++ b/Sources/ECS/SetUpSystem/SetUpsystemParameters.swift @@ -1,8 +1,14 @@ // -// File.swift +// SetUpsystemParameters.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +extension Commands: SetUpSystemParameter { + +} + +extension Resource: SetUpSystemParameter { + +} diff --git a/Sources/ECS/WorldMethods/World+Init.swift b/Sources/ECS/WorldMethods/World+Init.swift index 02ae531..f736756 100644 --- a/Sources/ECS/WorldMethods/World+Init.swift +++ b/Sources/ECS/WorldMethods/World+Init.swift @@ -5,7 +5,6 @@ // Created by rrbox on 2023/08/11. // - public extension World { convenience init() { self.init(entities: [:], worldBuffer: WorldBuffer()) @@ -17,6 +16,9 @@ public extension World { self.worldBuffer.resourceBuffer.addResource(CurrentTime(value: 0)) self.worldBuffer.resourceBuffer.addResource(DeltaTime(value: 0)) + // world buffer に setup system を保持する領域を確保します. + self.worldBuffer.systemBuffer.registerSystemRegistry(ofType: SetUpExecute.self) + // world buffer に update system を保持する領域を確保します. self.worldBuffer.systemBuffer.registerSystemRegistry(ofType: UpdateExecute.self) diff --git a/Sources/ECS/WorldMethods/World+SetUp.swift b/Sources/ECS/WorldMethods/World+SetUp.swift index 307b616..d9813f5 100644 --- a/Sources/ECS/WorldMethods/World+SetUp.swift +++ b/Sources/ECS/WorldMethods/World+SetUp.swift @@ -1,8 +1,16 @@ // -// File.swift +// World+SetUp.swift // // // Created by rrbox on 2023/08/12. // -import Foundation +public extension World { + func setUpWorld() { + for system in self.worldBuffer.systemBuffer.systems(ofType: SetUpExecute.self) { + system.setUp(worldBuffer: self.worldBuffer) + } + self.applyCommands() + self.worldBuffer.chunkBuffer.applyEntityQueue() + } +} From adf4fbe4b59d0a342062ab38c789478453c44574 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sun, 20 Aug 2023 08:36:59 +0900 Subject: [PATCH 20/42] add: files --- .../EntityCommands/EntityCommand.swift | 8 ++ .../{ => EntityCommands}/EntityCommands.swift | 4 + Sources/ECS/World/World+Entities.swift | 8 ++ Sources/ECS/WorldMethods/World+PlugIn.swift | 8 ++ Sources/PlugIns/Graphic/Graphic.swift | 90 +++++++++++++++++++ .../GraphicPlugInTests.swift | 35 ++++++++ 6 files changed, 153 insertions(+) create mode 100644 Sources/ECS/EntityCommands/EntityCommands/EntityCommand.swift rename Sources/ECS/EntityCommands/{ => EntityCommands}/EntityCommands.swift (92%) create mode 100644 Sources/ECS/World/World+Entities.swift create mode 100644 Sources/ECS/WorldMethods/World+PlugIn.swift create mode 100644 Sources/PlugIns/Graphic/Graphic.swift create mode 100644 Tests/GraphicPlugInTests/GraphicPlugInTests.swift diff --git a/Sources/ECS/EntityCommands/EntityCommands/EntityCommand.swift b/Sources/ECS/EntityCommands/EntityCommands/EntityCommand.swift new file mode 100644 index 0000000..380511a --- /dev/null +++ b/Sources/ECS/EntityCommands/EntityCommands/EntityCommand.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/18. +// + +import Foundation diff --git a/Sources/ECS/EntityCommands/EntityCommands.swift b/Sources/ECS/EntityCommands/EntityCommands/EntityCommands.swift similarity index 92% rename from Sources/ECS/EntityCommands/EntityCommands.swift rename to Sources/ECS/EntityCommands/EntityCommands/EntityCommands.swift index dfef972..a9e9ad9 100644 --- a/Sources/ECS/EntityCommands/EntityCommands.swift +++ b/Sources/ECS/EntityCommands/EntityCommands/EntityCommands.swift @@ -14,6 +14,10 @@ final public class EntityCommands { self.commands = commands } + public func pushCommand(_ command: Command) { + self.commands.commandQueue.append(command) + } + /// Commands で操作した Entity を受け取ります. /// - Returns: ID としての Entity をそのまま返します. public func id() -> Entity { diff --git a/Sources/ECS/World/World+Entities.swift b/Sources/ECS/World/World+Entities.swift new file mode 100644 index 0000000..380511a --- /dev/null +++ b/Sources/ECS/World/World+Entities.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/18. +// + +import Foundation diff --git a/Sources/ECS/WorldMethods/World+PlugIn.swift b/Sources/ECS/WorldMethods/World+PlugIn.swift new file mode 100644 index 0000000..32ccd7f --- /dev/null +++ b/Sources/ECS/WorldMethods/World+PlugIn.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/19. +// + +import Foundation diff --git a/Sources/PlugIns/Graphic/Graphic.swift b/Sources/PlugIns/Graphic/Graphic.swift new file mode 100644 index 0000000..8ccd44f --- /dev/null +++ b/Sources/PlugIns/Graphic/Graphic.swift @@ -0,0 +1,90 @@ +// +// Grahpic.swift +// +// +// Created by rrbox on 2023/08/18. +// + +import GameplayKit +import ECS + +public struct SceneResource: ResourceProtocol { + public unowned let scene: SKNode + public init(_ scene: SKNode) { + self.scene = scene + } +} + +//class NodeBox: GKComponent { +// let node: SKNode +// init(node: SKNode) { +// self.node = node +// super.init() +// } +// +// required init?(coder: NSCoder) { +// fatalError("init(coder:) has not been implemented") +// } +//} + +public class Graphic: Component { + public unowned let nodeRef: SKNode + init(node: SKNode) { + self.nodeRef = node + } +} + +extension World { + func setGraphic(_ node: SKNode, forEntity entity: Entity) { + node.userData = [:] + node.userData!["ECS/Entity"] = entity + let scene = self.worldBuffer.resourceBuffer.resource(ofType: SceneResource.self)?.resource.scene + scene?.addChild(node) + let entityRecord = self.entityRecord(forEntity: entity)! + entityRecord.addComponent(GKSKNodeComponent(node: node)) + } + + func removeGraphic(fromEntity entity: Entity) { + let entityRecord = self.entityRecord(forEntity: entity)! + let node = entityRecord.component(ofType: GKSKNodeComponent.self)!.node + node.removeFromParent() + entityRecord.removeComponent(ofType: GKSKNodeComponent.self) + } +} + +class SetGraphic: EntityCommand { + let node: SKNode + + init(node: SKNode, entity: Entity) { + self.node = node + super.init(entity: entity) + } + + override func runCommand(in world: World) { + world.setGraphic(self.node, forEntity: self.entity) + } +} + +class RemoveGraphic: EntityCommand { + override func runCommand(in world: World) { + world.removeGraphic(fromEntity: self.entity) + } +} + +public extension EntityCommands { + func setGraphic(_ node: Node) -> EntityCommands { + self.pushCommand(SetGraphic(node: node, entity: self.id())) + return self.addComponent(Graphic(node: node)) + } + + func removeGraphic() -> EntityCommands { + self.pushCommand(RemoveGraphic(entity: self.id())) + return self.removeComponent(ofType: Graphic.self) + } +} + +public extension SKNode { + func ecsEntity() -> Entity { + self.userData!["ECS/Entity"] as! Entity + } +} diff --git a/Tests/GraphicPlugInTests/GraphicPlugInTests.swift b/Tests/GraphicPlugInTests/GraphicPlugInTests.swift new file mode 100644 index 0000000..12cc1f3 --- /dev/null +++ b/Tests/GraphicPlugInTests/GraphicPlugInTests.swift @@ -0,0 +1,35 @@ +// +// GraphicPlugInTests.swift +// +// +// Created by rrbox on 2023/08/18. +// + +import XCTest + +final class GraphicPlugInTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} From 9163daceca7631e673a1aca49d24fc90b35b7b22 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sun, 20 Aug 2023 08:47:19 +0900 Subject: [PATCH 21/42] add: files for Graphic --- .../PlugIns/Graphic/Commands/EntityCommands+Graphic.swift | 8 ++++++++ Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift | 8 ++++++++ Sources/PlugIns/Graphic/Commands/SetGraphic.swift | 8 ++++++++ Sources/PlugIns/Graphic/World+Graphic.swift | 8 ++++++++ 4 files changed, 32 insertions(+) create mode 100644 Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift create mode 100644 Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift create mode 100644 Sources/PlugIns/Graphic/Commands/SetGraphic.swift create mode 100644 Sources/PlugIns/Graphic/World+Graphic.swift diff --git a/Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift b/Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift new file mode 100644 index 0000000..c40cd5c --- /dev/null +++ b/Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/20. +// + +import Foundation diff --git a/Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift b/Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift new file mode 100644 index 0000000..c40cd5c --- /dev/null +++ b/Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/20. +// + +import Foundation diff --git a/Sources/PlugIns/Graphic/Commands/SetGraphic.swift b/Sources/PlugIns/Graphic/Commands/SetGraphic.swift new file mode 100644 index 0000000..c40cd5c --- /dev/null +++ b/Sources/PlugIns/Graphic/Commands/SetGraphic.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/20. +// + +import Foundation diff --git a/Sources/PlugIns/Graphic/World+Graphic.swift b/Sources/PlugIns/Graphic/World+Graphic.swift new file mode 100644 index 0000000..c40cd5c --- /dev/null +++ b/Sources/PlugIns/Graphic/World+Graphic.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/20. +// + +import Foundation From 3282f0ef5743fcc03cc0ffcae6c71801dda39780 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sun, 20 Aug 2023 08:47:39 +0900 Subject: [PATCH 22/42] add: Graphic --- .../Commands/EntityCommands+Graphic.swift | 18 ++++- .../Graphic/Commands/RemoveGraphic.swift | 11 ++- .../PlugIns/Graphic/Commands/SetGraphic.swift | 19 ++++- Sources/PlugIns/Graphic/Graphic.swift | 73 ++++--------------- Sources/PlugIns/Graphic/World+Graphic.swift | 24 +++++- 5 files changed, 78 insertions(+), 67 deletions(-) diff --git a/Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift b/Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift index c40cd5c..d2ae07e 100644 --- a/Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift +++ b/Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift @@ -1,8 +1,22 @@ // -// File.swift +// EntityCommands+Graphic.swift // // // Created by rrbox on 2023/08/20. // -import Foundation +import SpriteKit +import ECS + +public extension EntityCommands { + @discardableResult func setGraphic(_ node: Node) -> EntityCommands { + self.pushCommand(SetGraphic(node: node, entity: self.id())) + return self.addComponent(Graphic(node: node)).addComponent(Graphic(node: node)) + } + + @discardableResult func removeGraphic() -> EntityCommands { + self.pushCommand(RemoveGraphic(entity: self.id())) + return self.removeComponent(ofType: Graphic.self).removeComponent(ofType: Graphic.self) + } +} + diff --git a/Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift b/Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift index c40cd5c..131b6f0 100644 --- a/Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift +++ b/Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift @@ -1,8 +1,15 @@ // -// File.swift +// RemoveGraphic.swift // // // Created by rrbox on 2023/08/20. // -import Foundation +import ECS + +class RemoveGraphic: EntityCommand { + override func runCommand(in world: World) { + world.removeGraphic(fromEntity: self.entity) + } +} + diff --git a/Sources/PlugIns/Graphic/Commands/SetGraphic.swift b/Sources/PlugIns/Graphic/Commands/SetGraphic.swift index c40cd5c..420881d 100644 --- a/Sources/PlugIns/Graphic/Commands/SetGraphic.swift +++ b/Sources/PlugIns/Graphic/Commands/SetGraphic.swift @@ -1,8 +1,23 @@ // -// File.swift +// SetGraphic.swift // // // Created by rrbox on 2023/08/20. // -import Foundation +import SpriteKit +import ECS + +class SetGraphic: EntityCommand { + let node: SKNode + + init(node: SKNode, entity: Entity) { + self.node = node + super.init(entity: entity) + } + + override func runCommand(in world: World) { + world.setGraphic(self.node, forEntity: self.entity) + } +} + diff --git a/Sources/PlugIns/Graphic/Graphic.swift b/Sources/PlugIns/Graphic/Graphic.swift index 8ccd44f..ec3f27f 100644 --- a/Sources/PlugIns/Graphic/Graphic.swift +++ b/Sources/PlugIns/Graphic/Graphic.swift @@ -9,77 +9,32 @@ import GameplayKit import ECS public struct SceneResource: ResourceProtocol { - public unowned let scene: SKNode - public init(_ scene: SKNode) { + public unowned let scene: SKScene + public init(_ scene: SKScene) { self.scene = scene } } -//class NodeBox: GKComponent { -// let node: SKNode -// init(node: SKNode) { -// self.node = node -// super.init() -// } -// -// required init?(coder: NSCoder) { -// fatalError("init(coder:) has not been implemented") -// } -//} - -public class Graphic: Component { - public unowned let nodeRef: SKNode - init(node: SKNode) { +public struct Graphic: Component { + public unowned let nodeRef: Node + init(node: Node) { self.nodeRef = node } } -extension World { - func setGraphic(_ node: SKNode, forEntity entity: Entity) { - node.userData = [:] - node.userData!["ECS/Entity"] = entity - let scene = self.worldBuffer.resourceBuffer.resource(ofType: SceneResource.self)?.resource.scene - scene?.addChild(node) - let entityRecord = self.entityRecord(forEntity: entity)! - entityRecord.addComponent(GKSKNodeComponent(node: node)) - } - - func removeGraphic(fromEntity entity: Entity) { - let entityRecord = self.entityRecord(forEntity: entity)! - let node = entityRecord.component(ofType: GKSKNodeComponent.self)!.node - node.removeFromParent() - entityRecord.removeComponent(ofType: GKSKNodeComponent.self) - } -} - -class SetGraphic: EntityCommand { - let node: SKNode - - init(node: SKNode, entity: Entity) { - self.node = node - super.init(entity: entity) +class GraphicDespawmDetector: GKComponent { + unowned let nodeRef: SKNode + init(nodeRef: SKNode) { + self.nodeRef = nodeRef + super.init() } - override func runCommand(in world: World) { - world.setGraphic(self.node, forEntity: self.entity) - } -} - -class RemoveGraphic: EntityCommand { - override func runCommand(in world: World) { - world.removeGraphic(fromEntity: self.entity) - } -} - -public extension EntityCommands { - func setGraphic(_ node: Node) -> EntityCommands { - self.pushCommand(SetGraphic(node: node, entity: self.id())) - return self.addComponent(Graphic(node: node)) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") } - func removeGraphic() -> EntityCommands { - self.pushCommand(RemoveGraphic(entity: self.id())) - return self.removeComponent(ofType: Graphic.self) + deinit { + self.nodeRef.removeFromParent() } } diff --git a/Sources/PlugIns/Graphic/World+Graphic.swift b/Sources/PlugIns/Graphic/World+Graphic.swift index c40cd5c..d166cc2 100644 --- a/Sources/PlugIns/Graphic/World+Graphic.swift +++ b/Sources/PlugIns/Graphic/World+Graphic.swift @@ -1,8 +1,28 @@ // -// File.swift +// World+Graphic.swift // // // Created by rrbox on 2023/08/20. // -import Foundation +import GameplayKit +import ECS + +extension World { + func setGraphic(_ node: Node, forEntity entity: Entity) { + node.userData = [:] + node.userData!["ECS/Entity"] = entity + let scene = self.worldBuffer.resourceBuffer.resource(ofType: SceneResource.self)?.resource.scene + scene?.addChild(node) + let entityRecord = self.entityRecord(forEntity: entity)! + entityRecord.addComponent(GKSKNodeComponent(node: node)) + entityRecord.addComponent(GraphicDespawmDetector(nodeRef: node)) + } + + func removeGraphic(fromEntity entity: Entity) { + let entityRecord = self.entityRecord(forEntity: entity)! + entityRecord.removeComponent(ofType: GKSKNodeComponent.self) + entityRecord.removeComponent(ofType: GraphicDespawmDetector.self) + } +} + From 3d94fa7dc4820b48ba86589b803190abb8544e84 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Wed, 13 Sep 2023 22:35:59 +0900 Subject: [PATCH 23/42] add: files --- .../CommandsEvent+Buffer.swift} | 2 +- .../Event/CommandsEvent/CommandsEvent.swift | 8 +++++ .../CommandsEvent/CommandsEventQueue.swift | 8 +++++ .../CommandsEvent/CommandsEventWriter.swift | 8 +++++ Sources/ECS/Event/World+EventStreamer.swift | 35 +++++++++++++++++++ ...rces.swift => UpdateSystemResources.swift} | 0 Sources/ECS/World/WorldResources.swift | 8 +++++ 7 files changed, 68 insertions(+), 1 deletion(-) rename Sources/ECS/Event/{EventStreaming/World+EventStreamer.swift => CommandsEvent/CommandsEvent+Buffer.swift} (57%) create mode 100644 Sources/ECS/Event/CommandsEvent/CommandsEvent.swift create mode 100644 Sources/ECS/Event/CommandsEvent/CommandsEventQueue.swift create mode 100644 Sources/ECS/Event/CommandsEvent/CommandsEventWriter.swift create mode 100644 Sources/ECS/Event/World+EventStreamer.swift rename Sources/ECS/UpdateSystem/{Resources.swift => UpdateSystemResources.swift} (100%) create mode 100644 Sources/ECS/World/WorldResources.swift diff --git a/Sources/ECS/Event/EventStreaming/World+EventStreamer.swift b/Sources/ECS/Event/CommandsEvent/CommandsEvent+Buffer.swift similarity index 57% rename from Sources/ECS/Event/EventStreaming/World+EventStreamer.swift rename to Sources/ECS/Event/CommandsEvent/CommandsEvent+Buffer.swift index e46c664..100ab2e 100644 --- a/Sources/ECS/Event/EventStreaming/World+EventStreamer.swift +++ b/Sources/ECS/Event/CommandsEvent/CommandsEvent+Buffer.swift @@ -2,7 +2,7 @@ // File.swift // // -// Created by rrbox on 2023/08/14. +// Created by rrbox on 2023/08/29. // import Foundation diff --git a/Sources/ECS/Event/CommandsEvent/CommandsEvent.swift b/Sources/ECS/Event/CommandsEvent/CommandsEvent.swift new file mode 100644 index 0000000..100ab2e --- /dev/null +++ b/Sources/ECS/Event/CommandsEvent/CommandsEvent.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/29. +// + +import Foundation diff --git a/Sources/ECS/Event/CommandsEvent/CommandsEventQueue.swift b/Sources/ECS/Event/CommandsEvent/CommandsEventQueue.swift new file mode 100644 index 0000000..100ab2e --- /dev/null +++ b/Sources/ECS/Event/CommandsEvent/CommandsEventQueue.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/29. +// + +import Foundation diff --git a/Sources/ECS/Event/CommandsEvent/CommandsEventWriter.swift b/Sources/ECS/Event/CommandsEvent/CommandsEventWriter.swift new file mode 100644 index 0000000..100ab2e --- /dev/null +++ b/Sources/ECS/Event/CommandsEvent/CommandsEventWriter.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/29. +// + +import Foundation diff --git a/Sources/ECS/Event/World+EventStreamer.swift b/Sources/ECS/Event/World+EventStreamer.swift new file mode 100644 index 0000000..d078d31 --- /dev/null +++ b/Sources/ECS/Event/World+EventStreamer.swift @@ -0,0 +1,35 @@ +// +// World+EventStreamer.swift +// +// +// Created by rrbox on 2023/08/14. +// + +public extension World { + /// `T` 型の値をイベントとして送受信するためのセットアップです. + /// + /// `Event` をイベントシステムで扱う前に, World に EventStreamer を追加する必要があります. + @discardableResult func addEventStreamer(eventType: T.Type) -> World { + self.worldBuffer.systemBuffer.registerSystemRegistry(ofType: EventSystemExecute.self) + self.worldBuffer.eventBuffer.registerEventWriter(eventType: T.self) + return self + } +} + +extension World { + func applyEventQueue() { + let eventQueue = self.worldBuffer.eventBuffer.eventQueue()! + eventQueue.sendingEvents = eventQueue.eventQueue + eventQueue.eventQueue = [] + for event in eventQueue.sendingEvents { + event.runEventReceiver(worldBuffer: self.worldBuffer) + } + eventQueue.sendingEvents = [] + } +} + +public extension World { + func sendEvent(_ value: T) { + self.worldBuffer.eventBuffer.eventWriter(eventOfType: T.self)?.send(value: value) + } +} diff --git a/Sources/ECS/UpdateSystem/Resources.swift b/Sources/ECS/UpdateSystem/UpdateSystemResources.swift similarity index 100% rename from Sources/ECS/UpdateSystem/Resources.swift rename to Sources/ECS/UpdateSystem/UpdateSystemResources.swift diff --git a/Sources/ECS/World/WorldResources.swift b/Sources/ECS/World/WorldResources.swift new file mode 100644 index 0000000..c40cd5c --- /dev/null +++ b/Sources/ECS/World/WorldResources.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/08/20. +// + +import Foundation From cc6c5da9d6668514ce8f39f53c45dcbc5797554e Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:14:25 +0900 Subject: [PATCH 24/42] add: Graphic module --- Package.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Package.swift b/Package.swift index 6229763..0274d6a 100644 --- a/Package.swift +++ b/Package.swift @@ -21,6 +21,7 @@ struct Module { extension Module { static let ecs = Module(name: "ECS") static let plugIns = Module(name: "PlugIns") + static let graphic = Module(name: "ECS_Graphic", path: "Sources/PlugIns/Graphic") static let keyboard = Module(name: "ECS_Keyboard", path: "Sources/PlugIns/Keyboard") static let mouse = Module(name: "ECS_Mouse", path: "Sources/PlugIns/Mouse") static let objectLink = Module(name: "ECS_ObjectLink", path: "Sources/PlugIns/ObjectLink") @@ -28,6 +29,7 @@ extension Module { static let scroll = Module(name: "ECS_Scroll", path: "Sources/PlugIns/Scroll") static let ecs_swiftTests = Module(name: "ecs-swiftTests") + static let graphicPlugInTests = Module(name: "GraphicPlugInTests") static let keyBoardPlugInTests = Module(name: "KeyBoardPlugInTests") static let mousePlugInTests = Module(name: "MousePlugInTests") static let objectLinkPlugInTests = Module(name: "ObjectLinkPlugInTests") @@ -63,6 +65,7 @@ let package = Package( .library( name: Module.plugIns.name, targets: [ + Module.graphic.name, Module.keyboard.name, Module.mouse.name, Module.objectLink.name, @@ -80,6 +83,9 @@ let package = Package( .target( module: .ecs, dependencies: []), + .target( + module: .graphic, + dependencies: [.ecs]), .target( module: .keyboard, dependencies: [.ecs]), @@ -98,6 +104,9 @@ let package = Package( .testTarget( module: .ecs_swiftTests, dependencies: [.ecs]), + .testTarget( + module: .graphicPlugInTests, + dependencies: [.graphic]), .testTarget( module: .keyBoardPlugInTests, dependencies: [.keyboard]), From e4ac4fa54da58636dea32e4fe3613ae7a5c098e4 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:17:26 +0900 Subject: [PATCH 25/42] feat: change access modifier Buffer, Command and Commands to public --- Sources/ECS/Chunk/ChunkBuffer.swift | 6 +++--- Sources/ECS/Commands/Command.swift | 1 + Sources/ECS/Commands/CommandsBuffer.swift | 6 +++--- Sources/ECS/Resource/ResourceBuffer.swift | 6 +++--- Sources/ECS/System/SystemBuffer.swift | 8 ++++---- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Sources/ECS/Chunk/ChunkBuffer.swift b/Sources/ECS/Chunk/ChunkBuffer.swift index 84b3101..59e67dc 100644 --- a/Sources/ECS/Chunk/ChunkBuffer.swift +++ b/Sources/ECS/Chunk/ChunkBuffer.swift @@ -8,7 +8,7 @@ import Foundation /// Chunk を種類別で格納します -class ChunkBuffer { +final public class ChunkBuffer { class ChunkRegistry: BufferElement { let chunk: ChunkType init(chunk: ChunkType) { @@ -26,12 +26,12 @@ class ChunkBuffer { self.buffer = buffer } - func chunk(ofType type: ChunkType.Type) -> ChunkType? { + public func chunk(ofType type: ChunkType.Type) -> ChunkType? { self.buffer.component(ofType: ChunkRegistry.self)?.chunk } } -extension WorldBuffer { +public extension WorldBuffer { var chunkBuffer: ChunkBuffer { ChunkBuffer(buffer: self) } diff --git a/Sources/ECS/Commands/Command.swift b/Sources/ECS/Commands/Command.swift index b71115e..71702bf 100644 --- a/Sources/ECS/Commands/Command.swift +++ b/Sources/ECS/Commands/Command.swift @@ -6,6 +6,7 @@ // open class Command { + public init() {} open func runCommand(in world: World) { } diff --git a/Sources/ECS/Commands/CommandsBuffer.swift b/Sources/ECS/Commands/CommandsBuffer.swift index 9bce8e3..e999856 100644 --- a/Sources/ECS/Commands/CommandsBuffer.swift +++ b/Sources/ECS/Commands/CommandsBuffer.swift @@ -7,7 +7,7 @@ import Foundation -class CommandsBuffer { +final public class CommandsBuffer { class CommandsRegistry: BufferElement { let commands: Commands init(commands: Commands) { @@ -25,7 +25,7 @@ class CommandsBuffer { self.buffer = buffer } - func commands() -> Commands? { + public func commands() -> Commands? { self.buffer.component(ofType: CommandsRegistry.self)?.commands } @@ -35,7 +35,7 @@ class CommandsBuffer { } // WorldBuffer + Commands -extension WorldBuffer { +public extension WorldBuffer { var commandsBuffer: CommandsBuffer { CommandsBuffer(buffer: self) } diff --git a/Sources/ECS/Resource/ResourceBuffer.swift b/Sources/ECS/Resource/ResourceBuffer.swift index 779477e..c31ef2d 100644 --- a/Sources/ECS/Resource/ResourceBuffer.swift +++ b/Sources/ECS/Resource/ResourceBuffer.swift @@ -5,7 +5,7 @@ // Created by rrbox on 2023/08/12. // -class ResourceBuffer { +final public class ResourceBuffer { let buffer: Buffer init(buffer: Buffer) { self.buffer = buffer @@ -15,12 +15,12 @@ class ResourceBuffer { self.buffer.addComponent(Resource(resource)) } - func resource(ofType type: T.Type) -> Resource? { + public func resource(ofType type: T.Type) -> Resource? { self.buffer.component(ofType: Resource.self) } } -extension WorldBuffer { +public extension WorldBuffer { var resourceBuffer: ResourceBuffer { ResourceBuffer(buffer: self) } diff --git a/Sources/ECS/System/SystemBuffer.swift b/Sources/ECS/System/SystemBuffer.swift index b257c3b..bd8e48e 100644 --- a/Sources/ECS/System/SystemBuffer.swift +++ b/Sources/ECS/System/SystemBuffer.swift @@ -6,10 +6,10 @@ // open class SystemExecute { - + public init() {} } -class SystemBuffer { +final public class SystemBuffer { final class SystemRegisotry: BufferElement { var systems = [Execute]() } @@ -19,7 +19,7 @@ class SystemBuffer { self.buffer = buffer } - func systems(ofType: System.Type) -> [System] { + public func systems(ofType: System.Type) -> [System] { self.buffer.component(ofType: SystemRegisotry.self)!.systems } @@ -35,7 +35,7 @@ class SystemBuffer { } } -extension WorldBuffer { +public extension WorldBuffer { var systemBuffer: SystemBuffer { SystemBuffer(buffer: self) } From 9c2034e937914ae9a878de00a9b89b7ff59b2041 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:19:36 +0900 Subject: [PATCH 26/42] add: EntityCommands --- .../EntityCommands/Commands/AddComponentCommand.swift | 5 ++--- Sources/ECS/EntityCommands/Commands/DespawnCommand.swift | 8 +------- .../EntityCommands/Commands/RemoveComponentCommand.swift | 6 ++---- Sources/ECS/EntityCommands/Commands/SpawnCommand.swift | 7 +++---- .../EntityCommands/EntityCommands/EntityCommand.swift | 9 +++++++-- .../EntityCommands/EntityCommands/EntityCommands.swift | 2 +- 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift b/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift index 4b33102..a51c701 100644 --- a/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/AddComponentCommand.swift @@ -5,13 +5,12 @@ // Created by rrbox on 2023/08/10. // -class AddComponent: Command { - let entity: Entity +class AddComponent: EntityCommand { let componnet: ComponentType init(entity: Entity, componnet: ComponentType) { - self.entity = entity self.componnet = componnet + super.init(entity: entity) } override func runCommand(in world: World) { diff --git a/Sources/ECS/EntityCommands/Commands/DespawnCommand.swift b/Sources/ECS/EntityCommands/Commands/DespawnCommand.swift index d994854..e986818 100644 --- a/Sources/ECS/EntityCommands/Commands/DespawnCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/DespawnCommand.swift @@ -5,13 +5,7 @@ // Created by rrbox on 2023/08/10. // -class DespawnCommand: Command { - let entity: Entity - - init(entity: Entity) { - self.entity = entity - } - +class DespawnCommand: EntityCommand { override func runCommand(in world: World) { world.despawn(entity: self.entity) } diff --git a/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift b/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift index 5db0a66..7bd9427 100644 --- a/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/RemoveComponentCommand.swift @@ -5,11 +5,9 @@ // Created by rrbox on 2023/08/10. // -class RemoveComponent: Command { - let entity: Entity - +class RemoveComponent: EntityCommand { init(entity: Entity, componentType type: ComponentType.Type) { - self.entity = entity + super.init(entity: entity) } override func runCommand(in world: World) { diff --git a/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift b/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift index 143eec2..87e72a6 100644 --- a/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift +++ b/Sources/ECS/EntityCommands/Commands/SpawnCommand.swift @@ -5,17 +5,16 @@ // Created by rrbox on 2023/08/10. // -class SpawnCommand: Command { - let id: Entity +class SpawnCommand: EntityCommand { let entityRecord: EntityRecord init(id: Entity, entityRecord: EntityRecord) { - self.id = id self.entityRecord = entityRecord + super.init(entity: id) } override func runCommand(in world: World) { - world.push(entity: self.id, entityRecord: self.entityRecord) + world.push(entity: self.entity, entityRecord: self.entityRecord) } } diff --git a/Sources/ECS/EntityCommands/EntityCommands/EntityCommand.swift b/Sources/ECS/EntityCommands/EntityCommands/EntityCommand.swift index 380511a..ba4d307 100644 --- a/Sources/ECS/EntityCommands/EntityCommands/EntityCommand.swift +++ b/Sources/ECS/EntityCommands/EntityCommands/EntityCommand.swift @@ -1,8 +1,13 @@ // -// File.swift +// EntityCommand.swift // // // Created by rrbox on 2023/08/18. // -import Foundation +open class EntityCommand: Command { + public let entity: Entity + public init(entity: Entity) { + self.entity = entity + } +} diff --git a/Sources/ECS/EntityCommands/EntityCommands/EntityCommands.swift b/Sources/ECS/EntityCommands/EntityCommands/EntityCommands.swift index a9e9ad9..614fb87 100644 --- a/Sources/ECS/EntityCommands/EntityCommands/EntityCommands.swift +++ b/Sources/ECS/EntityCommands/EntityCommands/EntityCommands.swift @@ -14,7 +14,7 @@ final public class EntityCommands { self.commands = commands } - public func pushCommand(_ command: Command) { + public func pushCommand(_ command: EntityCommand) { self.commands.commandQueue.append(command) } From 3f57254b326a4b43400cd7761ab9d1a47dbcd2e1 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:21:33 +0900 Subject: [PATCH 27/42] add: Event system --- .../CommandsEvent/CommandsEvent+Buffer.swift | 33 ++++++++++++- .../Event/CommandsEvent/CommandsEvent.swift | 7 ++- .../CommandsEvent/CommandsEventQueue.swift | 7 ++- .../CommandsEvent/CommandsEventWriter.swift | 23 ++++++++- Sources/ECS/Event/EventStreaming/Event.swift | 25 +++++++++- .../Event/EventStreaming/EventBuffer.swift | 47 ++++++++++++++++++- .../ECS/Event/EventStreaming/EventQueue.swift | 7 ++- .../Event/EventStreaming/EventWriter.swift | 23 ++++++++- .../ECS/Event/EventSystem/EventSystem.swift | 26 +++++++++- .../ECS/Event/EventSystem/EventSystem2.swift | 28 ++++++++++- .../ECS/Event/EventSystem/EventSystem3.swift | 28 ++++++++++- .../ECS/Event/EventSystem/EventSystem4.swift | 29 +++++++++++- .../ECS/Event/EventSystem/EventSystem5.swift | 30 +++++++++++- .../EventSystem/EventSystemExecute.swift | 8 +++- Sources/ECS/Event/World+EventStreamer.swift | 19 ++++++++ 15 files changed, 314 insertions(+), 26 deletions(-) diff --git a/Sources/ECS/Event/CommandsEvent/CommandsEvent+Buffer.swift b/Sources/ECS/Event/CommandsEvent/CommandsEvent+Buffer.swift index 100ab2e..7133e26 100644 --- a/Sources/ECS/Event/CommandsEvent/CommandsEvent+Buffer.swift +++ b/Sources/ECS/Event/CommandsEvent/CommandsEvent+Buffer.swift @@ -1,8 +1,39 @@ // -// File.swift +// CommandsEvent+Buffer.swift // // // Created by rrbox on 2023/08/29. // import Foundation + +class CommadsEventWriterRegistry: BufferElement { + let writer: CommandsEventWriter + init(writer: CommandsEventWriter) { + self.writer = writer + super.init() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension EventBuffer { + func setUpCommandsEventQueue(eventOfType: T.Type) { + self.buffer.addComponent(CommandsEventQueue()) + } + + func commandsEventQueue(eventOfType: T.Type) -> CommandsEventQueue? { + self.buffer.component(ofType: CommandsEventQueue.self) + } + + func commandsEventWriter(eventOfType type: T.Type) -> CommandsEventWriter? { + self.buffer.component(ofType: CommadsEventWriterRegistry.self)?.writer + } + + func registerCommandsEventWriter(eventType: T.Type) { + let eventQueue = self.buffer.component(ofType: CommandsEventQueue.self)! + self.buffer.addComponent(CommadsEventWriterRegistry(writer: CommandsEventWriter(eventQueue: eventQueue))) + } +} diff --git a/Sources/ECS/Event/CommandsEvent/CommandsEvent.swift b/Sources/ECS/Event/CommandsEvent/CommandsEvent.swift index 100ab2e..7be2376 100644 --- a/Sources/ECS/Event/CommandsEvent/CommandsEvent.swift +++ b/Sources/ECS/Event/CommandsEvent/CommandsEvent.swift @@ -1,8 +1,11 @@ // -// File.swift +// CommandsEvent.swift // // // Created by rrbox on 2023/08/29. // -import Foundation +/// Commands 実行中に発信されるイベントです. +protocol CommandsEventProtocol { + +} diff --git a/Sources/ECS/Event/CommandsEvent/CommandsEventQueue.swift b/Sources/ECS/Event/CommandsEvent/CommandsEventQueue.swift index 100ab2e..978e325 100644 --- a/Sources/ECS/Event/CommandsEvent/CommandsEventQueue.swift +++ b/Sources/ECS/Event/CommandsEvent/CommandsEventQueue.swift @@ -1,8 +1,11 @@ // -// File.swift +// CommandsEventQueue.swift // // // Created by rrbox on 2023/08/29. // -import Foundation +class CommandsEventQueue: BufferElement { + var eventQueue = [T]() + var sendingEvents = [T]() +} diff --git a/Sources/ECS/Event/CommandsEvent/CommandsEventWriter.swift b/Sources/ECS/Event/CommandsEvent/CommandsEventWriter.swift index 100ab2e..349ad96 100644 --- a/Sources/ECS/Event/CommandsEvent/CommandsEventWriter.swift +++ b/Sources/ECS/Event/CommandsEvent/CommandsEventWriter.swift @@ -1,8 +1,27 @@ // -// File.swift +// CommandsEventWriter.swift // // // Created by rrbox on 2023/08/29. // -import Foundation +final class CommandsEventWriter: SystemParameter, SetUpSystemParameter { + unowned let eventQueue: CommandsEventQueue + + init(eventQueue: CommandsEventQueue) { + self.eventQueue = eventQueue + } + + public func send(value: T) { + self.eventQueue.eventQueue.append(value) + } + + public static func register(to worldBuffer: WorldBuffer) { + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> CommandsEventWriter? { + worldBuffer.eventBuffer.commandsEventWriter(eventOfType: T.self) + } +} + diff --git a/Sources/ECS/Event/EventStreaming/Event.swift b/Sources/ECS/Event/EventStreaming/Event.swift index e46c664..edc203f 100644 --- a/Sources/ECS/Event/EventStreaming/Event.swift +++ b/Sources/ECS/Event/EventStreaming/Event.swift @@ -1,8 +1,29 @@ // -// File.swift +// Event.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +public protocol EventProtocol { + +} + +class AnyEvent { + func runEventReceiver(worldBuffer: WorldBuffer) { + + } +} + +final class Event: AnyEvent { + let value: T + init(value: T) { + self.value = value + } + + override func runEventReceiver(worldBuffer: WorldBuffer) { + for system in worldBuffer.systemBuffer.systems(ofType: EventSystemExecute.self) { + system.receive(event: EventReader(value: self.value), worldBuffer: worldBuffer) + } + } +} diff --git a/Sources/ECS/Event/EventStreaming/EventBuffer.swift b/Sources/ECS/Event/EventStreaming/EventBuffer.swift index e46c664..aca1bf2 100644 --- a/Sources/ECS/Event/EventStreaming/EventBuffer.swift +++ b/Sources/ECS/Event/EventStreaming/EventBuffer.swift @@ -1,8 +1,53 @@ // -// File.swift +// EventBuffer.swift // // // Created by rrbox on 2023/08/14. // import Foundation + +// world buffer にプロパティをつけておく +class EventBuffer { + class EventWriterRegistry: BufferElement { + let writer: EventWriter + init(writer: EventWriter) { + self.writer = writer + super.init() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + } + + let buffer: Buffer + init(buffer: Buffer) { + self.buffer = buffer + } + + func setUpEventQueue() { + self.buffer.addComponent(EventQueue()) + } + + func eventQueue() -> EventQueue? { + self.buffer.component(ofType: EventQueue.self) + } + + func eventWriter(eventOfType type: T.Type) -> EventWriter? { + self.buffer.component(ofType: EventWriterRegistry.self)?.writer + } + + func registerEventWriter(eventType: T.Type) { + let eventQueue = self.buffer.component(ofType: EventQueue.self)! + self.buffer.addComponent(EventWriterRegistry(writer: EventWriter(eventQueue: eventQueue))) + } + +} + +extension WorldBuffer { + var eventBuffer: EventBuffer { + EventBuffer(buffer: self) + } +} + diff --git a/Sources/ECS/Event/EventStreaming/EventQueue.swift b/Sources/ECS/Event/EventStreaming/EventQueue.swift index e46c664..f807487 100644 --- a/Sources/ECS/Event/EventStreaming/EventQueue.swift +++ b/Sources/ECS/Event/EventStreaming/EventQueue.swift @@ -1,8 +1,11 @@ // -// File.swift +// EventQueue.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +class EventQueue: BufferElement { + var eventQueue = [AnyEvent]() + var sendingEvents = [AnyEvent]() +} diff --git a/Sources/ECS/Event/EventStreaming/EventWriter.swift b/Sources/ECS/Event/EventStreaming/EventWriter.swift index e46c664..1924189 100644 --- a/Sources/ECS/Event/EventStreaming/EventWriter.swift +++ b/Sources/ECS/Event/EventStreaming/EventWriter.swift @@ -1,8 +1,27 @@ // -// File.swift +// EventWriter.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +// Commands と基本的な仕組みは同じ. +final public class EventWriter: SystemParameter, SetUpSystemParameter { + unowned let eventQueue: EventQueue + + init(eventQueue: EventQueue) { + self.eventQueue = eventQueue + } + + public func send(value: T) { + self.eventQueue.eventQueue.append(Event(value: value)) + } + + public static func register(to worldBuffer: WorldBuffer) { + + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> EventWriter? { + worldBuffer.eventBuffer.eventWriter(eventOfType: T.self) + } +} diff --git a/Sources/ECS/Event/EventSystem/EventSystem.swift b/Sources/ECS/Event/EventSystem/EventSystem.swift index e46c664..8dbc61e 100644 --- a/Sources/ECS/Event/EventSystem/EventSystem.swift +++ b/Sources/ECS/Event/EventSystem/EventSystem.swift @@ -1,8 +1,30 @@ // -// File.swift +// EventSystem.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +final public class EventSystem: EventSystemExecute { + let execute: (EventReader, Parameter) -> () + + public init(execute: @escaping (EventReader, Parameter) -> ()) { + self.execute = execute + } + + override func receive(event: EventReader, worldBuffer: WorldBuffer) { + self.execute(event, Parameter.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addEventSystem(_ system: EventSystem) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: EventSystemExecute.self) + Parameter.register(to: self.worldBuffer) + return self + } + + @discardableResult func addEventSystem(_ execute: @escaping (EventReader, Parameter) -> ()) -> World { + self.addEventSystem(EventSystem(execute: execute)) + } +} diff --git a/Sources/ECS/Event/EventSystem/EventSystem2.swift b/Sources/ECS/Event/EventSystem/EventSystem2.swift index e46c664..aaa09b2 100644 --- a/Sources/ECS/Event/EventSystem/EventSystem2.swift +++ b/Sources/ECS/Event/EventSystem/EventSystem2.swift @@ -1,8 +1,32 @@ // -// File.swift +// EventSystem2.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +final public class EventSystem2: EventSystemExecute { + let execute: (EventReader, P0, P1) -> () + + public init(execute: @escaping (EventReader, P0, P1) -> ()) { + self.execute = execute + } + + override func receive(event: EventReader, worldBuffer: WorldBuffer) { + self.execute(event, P0.getParameter(from: worldBuffer)!, P1.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addEventSystem(_ system: EventSystem2) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: EventSystemExecute.self) + P0.register(to: self.worldBuffer) + P1.register(to: self.worldBuffer) + return self + } + + @discardableResult func addEventSystem(_ execute: @escaping (EventReader, P0, P1) -> ()) -> World { + self.addEventSystem(EventSystem2(execute: execute)) + } +} + diff --git a/Sources/ECS/Event/EventSystem/EventSystem3.swift b/Sources/ECS/Event/EventSystem/EventSystem3.swift index e46c664..06dd8f6 100644 --- a/Sources/ECS/Event/EventSystem/EventSystem3.swift +++ b/Sources/ECS/Event/EventSystem/EventSystem3.swift @@ -1,8 +1,32 @@ // -// File.swift +// EventSystem3.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +final public class EventSystem3: EventSystemExecute { + let execute: (EventReader, P0, P1, P2) -> () + + public init(execute: @escaping (EventReader, P0, P1, P2) -> ()) { + self.execute = execute + } + + override func receive(event: EventReader, worldBuffer: WorldBuffer) { + self.execute(event, P0.getParameter(from: worldBuffer)!, P1.getParameter(from: worldBuffer)!, P2.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addEventSystem(_ system: EventSystem3) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: EventSystemExecute.self) + P0.register(to: self.worldBuffer) + P1.register(to: self.worldBuffer) + P2.register(to: self.worldBuffer) + return self + } + + @discardableResult func addEventSystem(_ execute: @escaping (EventReader, P0, P1, P2) -> ()) -> World { + self.addEventSystem(EventSystem3(execute: execute)) + } +} diff --git a/Sources/ECS/Event/EventSystem/EventSystem4.swift b/Sources/ECS/Event/EventSystem/EventSystem4.swift index e46c664..73d5d6b 100644 --- a/Sources/ECS/Event/EventSystem/EventSystem4.swift +++ b/Sources/ECS/Event/EventSystem/EventSystem4.swift @@ -1,8 +1,33 @@ // -// File.swift +// EventSystem4.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +final public class EventSystem4: EventSystemExecute { + let execute: (EventReader, P0, P1, P2, P3) -> () + + public init(execute: @escaping (EventReader, P0, P1, P2, P3) -> ()) { + self.execute = execute + } + + override func receive(event: EventReader, worldBuffer: WorldBuffer) { + self.execute(event, P0.getParameter(from: worldBuffer)!, P1.getParameter(from: worldBuffer)!, P2.getParameter(from: worldBuffer)!, P3.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addEventSystem(_ system: EventSystem4) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: EventSystemExecute.self) + P0.register(to: self.worldBuffer) + P1.register(to: self.worldBuffer) + P2.register(to: self.worldBuffer) + P3.register(to: self.worldBuffer) + return self + } + + @discardableResult func addEventSystem(_ execute: @escaping (EventReader, P0, P1, P2, P3) -> ()) -> World { + self.addEventSystem(EventSystem4(execute: execute)) + } +} diff --git a/Sources/ECS/Event/EventSystem/EventSystem5.swift b/Sources/ECS/Event/EventSystem/EventSystem5.swift index e46c664..5d892f8 100644 --- a/Sources/ECS/Event/EventSystem/EventSystem5.swift +++ b/Sources/ECS/Event/EventSystem/EventSystem5.swift @@ -1,8 +1,34 @@ // -// File.swift +// EventSystem5.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +final public class EventSystem5: EventSystemExecute { + let execute: (EventReader, P0, P1, P2, P3, P4) -> () + + public init(execute: @escaping (EventReader, P0, P1, P2, P3, P4) -> ()) { + self.execute = execute + } + + override func receive(event: EventReader, worldBuffer: WorldBuffer) { + self.execute(event, P0.getParameter(from: worldBuffer)!, P1.getParameter(from: worldBuffer)!, P2.getParameter(from: worldBuffer)!, P3.getParameter(from: worldBuffer)!, P4.getParameter(from: worldBuffer)!) + } +} + +public extension World { + @discardableResult func addEventSystem(_ system: EventSystem5) -> World { + self.worldBuffer.systemBuffer.addSystem(system, as: EventSystemExecute.self) + P0.register(to: self.worldBuffer) + P1.register(to: self.worldBuffer) + P2.register(to: self.worldBuffer) + P3.register(to: self.worldBuffer) + P4.register(to: self.worldBuffer) + return self + } + + @discardableResult func addEventSystem(_ execute: @escaping (EventReader, P0, P1, P2, P3, P4) -> ()) -> World { + self.addEventSystem(EventSystem5(execute: execute)) + } +} diff --git a/Sources/ECS/Event/EventSystem/EventSystemExecute.swift b/Sources/ECS/Event/EventSystem/EventSystemExecute.swift index e46c664..af387c9 100644 --- a/Sources/ECS/Event/EventSystem/EventSystemExecute.swift +++ b/Sources/ECS/Event/EventSystem/EventSystemExecute.swift @@ -1,8 +1,12 @@ // -// File.swift +// EventSystemExecute.swift // // // Created by rrbox on 2023/08/14. // -import Foundation +public class EventSystemExecute: SystemExecute { + func receive(event: EventReader, worldBuffer: WorldBuffer) { + + } +} diff --git a/Sources/ECS/Event/World+EventStreamer.swift b/Sources/ECS/Event/World+EventStreamer.swift index d078d31..f49ff0e 100644 --- a/Sources/ECS/Event/World+EventStreamer.swift +++ b/Sources/ECS/Event/World+EventStreamer.swift @@ -16,6 +16,13 @@ public extension World { } } +extension World { + func addCommandsEventStreamer(eventType: T.Type) { + self.worldBuffer.systemBuffer.registerSystemRegistry(ofType: EventSystemExecute.self) + self.worldBuffer.eventBuffer.registerCommandsEventWriter(eventType: T.self) + } +} + extension World { func applyEventQueue() { let eventQueue = self.worldBuffer.eventBuffer.eventQueue()! @@ -26,6 +33,18 @@ extension World { } eventQueue.sendingEvents = [] } + + func applyCommandsEventQueue(eventOfType: T.Type) { + let eventQueue = self.worldBuffer.eventBuffer.commandsEventQueue(eventOfType: T.self)! + eventQueue.sendingEvents = eventQueue.eventQueue + eventQueue.eventQueue = [] + for event in eventQueue.sendingEvents { + for system in self.worldBuffer.systemBuffer.systems(ofType: EventSystemExecute.self) { + system.receive(event: EventReader(value: event), worldBuffer: self.worldBuffer) + } + } + eventQueue.sendingEvents = [] + } } public extension World { From 025a721de3f3d0c96dfbabdcf5238ff2fb19ccea Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:22:16 +0900 Subject: [PATCH 28/42] add: methods of queries for single entity --- Sources/ECS/Query/Query.swift | 9 +++++++++ Sources/ECS/Query/Query2.swift | 11 +++++++++++ Sources/ECS/Query/Query3.swift | 10 ++++++++++ Sources/ECS/Query/Query4.swift | 10 ++++++++++ Sources/ECS/Query/Query5.swift | 10 ++++++++++ 5 files changed, 50 insertions(+) diff --git a/Sources/ECS/Query/Query.swift b/Sources/ECS/Query/Query.swift index 5ab71e4..e017002 100644 --- a/Sources/ECS/Query/Query.swift +++ b/Sources/ECS/Query/Query.swift @@ -32,6 +32,15 @@ final public class Query: Chunk, SystemParameter { } } + public func update(_ entity: Entity, _ execute: (inout ComponentType) -> ()) { + guard let componentRef = self.components[entity] else { return } + execute(&componentRef.value) + } + + public func component(forEntity entity: Entity) -> ComponentType? { + self.components[entity]?.value + } + public static func register(to worldBuffer: WorldBuffer) { guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { return diff --git a/Sources/ECS/Query/Query2.swift b/Sources/ECS/Query/Query2.swift index 5d23edf..74160b2 100644 --- a/Sources/ECS/Query/Query2.swift +++ b/Sources/ECS/Query/Query2.swift @@ -35,6 +35,17 @@ final public class Query2: Chunk, SystemParameter } } + public func update(_ entity: Entity, _ execute: (inout C0, inout C1) -> ()) { + guard let group = self.components[entity] else { return } + execute(&group.0.value, &group.1.value) + } + + public func components(forEntity entity: Entity) -> (C0, C1)? { + guard let references = components[entity] else { return nil } + return (references.0.value, references.1.value) + } + + public static func register(to worldBuffer: WorldBuffer) { guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { return diff --git a/Sources/ECS/Query/Query3.swift b/Sources/ECS/Query/Query3.swift index be734e6..cdfce62 100644 --- a/Sources/ECS/Query/Query3.swift +++ b/Sources/ECS/Query/Query3.swift @@ -36,6 +36,16 @@ final public class Query3: Chunk, S } } + public func update(_ entity: Entity, _ execute: (inout C0, inout C1, inout C2) -> ()) { + guard let group = self.components[entity] else { return } + execute(&group.0.value, &group.1.value, &group.2.value) + } + + public func components(forEntity entity: Entity) -> (C0, C1, C2)? { + guard let references = components[entity] else { return nil } + return (references.0.value, references.1.value, references.2.value) + } + public static func register(to worldBuffer: WorldBuffer) { guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { return diff --git a/Sources/ECS/Query/Query4.swift b/Sources/ECS/Query/Query4.swift index 7592dfd..b9a46c5 100644 --- a/Sources/ECS/Query/Query4.swift +++ b/Sources/ECS/Query/Query4.swift @@ -38,6 +38,16 @@ final public class Query4 ()) { + guard let group = self.components[entity] else { return } + execute(&group.0.value, &group.1.value, &group.2.value, &group.3.value) + } + + public func components(forEntity entity: Entity) -> (C0, C1, C2, C3)? { + guard let references = components[entity] else { return nil } + return (references.0.value, references.1.value, references.2.value, references.3.value) + } + public static func register(to worldBuffer: WorldBuffer) { guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { return diff --git a/Sources/ECS/Query/Query5.swift b/Sources/ECS/Query/Query5.swift index 541e7eb..71870f1 100644 --- a/Sources/ECS/Query/Query5.swift +++ b/Sources/ECS/Query/Query5.swift @@ -40,6 +40,16 @@ final public class Query5 ()) { + guard let group = self.components[entity] else { return } + execute(&group.0.value, &group.1.value, &group.2.value, &group.3.value, &group.4.value) + } + + public func components(forEntity entity: Entity) -> (C0, C1, C2, C3, C4)? { + guard let references = components[entity] else { return nil } + return (references.0.value, references.1.value, references.2.value, references.3.value, references.4.value) + } + public static func register(to worldBuffer: WorldBuffer) { guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { return From f35f7812fec477918c1f46cb4de70b5f138215a7 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:23:26 +0900 Subject: [PATCH 29/42] chore: add `@discardableResult` attribute to `addResource` method of Commands --- Sources/ECS/Resource/Commands+Resource.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/ECS/Resource/Commands+Resource.swift b/Sources/ECS/Resource/Commands+Resource.swift index a6bddc8..b3d9296 100644 --- a/Sources/ECS/Resource/Commands+Resource.swift +++ b/Sources/ECS/Resource/Commands+Resource.swift @@ -21,7 +21,8 @@ public extension Commands { /// world に対して resource を追加します. /// /// resource はフレームの終了直前に追加されます. - func addResource(_ resource: T) { + @discardableResult func addResource(_ resource: T) -> Commands { self.push(command: AddResource(resrouce: resource)) + return self } } From 9648aa0c01d60d89c7ceadc551ccc08981156a72 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:25:14 +0900 Subject: [PATCH 30/42] change: omit external parameter name of parameter name of initializer of update systems --- Sources/ECS/UpdateSystem/UpdateSystem.swift | 4 ++-- Sources/ECS/UpdateSystem/UpdateSystem2.swift | 4 ++-- Sources/ECS/UpdateSystem/UpdateSystem3.swift | 4 ++-- Sources/ECS/UpdateSystem/UpdateSystem4.swift | 4 ++-- Sources/ECS/UpdateSystem/UpdateSystem5.swift | 4 ++-- Sources/ECS/UpdateSystem/UpdateSystemResources.swift | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/ECS/UpdateSystem/UpdateSystem.swift b/Sources/ECS/UpdateSystem/UpdateSystem.swift index 1ddcf18..c720e65 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem.swift @@ -12,7 +12,7 @@ public protocol UpdateSystemProtocol: SystemProtocol, UpdateExecute { final public class UpdateSystem: UpdateExecute, UpdateSystemProtocol { let execute: (Parameter) -> () - init(execute: @escaping (Parameter) -> Void) { + public init(_ execute: @escaping (Parameter) -> Void) { self.execute = execute } @@ -29,6 +29,6 @@ public extension World { } @discardableResult func addUpdateSystem(_ execute: @escaping (Parameter) -> ()) -> World { - self.addUpdateSystem(UpdateSystem(execute: execute)) + self.addUpdateSystem(UpdateSystem(execute)) } } diff --git a/Sources/ECS/UpdateSystem/UpdateSystem2.swift b/Sources/ECS/UpdateSystem/UpdateSystem2.swift index 008f189..a89a5ce 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem2.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem2.swift @@ -12,7 +12,7 @@ public protocol UpdateSystemProtocol2: SystemProtocol2, UpdateExecute { final public class UpdateSystem2: UpdateExecute, UpdateSystemProtocol2 { let execute: (P0, P1) -> () - init(execute: @escaping (P0, P1) -> Void) { + public init(_ execute: @escaping (P0, P1) -> Void) { self.execute = execute } @@ -30,6 +30,6 @@ public extension World { } @discardableResult func addUpdateSystem(_ execute: @escaping (P0, P1) -> ()) -> World { - self.addUpdateSystem(UpdateSystem2(execute: execute)) + self.addUpdateSystem(UpdateSystem2(execute)) } } diff --git a/Sources/ECS/UpdateSystem/UpdateSystem3.swift b/Sources/ECS/UpdateSystem/UpdateSystem3.swift index 2c4a0a8..e0fc9ae 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem3.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem3.swift @@ -12,7 +12,7 @@ public protocol UpdateSystemProtocol3: SystemProtocol3, UpdateExecute { final public class UpdateSystem3: UpdateExecute, UpdateSystemProtocol3 { let execute: (P0, P1, P2) -> () - init(execute: @escaping (P0, P1, P2) -> Void) { + public init(_ execute: @escaping (P0, P1, P2) -> Void) { self.execute = execute } @@ -31,6 +31,6 @@ public extension World { } @discardableResult func addUpdateSystem(_ execute: @escaping (P0, P1, P2) -> ()) -> World { - self.addUpdateSystem(UpdateSystem3(execute: execute)) + self.addUpdateSystem(UpdateSystem3(execute)) } } diff --git a/Sources/ECS/UpdateSystem/UpdateSystem4.swift b/Sources/ECS/UpdateSystem/UpdateSystem4.swift index 6626028..2af6729 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem4.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem4.swift @@ -12,7 +12,7 @@ public protocol UpdateSystemProtocol4: SystemProtocol4, UpdateExecute { final public class UpdateSystem4: UpdateExecute, UpdateSystemProtocol4 { let execute: (P0, P1, P2, P3) -> () - init(execute: @escaping (P0, P1, P2, P3) -> Void) { + public init(_ execute: @escaping (P0, P1, P2, P3) -> Void) { self.execute = execute } @@ -32,6 +32,6 @@ public extension World { } @discardableResult func addUpdateSystem(_ execute: @escaping (P0, P1, P2, P3) -> ()) -> World { - self.addUpdateSystem(UpdateSystem4(execute: execute)) + self.addUpdateSystem(UpdateSystem4(execute)) } } diff --git a/Sources/ECS/UpdateSystem/UpdateSystem5.swift b/Sources/ECS/UpdateSystem/UpdateSystem5.swift index 5819c79..d683e71 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystem5.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystem5.swift @@ -12,7 +12,7 @@ public protocol UpdateSystemProtocol5: SystemProtocol5, UpdateExecute { final public class UpdateSystem5: UpdateExecute, UpdateSystemProtocol5 { let execute: (P0, P1, P2, P3, P4) -> () - init(execute: @escaping (P0, P1, P2, P3, P4) -> Void) { + public init(_ execute: @escaping (P0, P1, P2, P3, P4) -> Void) { self.execute = execute } @@ -33,7 +33,7 @@ public extension World { } @discardableResult func addUpdateSystem(_ execute: @escaping (P0, P1, P2, P3, P4) -> ()) -> World { - self.addUpdateSystem(UpdateSystem5(execute: execute)) + self.addUpdateSystem(UpdateSystem5(execute)) } } diff --git a/Sources/ECS/UpdateSystem/UpdateSystemResources.swift b/Sources/ECS/UpdateSystem/UpdateSystemResources.swift index 18ee54e..2a80f1b 100644 --- a/Sources/ECS/UpdateSystem/UpdateSystemResources.swift +++ b/Sources/ECS/UpdateSystem/UpdateSystemResources.swift @@ -1,5 +1,5 @@ // -// Resources.swift +// UpdateSystemResources.swift // // // Created by rrbox on 2023/08/12. From 30d0a5fce49e761278fb55aa42c18e45a25792df Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:37:48 +0900 Subject: [PATCH 31/42] add: Entity count resource --- Sources/ECS/World/World+Entities.swift | 17 +++++++++++++++-- Sources/ECS/World/World.swift | 14 ++------------ Sources/ECS/World/WorldResources.swift | 6 ++++-- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Sources/ECS/World/World+Entities.swift b/Sources/ECS/World/World+Entities.swift index 380511a..3d717a8 100644 --- a/Sources/ECS/World/World+Entities.swift +++ b/Sources/ECS/World/World+Entities.swift @@ -1,8 +1,21 @@ // -// File.swift +// World+Entities.swift // // // Created by rrbox on 2023/08/18. // -import Foundation +public extension World { + func insert(entity: Entity, entityRecord: EntityRecord) { + self.entities.sequence[entity] = entityRecord + } + + func remove(entity: Entity) { + self.entities.sequence.removeValue(forKey: entity) + } + + func entityRecord(forEntity entity: Entity) -> EntityRecord? { + self.entities.sequence[entity] + } + +} diff --git a/Sources/ECS/World/World.swift b/Sources/ECS/World/World.swift index 0e8b81d..7ed0761 100644 --- a/Sources/ECS/World/World.swift +++ b/Sources/ECS/World/World.swift @@ -7,18 +7,6 @@ public struct Entities { var sequence: [Entity: EntityRecord] - - public mutating func insert(entity: Entity, entityRecord: EntityRecord) { - self.sequence[entity] = entityRecord - } - - public mutating func remove(entity: Entity) { - self.sequence.removeValue(forKey: entity) - } - - public mutating func entityRecord(forEntity entity: Entity) -> EntityRecord? { - self.sequence[entity] - } } final public class World { @@ -31,3 +19,5 @@ final public class World { } } + + diff --git a/Sources/ECS/World/WorldResources.swift b/Sources/ECS/World/WorldResources.swift index c40cd5c..68e6b02 100644 --- a/Sources/ECS/World/WorldResources.swift +++ b/Sources/ECS/World/WorldResources.swift @@ -1,8 +1,10 @@ // -// File.swift +// WorldResources.swift // // // Created by rrbox on 2023/08/20. // -import Foundation +struct EntityCount: ResourceProtocol { + var count: Int +} From e41179de13955e25efff8427c1c2369e9c8a72c4 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:39:15 +0900 Subject: [PATCH 32/42] add: DidSpawnEvent, WillDespawnEvent --- Sources/ECS/WorldMethods/World+Spawn.swift | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Sources/ECS/WorldMethods/World+Spawn.swift b/Sources/ECS/WorldMethods/World+Spawn.swift index 9ba0f2b..f30af39 100644 --- a/Sources/ECS/WorldMethods/World+Spawn.swift +++ b/Sources/ECS/WorldMethods/World+Spawn.swift @@ -5,25 +5,43 @@ // Created by rrbox on 2023/08/10. // +public struct DidSpawnEvent: CommandsEventProtocol { + public let spawnedEntity: Entity +} + +public struct WillDespawnEvent: CommandsEventProtocol { + public let despawnedEntity: Entity +} + extension World { /// Entity を登録します. /// /// ``Commands/spawn()`` が実行された後, フレームが終了するタイミングでこの関数が実行されます. /// entity へのコンポーネントの登録などは, push の後に行われます. func push(entity: Entity, entityRecord: EntityRecord) { - self.entities.insert(entity: entity, entityRecord: entityRecord) + self.insert(entity: entity, entityRecord: entityRecord) self.worldBuffer .chunkBuffer .push(entity: entity, entityRecord: entityRecord) + + self.worldBuffer + .eventBuffer + .commandsEventWriter(eventOfType: DidSpawnEvent.self)! + .send(value: DidSpawnEvent(spawnedEntity: entity)) } /// Entity を削除します. /// /// ``Commands/despawn()`` が実行された後, フレームが終了するタイミングでこの関数が実行されます. func despawn(entity: Entity) { - self.entities.remove(entity: entity) + self.remove(entity: entity) self.worldBuffer .chunkBuffer .despawn(entity: entity) + + self.worldBuffer + .eventBuffer + .commandsEventWriter(eventOfType: WillDespawnEvent.self)! + .send(value: WillDespawnEvent(despawnedEntity: entity)) } } From c0f7c7a89b6ab48ad5845a266680922ad8a95601 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:39:52 +0900 Subject: [PATCH 33/42] add: add plugin method of world --- Sources/ECS/WorldMethods/World+PlugIn.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Sources/ECS/WorldMethods/World+PlugIn.swift b/Sources/ECS/WorldMethods/World+PlugIn.swift index 32ccd7f..bdd2e1e 100644 --- a/Sources/ECS/WorldMethods/World+PlugIn.swift +++ b/Sources/ECS/WorldMethods/World+PlugIn.swift @@ -1,8 +1,13 @@ // -// File.swift +// World+PlugIn.swift // // // Created by rrbox on 2023/08/19. // -import Foundation +public extension World { + @discardableResult func addPlugIn(_ execute: (World) -> ()) -> World { + execute(self) + return self + } +} From 92cf0c461f17085f332cd2bc5d84e10f353e127a Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:48:28 +0900 Subject: [PATCH 34/42] =?UTF-8?q?change:=20entity=20count=20resource=20?= =?UTF-8?q?=E3=81=AE=E8=BF=BD=E5=8A=A0,=20spawn/despawn=20event=20?= =?UTF-8?q?=E3=81=AE=E8=A8=AD=E5=AE=9A=E3=82=92=E3=83=97=E3=83=AD=E3=82=BB?= =?UTF-8?q?=E3=82=B9=E3=81=AB=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/ECS/WorldMethods/World+Init.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Sources/ECS/WorldMethods/World+Init.swift b/Sources/ECS/WorldMethods/World+Init.swift index f736756..3fe6fa3 100644 --- a/Sources/ECS/WorldMethods/World+Init.swift +++ b/Sources/ECS/WorldMethods/World+Init.swift @@ -16,12 +16,24 @@ public extension World { self.worldBuffer.resourceBuffer.addResource(CurrentTime(value: 0)) self.worldBuffer.resourceBuffer.addResource(DeltaTime(value: 0)) + // resrouce buffer に world の情報関係の resource を追加します. + self.worldBuffer.resourceBuffer.addResource(EntityCount(count: 0)) + // world buffer に setup system を保持する領域を確保します. self.worldBuffer.systemBuffer.registerSystemRegistry(ofType: SetUpExecute.self) // world buffer に update system を保持する領域を確保します. self.worldBuffer.systemBuffer.registerSystemRegistry(ofType: UpdateExecute.self) + // world buffer に event queue を作成します. + self.worldBuffer.eventBuffer.setUpEventQueue() + self.worldBuffer.eventBuffer.setUpCommandsEventQueue(eventOfType: DidSpawnEvent.self) + self.worldBuffer.eventBuffer.setUpCommandsEventQueue(eventOfType: WillDespawnEvent.self) + + // world buffer に spawn/despawn event の streamer を登録します. + self.addCommandsEventStreamer(eventType: DidSpawnEvent.self) + self.addCommandsEventStreamer(eventType: WillDespawnEvent.self) + // world buffer に commands の初期値を設定します. self.worldBuffer.commandsBuffer.setCommands(Commands()) } From 85ffdf7a64416669f48d51fe2c1a4c7b1ebfaddf Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 06:58:19 +0900 Subject: [PATCH 35/42] change: frame cycle 1. `CurrentTime` rsource update 2. update shceduler execute 3. apply event queue 4. apply commands 5. will despawn event 6. apply entity queue (spawn/despawn) 7. did spawn event --- Sources/ECS/WorldMethods/World+Update.swift | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Sources/ECS/WorldMethods/World+Update.swift b/Sources/ECS/WorldMethods/World+Update.swift index 9cc7f3f..7a33de0 100644 --- a/Sources/ECS/WorldMethods/World+Update.swift +++ b/Sources/ECS/WorldMethods/World+Update.swift @@ -9,18 +9,28 @@ import Foundation public extension World { func update(currentTime: TimeInterval) { - let lastTime = self.worldBuffer.resourceBuffer.resource(ofType: CurrentTime.self)!.resource.value + let currentTimeResource = self.worldBuffer.resourceBuffer.resource(ofType: CurrentTime.self)! - self.worldBuffer.resourceBuffer.resource(ofType: DeltaTime.self)?.resource = DeltaTime(value: currentTime - lastTime) + self.worldBuffer.resourceBuffer.resource(ofType: DeltaTime.self)?.resource = DeltaTime(value: currentTime - currentTimeResource.resource.value) + + currentTimeResource.resource = CurrentTime(value: currentTime) for system in self.worldBuffer.systemBuffer.systems(ofType: UpdateExecute.self) { system.update(worldBuffer: self.worldBuffer) } + // world が受信した event を event system に発信します. + self.applyEventQueue() + self.applyCommands() + + // will despawn event を配信します. + self.applyCommandsEventQueue(eventOfType: WillDespawnEvent.self) + // apply commands の際に push された entity を chunk に割り振ります. self.worldBuffer.chunkBuffer.applyEntityQueue() - self.worldBuffer.resourceBuffer.resource(ofType: CurrentTime.self)?.resource = CurrentTime(value: currentTime) + // Did Spawn event を event system に発信します. + self.applyCommandsEventQueue(eventOfType: DidSpawnEvent.self) } } From f511dfbad8551376dd8b44b18a9492a398986760 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Thu, 14 Sep 2023 07:02:10 +0900 Subject: [PATCH 36/42] chore: get entity record method --- Sources/ECS/WorldMethods/World+EntityCommands.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ECS/WorldMethods/World+EntityCommands.swift b/Sources/ECS/WorldMethods/World+EntityCommands.swift index 5b4d0b2..b83e4ad 100644 --- a/Sources/ECS/WorldMethods/World+EntityCommands.swift +++ b/Sources/ECS/WorldMethods/World+EntityCommands.swift @@ -8,7 +8,7 @@ extension World { /// Entity に Component を追加します. func addComponent(_ component: ComponentType, forEntity entity: Entity) { - let archetype = self.entities.entityRecord(forEntity: entity)! + let archetype = self.entityRecord(forEntity: entity)! if let componentRef = archetype.component(ofType: ComponentRef.self) { componentRef.value = component } @@ -18,7 +18,7 @@ extension World { /// Entity から Component を削除します. func removeComponent(ofType type: ComponentType.Type, fromEntity entity: Entity) { - let archetype = self.entities.entityRecord(forEntity: entity)! + let archetype = self.entityRecord(forEntity: entity)! archetype.removeComponent(ofType: ComponentRef.self) self.worldBuffer.chunkBuffer.applyCurrentState(archetype, forEntity: entity) } From 63caf17563746e441ce937781c33346d61864d74 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sun, 22 Oct 2023 14:29:09 +0900 Subject: [PATCH 37/42] rename: Graphic -> Graphic2D --- ...2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist | 22 +++++++++++ .../ecs-swiftTests.xcbaseline/Info.plist | 33 ++++++++++++++++ Package.swift | 8 ++-- Sources/ECS/FilterdQuery/FIlteredQuery.swift | 8 ++++ Sources/ECS/FilterdQuery/Filter.swift | 8 ++++ Sources/ECS/FilterdQuery/QueryProtocol.swift | 8 ++++ Sources/ECS/States/StateRegistry.swift | 8 ++++ Sources/ECS/States/StateSystemBuffer.swift | 39 +++++++++++++++++++ Sources/ECS/States/World+States.swift | 8 ++++ Sources/PlugIns/Graphic2D/Camera.swift | 8 ++++ .../Commands/EntityCommands+Graphic.swift | 0 .../Commands/RemoveGraphic.swift | 0 .../Commands/SetGraphic.swift | 0 .../Graphic2D.swift} | 0 .../World+Graphic2D.swift} | 0 Sources/PlugIns/Mouse/TrackableView.swift | 8 ++++ 16 files changed, 154 insertions(+), 4 deletions(-) create mode 100644 .swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist create mode 100644 .swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/Info.plist create mode 100644 Sources/ECS/FilterdQuery/FIlteredQuery.swift create mode 100644 Sources/ECS/FilterdQuery/Filter.swift create mode 100644 Sources/ECS/FilterdQuery/QueryProtocol.swift create mode 100644 Sources/ECS/States/StateRegistry.swift create mode 100644 Sources/ECS/States/StateSystemBuffer.swift create mode 100644 Sources/ECS/States/World+States.swift create mode 100644 Sources/PlugIns/Graphic2D/Camera.swift rename Sources/PlugIns/{Graphic => Graphic2D}/Commands/EntityCommands+Graphic.swift (100%) rename Sources/PlugIns/{Graphic => Graphic2D}/Commands/RemoveGraphic.swift (100%) rename Sources/PlugIns/{Graphic => Graphic2D}/Commands/SetGraphic.swift (100%) rename Sources/PlugIns/{Graphic/Graphic.swift => Graphic2D/Graphic2D.swift} (100%) rename Sources/PlugIns/{Graphic/World+Graphic.swift => Graphic2D/World+Graphic2D.swift} (100%) create mode 100644 Sources/PlugIns/Mouse/TrackableView.swift diff --git a/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist b/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist new file mode 100644 index 0000000..616adcc --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist @@ -0,0 +1,22 @@ + + + + + classNames + + ecs_swiftTests + + testPerformance() + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 0.000023 + baselineIntegrationDisplayName + Local Baseline + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/Info.plist b/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/Info.plist new file mode 100644 index 0000000..a261598 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/Info.plist @@ -0,0 +1,33 @@ + + + + + runDestinationsByUUID + + 2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706 + + localComputer + + busSpeedInMHz + 0 + cpuCount + 1 + cpuKind + Apple M1 + cpuSpeedInMHz + 0 + logicalCPUCoresPerPackage + 8 + modelCode + MacBookPro17,1 + physicalCPUCoresPerPackage + 8 + platformIdentifier + com.apple.platform.macosx + + targetArchitecture + arm64 + + + + diff --git a/Package.swift b/Package.swift index 0274d6a..1ab7577 100644 --- a/Package.swift +++ b/Package.swift @@ -21,7 +21,7 @@ struct Module { extension Module { static let ecs = Module(name: "ECS") static let plugIns = Module(name: "PlugIns") - static let graphic = Module(name: "ECS_Graphic", path: "Sources/PlugIns/Graphic") + static let graphic2d = Module(name: "ECS_Graphic", path: "Sources/PlugIns/Graphic2D") static let keyboard = Module(name: "ECS_Keyboard", path: "Sources/PlugIns/Keyboard") static let mouse = Module(name: "ECS_Mouse", path: "Sources/PlugIns/Mouse") static let objectLink = Module(name: "ECS_ObjectLink", path: "Sources/PlugIns/ObjectLink") @@ -65,7 +65,7 @@ let package = Package( .library( name: Module.plugIns.name, targets: [ - Module.graphic.name, + Module.graphic2d.name, Module.keyboard.name, Module.mouse.name, Module.objectLink.name, @@ -84,7 +84,7 @@ let package = Package( module: .ecs, dependencies: []), .target( - module: .graphic, + module: .graphic2d, dependencies: [.ecs]), .target( module: .keyboard, @@ -106,7 +106,7 @@ let package = Package( dependencies: [.ecs]), .testTarget( module: .graphicPlugInTests, - dependencies: [.graphic]), + dependencies: [.graphic2d]), .testTarget( module: .keyBoardPlugInTests, dependencies: [.keyboard]), diff --git a/Sources/ECS/FilterdQuery/FIlteredQuery.swift b/Sources/ECS/FilterdQuery/FIlteredQuery.swift new file mode 100644 index 0000000..ae844a3 --- /dev/null +++ b/Sources/ECS/FilterdQuery/FIlteredQuery.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/09/17. +// + +import Foundation diff --git a/Sources/ECS/FilterdQuery/Filter.swift b/Sources/ECS/FilterdQuery/Filter.swift new file mode 100644 index 0000000..ae844a3 --- /dev/null +++ b/Sources/ECS/FilterdQuery/Filter.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/09/17. +// + +import Foundation diff --git a/Sources/ECS/FilterdQuery/QueryProtocol.swift b/Sources/ECS/FilterdQuery/QueryProtocol.swift new file mode 100644 index 0000000..ae844a3 --- /dev/null +++ b/Sources/ECS/FilterdQuery/QueryProtocol.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/09/17. +// + +import Foundation diff --git a/Sources/ECS/States/StateRegistry.swift b/Sources/ECS/States/StateRegistry.swift new file mode 100644 index 0000000..c482cd5 --- /dev/null +++ b/Sources/ECS/States/StateRegistry.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/10/15. +// + +import Foundation diff --git a/Sources/ECS/States/StateSystemBuffer.swift b/Sources/ECS/States/StateSystemBuffer.swift new file mode 100644 index 0000000..253a29b --- /dev/null +++ b/Sources/ECS/States/StateSystemBuffer.swift @@ -0,0 +1,39 @@ +// +// State.swift +// +// +// Created by rrbox on 2023/10/15. +// + +class StateDependentSystemBuffer { + class StateSystemRegistry: BufferElement { + var stateSystemMap: [State: [System]] = [:] + } + + let buffer: Buffer + init(buffer: Buffer) { + self.buffer = buffer + } + + public func systems( + ofType: System.Type, + forState state: State + ) -> [System] { + self.buffer.component(ofType: StateSystemRegistry.self)!.stateSystemMap[state]! + } + + public func addSystem( + _ system: System, + as: System.Type, + forState state: State + ) { + let registry = self.buffer.component(ofType: StateSystemRegistry.self)! + if registry.stateSystemMap[state] == nil { + registry.stateSystemMap[state] = [system] + } else { + registry.stateSystemMap[state]?.append(system) + } + } + + +} diff --git a/Sources/ECS/States/World+States.swift b/Sources/ECS/States/World+States.swift new file mode 100644 index 0000000..c482cd5 --- /dev/null +++ b/Sources/ECS/States/World+States.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/10/15. +// + +import Foundation diff --git a/Sources/PlugIns/Graphic2D/Camera.swift b/Sources/PlugIns/Graphic2D/Camera.swift new file mode 100644 index 0000000..5928cfa --- /dev/null +++ b/Sources/PlugIns/Graphic2D/Camera.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/10/09. +// + +import Foundation diff --git a/Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift b/Sources/PlugIns/Graphic2D/Commands/EntityCommands+Graphic.swift similarity index 100% rename from Sources/PlugIns/Graphic/Commands/EntityCommands+Graphic.swift rename to Sources/PlugIns/Graphic2D/Commands/EntityCommands+Graphic.swift diff --git a/Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift b/Sources/PlugIns/Graphic2D/Commands/RemoveGraphic.swift similarity index 100% rename from Sources/PlugIns/Graphic/Commands/RemoveGraphic.swift rename to Sources/PlugIns/Graphic2D/Commands/RemoveGraphic.swift diff --git a/Sources/PlugIns/Graphic/Commands/SetGraphic.swift b/Sources/PlugIns/Graphic2D/Commands/SetGraphic.swift similarity index 100% rename from Sources/PlugIns/Graphic/Commands/SetGraphic.swift rename to Sources/PlugIns/Graphic2D/Commands/SetGraphic.swift diff --git a/Sources/PlugIns/Graphic/Graphic.swift b/Sources/PlugIns/Graphic2D/Graphic2D.swift similarity index 100% rename from Sources/PlugIns/Graphic/Graphic.swift rename to Sources/PlugIns/Graphic2D/Graphic2D.swift diff --git a/Sources/PlugIns/Graphic/World+Graphic.swift b/Sources/PlugIns/Graphic2D/World+Graphic2D.swift similarity index 100% rename from Sources/PlugIns/Graphic/World+Graphic.swift rename to Sources/PlugIns/Graphic2D/World+Graphic2D.swift diff --git a/Sources/PlugIns/Mouse/TrackableView.swift b/Sources/PlugIns/Mouse/TrackableView.swift new file mode 100644 index 0000000..5928cfa --- /dev/null +++ b/Sources/PlugIns/Mouse/TrackableView.swift @@ -0,0 +1,8 @@ +// +// File.swift +// +// +// Created by rrbox on 2023/10/09. +// + +import Foundation From 34bded34a35646ec2dd4a28f1c1f900e3a09f893 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sun, 22 Oct 2023 15:16:36 +0900 Subject: [PATCH 38/42] add: tests --- ...2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist | 12 ++- .../xcschemes/ECS-Package.xcscheme | 2 +- .../xcode/xcshareddata/xcschemes/ECS.xcscheme | 2 +- .../GraphicPlugInTests.swift | 25 +---- .../ObjectLinkPlugInTests.swift | 2 +- .../ScrollPlugInTests/ScrollPlugInTests.swift | 1 - Tests/ecs-swiftTests/ChunkTests.swift | 64 +++++++---- Tests/ecs-swiftTests/CommandsTests.swift | 60 +++++++---- .../ecs-swiftTests/EntityCommandsTests.swift | 49 +++++---- Tests/ecs-swiftTests/EventTests.swift | 76 +++++++++---- .../ecs-swiftTests/Mocks/ComponentMocks.swift | 28 +++++ Tests/ecs-swiftTests/Mocks/Components.swift | 8 -- Tests/ecs-swiftTests/PlugInTests.swift | 25 +---- Tests/ecs-swiftTests/QueryTests.swift | 101 ++++++++++++++---- Tests/ecs-swiftTests/ResourceTests.swift | 29 +---- .../ecs-swiftTests/SystemParameterTests.swift | 25 +---- Tests/ecs-swiftTests/SystemTests.swift | 93 ++++++++++++---- Tests/ecs-swiftTests/UpdateSystemTests.swift | 38 +++---- Tests/ecs-swiftTests/WorldTests.swift | 26 +---- Tests/ecs-swiftTests/ecs_swiftTests.swift | 78 ++++++++++++++ 20 files changed, 469 insertions(+), 275 deletions(-) create mode 100644 Tests/ecs-swiftTests/Mocks/ComponentMocks.swift delete mode 100644 Tests/ecs-swiftTests/Mocks/Components.swift diff --git a/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist b/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist index 616adcc..c24d915 100644 --- a/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist +++ b/.swiftpm/xcode/xcshareddata/xcbaselines/ecs-swiftTests.xcbaseline/2AC02D75-F4A4-4DFA-8C0B-FAD0AD501706.plist @@ -11,7 +11,17 @@ com.apple.XCTPerformanceMetric_WallClockTime baselineAverage - 0.000023 + 0.004780 + baselineIntegrationDisplayName + Local Baseline + + + testUpdate4Performance() + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 0.015800 baselineIntegrationDisplayName Local Baseline diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ECS-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ECS-Package.xcscheme index b7d7296..e45474d 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/ECS-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/ECS-Package.xcscheme @@ -1,6 +1,6 @@ .self)!.value.content, "test") + + commands.entity(entity)?.removeComponent(ofType: TestComponent.self) + world.applyCommands() + + // world 内に entity が存在し, component が削除されていることをテストします. + XCTAssertNotNil(world.entityRecord(forEntity: entity)) + XCTAssertNil(world.entityRecord(forEntity: entity)!.component(ofType: ComponentRef.self)) + + commands.despawn(entity: entity) + world.applyCommands() + + // world から entity が削除されたことをテストします. + XCTAssertNil(world.entityRecord(forEntity: entity)) } - } diff --git a/Tests/ecs-swiftTests/EventTests.swift b/Tests/ecs-swiftTests/EventTests.swift index dc20e38..9711647 100644 --- a/Tests/ecs-swiftTests/EventTests.swift +++ b/Tests/ecs-swiftTests/EventTests.swift @@ -6,30 +6,66 @@ // import XCTest +@testable import ECS -final class EventTests: XCTestCase { +struct TestEvent: EventProtocol { + let name: String +} - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } +func testEvent(event: EventReader, eventWriter: EventWriter, commands: Commands, currentTime: Resource) { + print("---test event read---") + print("frame:", currentTime.resource.value) + print("<- read event:", event.value.name) + let spawned = commands.spawn().addComponent(TestComponent(content: event.value.name)).id() + print("-> spawn:", spawned) + print("-> event send:", "\"link\"") + eventWriter.send(value: TestEvent(name: "[\(currentTime.resource.value)]: link")) + print("---") + print() +} - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } +func setUp(eventWriter: EventWriter) { + print("---set up---") + print("-> event send:", "\"test event\"") + eventWriter.send(value: TestEvent(name: "test event")) + print("---") + print() +} - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } +func spawnedEntitySystem(eventReader: EventReader, commands: Commands, currentTime: Resource) { + print("---spawned entity event read---") + print("frame:", currentTime.resource.value) + print("<- spawned(receive):", eventReader.value.spawnedEntity) + print("-> despawn:", eventReader.value.spawnedEntity) + commands.despawn(entity: eventReader.value.spawnedEntity) + print("---") + print() +} - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } +func despanedEntitySystem(eventReader: EventReader, commands: Commands, currentTime: Resource) { + print("---despawned entity event read---") + print("frame:", currentTime.resource.value) + print("<- despawned(receive):", eventReader.value.despawnedEntity) + print("---") + print() +} +final class EventTests: XCTestCase { + func testEvent() { + print() + + let world = World() + .addEventStreamer(eventType: TestEvent.self) + .addEventSystem(testEvent(event:eventWriter:commands:currentTime:)) + .addSetUpSystem(setUp(eventWriter:)) + .addEventSystem(spawnedEntitySystem) + .addEventSystem(despanedEntitySystem) + + world.setUpWorld() + + world.update(currentTime: 0) + world.update(currentTime: 1) + world.update(currentTime: 2) + world.update(currentTime: 3) + } } diff --git a/Tests/ecs-swiftTests/Mocks/ComponentMocks.swift b/Tests/ecs-swiftTests/Mocks/ComponentMocks.swift new file mode 100644 index 0000000..c8fd5d7 --- /dev/null +++ b/Tests/ecs-swiftTests/Mocks/ComponentMocks.swift @@ -0,0 +1,28 @@ +// +// Components.swift +// +// +// Created by rrbox on 2023/08/14. +// + +import ECS + +struct TestComponent: Component { + let content: String +} + +struct TestComponent2: Component { + let content: String +} + +struct TestComponent3: Component { + let content: String +} + +struct TestComponent4: Component { + let content: String +} + +struct TestComponent5: Component { + let content: String +} diff --git a/Tests/ecs-swiftTests/Mocks/Components.swift b/Tests/ecs-swiftTests/Mocks/Components.swift deleted file mode 100644 index e46c664..0000000 --- a/Tests/ecs-swiftTests/Mocks/Components.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// File.swift -// -// -// Created by rrbox on 2023/08/14. -// - -import Foundation diff --git a/Tests/ecs-swiftTests/PlugInTests.swift b/Tests/ecs-swiftTests/PlugInTests.swift index aeb2c64..3954b07 100644 --- a/Tests/ecs-swiftTests/PlugInTests.swift +++ b/Tests/ecs-swiftTests/PlugInTests.swift @@ -8,28 +8,5 @@ import XCTest final class PlugInTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - + } diff --git a/Tests/ecs-swiftTests/QueryTests.swift b/Tests/ecs-swiftTests/QueryTests.swift index 37953b2..d8945bc 100644 --- a/Tests/ecs-swiftTests/QueryTests.swift +++ b/Tests/ecs-swiftTests/QueryTests.swift @@ -6,30 +6,85 @@ // import XCTest +@testable import ECS final class QueryTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } + func testQuery() { + let testQuery = Query() + let testQuery2 = Query2() + let testQuery3 = Query3() + let testQuery4 = Query4() + let testQuery5 = Query5() + + let world = World() + + world.worldBuffer.chunkBuffer.addChunk(testQuery) + world.worldBuffer.chunkBuffer.addChunk(testQuery2) + world.worldBuffer.chunkBuffer.addChunk(testQuery3) + world.worldBuffer.chunkBuffer.addChunk(testQuery4) + world.worldBuffer.chunkBuffer.addChunk(testQuery5) + + let commands = world.worldBuffer.commandsBuffer.commands()! + + let testEntity = commands.spawn().addComponent(TestComponent(content: "test")).id() + + world.applyCommands() + + XCTAssertEqual(testQuery.components.count, 1) + XCTAssertEqual(testQuery2.components.count, 0) + XCTAssertEqual(testQuery3.components.count, 0) + XCTAssertEqual(testQuery4.components.count, 0) + XCTAssertEqual(testQuery5.components.count, 0) + + commands.entity(testEntity)?.addComponent(TestComponent2(content: "test2")) + + world.applyCommands() + + XCTAssertEqual(testQuery.components.count, 1) + XCTAssertEqual(testQuery2.components.count, 1) + XCTAssertEqual(testQuery3.components.count, 0) + XCTAssertEqual(testQuery4.components.count, 0) + XCTAssertEqual(testQuery5.components.count, 0) + + commands.entity(testEntity)?.addComponent(TestComponent3(content: "test2")) + + world.applyCommands() + + XCTAssertEqual(testQuery.components.count, 1) + XCTAssertEqual(testQuery2.components.count, 1) + XCTAssertEqual(testQuery3.components.count, 1) + XCTAssertEqual(testQuery4.components.count, 0) + XCTAssertEqual(testQuery5.components.count, 0) + + commands.entity(testEntity)?.addComponent(TestComponent4(content: "test2")) + + world.applyCommands() + + XCTAssertEqual(testQuery.components.count, 1) + XCTAssertEqual(testQuery2.components.count, 1) + XCTAssertEqual(testQuery3.components.count, 1) + XCTAssertEqual(testQuery4.components.count, 1) + XCTAssertEqual(testQuery5.components.count, 0) + + commands.entity(testEntity)?.addComponent(TestComponent5(content: "test2")) + + world.applyCommands() + + XCTAssertEqual(testQuery.components.count, 1) + XCTAssertEqual(testQuery2.components.count, 1) + XCTAssertEqual(testQuery3.components.count, 1) + XCTAssertEqual(testQuery4.components.count, 1) + XCTAssertEqual(testQuery5.components.count, 1) + + commands.entity(testEntity)?.removeComponent(ofType: TestComponent.self) + + world.applyCommands() + + XCTAssertEqual(testQuery.components.count, 0) + XCTAssertEqual(testQuery2.components.count, 0) + XCTAssertEqual(testQuery3.components.count, 0) + XCTAssertEqual(testQuery4.components.count, 0) + XCTAssertEqual(testQuery5.components.count, 0) } - + } diff --git a/Tests/ecs-swiftTests/ResourceTests.swift b/Tests/ecs-swiftTests/ResourceTests.swift index 0cb8a6d..689a974 100644 --- a/Tests/ecs-swiftTests/ResourceTests.swift +++ b/Tests/ecs-swiftTests/ResourceTests.swift @@ -1,5 +1,5 @@ // -// ReourceTests.swift +// ResourceTests.swift // // // Created by rrbox on 2023/08/11. @@ -7,29 +7,6 @@ import XCTest -final class ReourceTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - +final class ResourceTests: XCTestCase { + } diff --git a/Tests/ecs-swiftTests/SystemParameterTests.swift b/Tests/ecs-swiftTests/SystemParameterTests.swift index 00d131d..528d003 100644 --- a/Tests/ecs-swiftTests/SystemParameterTests.swift +++ b/Tests/ecs-swiftTests/SystemParameterTests.swift @@ -8,28 +8,5 @@ import XCTest final class SystemParameterTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - + } diff --git a/Tests/ecs-swiftTests/SystemTests.swift b/Tests/ecs-swiftTests/SystemTests.swift index a846c38..12235b6 100644 --- a/Tests/ecs-swiftTests/SystemTests.swift +++ b/Tests/ecs-swiftTests/SystemTests.swift @@ -6,30 +6,87 @@ // import XCTest +import ECS -final class SystemTests: XCTestCase { +func testSetUp(commands: Commands) { + print("set up") + commands.spawn() + .addComponent(TestComponent(content: "sample_1010")) + + commands.spawn() + .addComponent(TestComponent(content: "sample_120391-2")) +} - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } +func currentTimeTestSystem(time: Resource) { + print(time.resource) +} - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } +func deltaTimeTestSystem(deltaTime: Resource) { + print(deltaTime.resource) +} - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. +func apiTestSystem( + q0: Query +) { + q0.update { _, component in + print(component) } +} + +func apiTestSystem( + q0: Query, + q1: Query2 +) { + +} + +func apiTestSystem( + q0: Query, + q1: Query2, + q2: Query3 +) { + +} + +func apiTestSystem( + q0: Query, + q1: Query2, + q2: Query3, + q3: Query4 +) { + +} - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } +func apiTestSystem( + q0: Query, + q1: Query2, + q2: Query3, + q3: Query4, + q4: Query5 +) { + q0.update { _, component in + print(component) } +} +final class SystemTests: XCTestCase { + func testUpdateSystem() { + let world = World() + .addSetUpSystem(testSetUp(commands:)) + .addUpdateSystem(currentTimeTestSystem(time:)) + .addUpdateSystem(deltaTimeTestSystem(deltaTime:)) + .addUpdateSystem(apiTestSystem(q0:)) + .addUpdateSystem(apiTestSystem(q0:q1:)) + .addUpdateSystem(apiTestSystem(q0:q1:q2:)) + .addUpdateSystem(apiTestSystem(q0:q1:q2:q3:)) + .addUpdateSystem(apiTestSystem(q0:q1:q2:q3:q4:)) + + world.setUpWorld() + + world.update(currentTime: 0) + world.update(currentTime: 1) + world.update(currentTime: 2) + world.update(currentTime: 3) + world.update(currentTime: 4) + } } diff --git a/Tests/ecs-swiftTests/UpdateSystemTests.swift b/Tests/ecs-swiftTests/UpdateSystemTests.swift index af820d8..807cfc7 100644 --- a/Tests/ecs-swiftTests/UpdateSystemTests.swift +++ b/Tests/ecs-swiftTests/UpdateSystemTests.swift @@ -6,30 +6,26 @@ // import XCTest +@testable import ECS -final class UpdateSystemTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } +func mySystem(commands: Commands) { + commands.spawn() + .addComponent(TestComponent(content: "sample")) +} - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. +func mySystem2(query: Query) { + query.update { _, component in + XCTAssertEqual(component.content, "sample") } +} - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } +final class UpdateSystemTests: XCTestCase { + func testUpdate() { + let world = World() + .addUpdateSystem(mySystem(commands:)) + .addUpdateSystem(mySystem2(query:)) + + world.update(currentTime: 0) + world.update(currentTime: 0) } - } diff --git a/Tests/ecs-swiftTests/WorldTests.swift b/Tests/ecs-swiftTests/WorldTests.swift index 999346d..fb72245 100644 --- a/Tests/ecs-swiftTests/WorldTests.swift +++ b/Tests/ecs-swiftTests/WorldTests.swift @@ -6,30 +6,10 @@ // import XCTest +import ECS final class WorldTests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - // Any test you write for XCTest can be annotated as throws and async. - // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. - // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } + func testWorld() { + _ = World() } - } diff --git a/Tests/ecs-swiftTests/ecs_swiftTests.swift b/Tests/ecs-swiftTests/ecs_swiftTests.swift index 0ae8551..f8e555a 100644 --- a/Tests/ecs-swiftTests/ecs_swiftTests.swift +++ b/Tests/ecs-swiftTests/ecs_swiftTests.swift @@ -1,6 +1,84 @@ import XCTest @testable import ECS +struct Text: Component { + let v: String +} + +func entitycreate(commands: Commands) { + for i in 1...20000 { + commands.spawn() + .addComponent(Text(v: "\(i)")) + } +} + +func entitycreate2(commands: Commands) { + for i in 1...20000 { + commands.spawn() + .addComponent(Text(v: "\(i)")) + } +} + + +func update(query: Query) { + query.update { _, _ in + + } +} + +func update2(query: Query) { + query.update { _, _ in + + } +} + +func update3(query: Query) { + query.update { _, _ in + + } +} + +func update4(query: Query) { + query.update { _, _ in + + } +} + final class ecs_swiftTests: XCTestCase { + // entity: 20000 + // set up: 1 + // update: 1 + // 0.00478 s + func testPerformance() { + let world = World() + .addSetUpSystem(entitycreate(commands:)) + .addUpdateSystem(update(query:)) + world.setUpWorld() + + print(world.entities.sequence.count) + + measure { + world.update(currentTime: 0) + } + } + // entity: 20000 + // set up: 1 + // update: 4 + // 0.0158 s -> およそ 4 倍 + func testUpdate4Performance() { + let world = World() + .addSetUpSystem(entitycreate(commands:)) + .addUpdateSystem(update(query:)) + .addUpdateSystem(update2(query:)) + .addUpdateSystem(update3(query:)) + .addUpdateSystem(update4(query:)) + world.setUpWorld() + + print(world.entities.sequence.count) + + measure { + world.update(currentTime: 0) + } + } } From b34805b1f22e5cc70b0a0db0d9e2abc222b3f213 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sun, 22 Oct 2023 15:17:37 +0900 Subject: [PATCH 39/42] add: Filtered query --- Sources/ECS/FilterdQuery/FIlteredQuery.swift | 28 ++++++++++++++++-- Sources/ECS/FilterdQuery/Filter.swift | 30 ++++++++++++++++++-- Sources/ECS/FilterdQuery/QueryProtocol.swift | 14 +++++++-- 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/Sources/ECS/FilterdQuery/FIlteredQuery.swift b/Sources/ECS/FilterdQuery/FIlteredQuery.swift index ae844a3..3585fda 100644 --- a/Sources/ECS/FilterdQuery/FIlteredQuery.swift +++ b/Sources/ECS/FilterdQuery/FIlteredQuery.swift @@ -1,8 +1,32 @@ // -// File.swift +// FilteredQuery.swift // // // Created by rrbox on 2023/09/17. // -import Foundation +final public class Filtered: Chunk, SystemParameter { + public let query: Q = Q() + + override func spawn(entity: Entity, entityRecord: EntityRecord) { + guard F.condition(forEntityRecord: entityRecord) else { return } + self.query.spawn(entity: entity, entityRecord: entityRecord) + } + + override func despawn(entity: Entity) { + self.query.despawn(entity: entity) + } + + public static func getParameter(from worldBuffer: WorldBuffer) -> Filtered? { + worldBuffer.chunkBuffer.chunk(ofType: Filtered.self) + } + + public static func register(to worldBuffer: WorldBuffer) { + guard worldBuffer.chunkBuffer.chunk(ofType: Self.self) == nil else { + return + } + + worldBuffer.chunkBuffer.addChunk(Filtered()) + } + +} diff --git a/Sources/ECS/FilterdQuery/Filter.swift b/Sources/ECS/FilterdQuery/Filter.swift index ae844a3..fd097c5 100644 --- a/Sources/ECS/FilterdQuery/Filter.swift +++ b/Sources/ECS/FilterdQuery/Filter.swift @@ -1,8 +1,34 @@ // -// File.swift +// Filter.swift // // // Created by rrbox on 2023/09/17. // -import Foundation +public protocol Filter { + static func condition(forEntityRecord entityRecord: EntityRecord) -> Bool +} + +public struct With: Filter { + public static func condition(forEntityRecord entityRecord: EntityRecord) -> Bool { + entityRecord.component(ofType: ComponentRef.self) != nil + } +} + +public struct WithOut: Filter { + public static func condition(forEntityRecord entityRecord: EntityRecord) -> Bool { + entityRecord.component(ofType: ComponentRef.self) == nil + } +} + +public struct And: Filter { + public static func condition(forEntityRecord entityRecord: EntityRecord) -> Bool { + T.condition(forEntityRecord: entityRecord) && U.condition(forEntityRecord: entityRecord) + } +} + +public struct Or: Filter { + public static func condition(forEntityRecord entityRecord: EntityRecord) -> Bool { + T.condition(forEntityRecord: entityRecord) || U.condition(forEntityRecord: entityRecord) + } +} diff --git a/Sources/ECS/FilterdQuery/QueryProtocol.swift b/Sources/ECS/FilterdQuery/QueryProtocol.swift index ae844a3..56d421d 100644 --- a/Sources/ECS/FilterdQuery/QueryProtocol.swift +++ b/Sources/ECS/FilterdQuery/QueryProtocol.swift @@ -1,8 +1,18 @@ // -// File.swift +// QueryProtocol.swift // // // Created by rrbox on 2023/09/17. // -import Foundation +public protocol QueryProtocol { + func spawn(entity: Entity, entityRecord: EntityRecord) + func despawn(entity: Entity) + init() +} + +extension Query: QueryProtocol {} +extension Query2: QueryProtocol {} +extension Query3: QueryProtocol {} +extension Query4: QueryProtocol {} +extension Query5: QueryProtocol {} From 261e8c2749aaab0f6c994f10e9eaccc78ea17d23 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sun, 22 Oct 2023 15:18:41 +0900 Subject: [PATCH 40/42] change: Query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `QueryProtocol` に適合しました. --- Sources/ECS/Query/Query.swift | 8 +++++--- Sources/ECS/Query/Query2.swift | 7 +++++-- Sources/ECS/Query/Query3.swift | 6 ++++-- Sources/ECS/Query/Query4.swift | 6 ++++-- Sources/ECS/Query/Query5.swift | 6 ++++-- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/Sources/ECS/Query/Query.swift b/Sources/ECS/Query/Query.swift index e017002..06cdc1e 100644 --- a/Sources/ECS/Query/Query.swift +++ b/Sources/ECS/Query/Query.swift @@ -8,12 +8,14 @@ final public class Query: Chunk, SystemParameter { var components = [Entity: ComponentRef]() - override func spawn(entity: Entity, entityRecord: EntityRecord) { + public override init() {} + + public override func spawn(entity: Entity, entityRecord: EntityRecord) { guard let componentRef = entityRecord.component(ofType: ComponentRef.self) else { return } self.components[entity] = componentRef } - override func despawn(entity: Entity) { + public override func despawn(entity: Entity) { self.components.removeValue(forKey: entity) } @@ -37,7 +39,7 @@ final public class Query: Chunk, SystemParameter { execute(&componentRef.value) } - public func component(forEntity entity: Entity) -> ComponentType? { + public func components(forEntity entity: Entity) -> ComponentType? { self.components[entity]?.value } diff --git a/Sources/ECS/Query/Query2.swift b/Sources/ECS/Query/Query2.swift index 74160b2..dd06735 100644 --- a/Sources/ECS/Query/Query2.swift +++ b/Sources/ECS/Query/Query2.swift @@ -7,14 +7,17 @@ final public class Query2: Chunk, SystemParameter { var components = [Entity: (ComponentRef, ComponentRef)]() + var executes: [(Entity, inout C0, inout C1) -> ()] = [] - override func spawn(entity: Entity, entityRecord: EntityRecord) { + public override init() {} + + public override func spawn(entity: Entity, entityRecord: EntityRecord) { guard let c0 = entityRecord.component(ofType: ComponentRef.self), let c1 = entityRecord.component(ofType: ComponentRef.self) else { return } self.components[entity] = (c0, c1) } - override func despawn(entity: Entity) { + public override func despawn(entity: Entity) { self.components.removeValue(forKey: entity) } diff --git a/Sources/ECS/Query/Query3.swift b/Sources/ECS/Query/Query3.swift index cdfce62..9096dbe 100644 --- a/Sources/ECS/Query/Query3.swift +++ b/Sources/ECS/Query/Query3.swift @@ -8,14 +8,16 @@ final public class Query3: Chunk, SystemParameter { var components = [Entity: (ComponentRef, ComponentRef, ComponentRef)]() - override func spawn(entity: Entity, entityRecord: EntityRecord) { + public override init() {} + + public override func spawn(entity: Entity, entityRecord: EntityRecord) { guard let c0 = entityRecord.component(ofType: ComponentRef.self), let c1 = entityRecord.component(ofType: ComponentRef.self), let c2 = entityRecord.component(ofType: ComponentRef.self) else { return } self.components[entity] = (c0, c1, c2) } - override func despawn(entity: Entity) { + public override func despawn(entity: Entity) { self.components.removeValue(forKey: entity) } diff --git a/Sources/ECS/Query/Query4.swift b/Sources/ECS/Query/Query4.swift index b9a46c5..7c7dcaa 100644 --- a/Sources/ECS/Query/Query4.swift +++ b/Sources/ECS/Query/Query4.swift @@ -8,7 +8,9 @@ final public class Query4: Chunk, SystemParameter { var components = [Entity: (ComponentRef, ComponentRef, ComponentRef, ComponentRef)]() - override func spawn(entity: Entity, entityRecord: EntityRecord) { + public override init() {} + + public override func spawn(entity: Entity, entityRecord: EntityRecord) { guard let c0 = entityRecord.component(ofType: ComponentRef.self), let c1 = entityRecord.component(ofType: ComponentRef.self), let c2 = entityRecord.component(ofType: ComponentRef.self), @@ -16,7 +18,7 @@ final public class Query4: Chunk, SystemParameter { var components = [Entity: (ComponentRef, ComponentRef, ComponentRef, ComponentRef, ComponentRef)]() - override func spawn(entity: Entity, entityRecord: EntityRecord) { + public override init() {} + + public override func spawn(entity: Entity, entityRecord: EntityRecord) { guard let c0 = entityRecord.component(ofType: ComponentRef.self), let c1 = entityRecord.component(ofType: ComponentRef.self), let c2 = entityRecord.component(ofType: ComponentRef.self), @@ -17,7 +19,7 @@ final public class Query5 Date: Sun, 22 Oct 2023 15:24:42 +0900 Subject: [PATCH 41/42] add: Camera --- Sources/PlugIns/Graphic2D/Camera.swift | 23 ++++++++++++++++--- Sources/PlugIns/Graphic2D/Graphic2D.swift | 2 +- .../PlugIns/Graphic2D/World+Graphic2D.swift | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Sources/PlugIns/Graphic2D/Camera.swift b/Sources/PlugIns/Graphic2D/Camera.swift index 5928cfa..d985a65 100644 --- a/Sources/PlugIns/Graphic2D/Camera.swift +++ b/Sources/PlugIns/Graphic2D/Camera.swift @@ -1,8 +1,25 @@ // -// File.swift -// +// Camera.swift +// // // Created by rrbox on 2023/10/09. // -import Foundation +import SpriteKit +import ECS + +public struct Camera: ResourceProtocol { + public let camera: SKCameraNode + + public static func setDefaultCamera(scene: SKScene) -> Camera { + let cameraNode = SKCameraNode() + scene.camera = cameraNode + return Camera(camera: cameraNode) + } + + public static func createFrom(cameraNamed name: String, inScene scene: SKScene) -> Camera { + let cameraNode = scene.childNode(withName: name) as! SKCameraNode + return Camera(camera: cameraNode) + } +} + diff --git a/Sources/PlugIns/Graphic2D/Graphic2D.swift b/Sources/PlugIns/Graphic2D/Graphic2D.swift index ec3f27f..b11458f 100644 --- a/Sources/PlugIns/Graphic2D/Graphic2D.swift +++ b/Sources/PlugIns/Graphic2D/Graphic2D.swift @@ -1,5 +1,5 @@ // -// Grahpic.swift +// Graphic2D.swift // // // Created by rrbox on 2023/08/18. diff --git a/Sources/PlugIns/Graphic2D/World+Graphic2D.swift b/Sources/PlugIns/Graphic2D/World+Graphic2D.swift index d166cc2..56f46f7 100644 --- a/Sources/PlugIns/Graphic2D/World+Graphic2D.swift +++ b/Sources/PlugIns/Graphic2D/World+Graphic2D.swift @@ -1,5 +1,5 @@ // -// World+Graphic.swift +// World+Graphic2D.swift // // // Created by rrbox on 2023/08/20. From b3161c4bb10e3844ae35b6789d01f3dd8024e503 Mon Sep 17 00:00:00 2001 From: rrbox <87851278+rrbox@users.noreply.github.com> Date: Sun, 22 Oct 2023 15:25:47 +0900 Subject: [PATCH 42/42] add: MouseEvent --- Sources/PlugIns/Mouse/Mouse.swift | 63 ++++++++++++++++++++++- Sources/PlugIns/Mouse/TrackableView.swift | 28 ++++++++-- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/Sources/PlugIns/Mouse/Mouse.swift b/Sources/PlugIns/Mouse/Mouse.swift index 96c0980..d09306a 100644 --- a/Sources/PlugIns/Mouse/Mouse.swift +++ b/Sources/PlugIns/Mouse/Mouse.swift @@ -5,4 +5,65 @@ // Created by rrbox on 2023/08/05. // -import Foundation +import ECS +import AppKit + +public struct MouseEnteredEvent: EventProtocol { + public let nsEvent: NSEvent +} + +public struct MouseExitedEvent: EventProtocol { + public let nsEvent: NSEvent +} + +public struct MouseMovedEvent: EventProtocol { + public let nsEvent: NSEvent +} + +public struct MouseDownEvent: EventProtocol { + public let nsEvent: NSEvent +} + +public struct MouseDraggedEvent: EventProtocol { + public let nsEvent: NSEvent +} + +public struct MouseUpEvent: EventProtocol { + public let nsEvent: NSEvent +} + +public func mousePlugIns(_ world: World) { + world + .addEventStreamer(eventType: MouseEnteredEvent.self) + .addEventStreamer(eventType: MouseExitedEvent.self) + .addEventStreamer(eventType: MouseMovedEvent.self) + .addEventStreamer(eventType: MouseDownEvent.self) + .addEventStreamer(eventType: MouseDraggedEvent.self) + .addEventStreamer(eventType: MouseUpEvent.self) +} + +public extension World { + func mouseEntered(with event: NSEvent) { + self.sendEvent(MouseEnteredEvent(nsEvent: event)) + } + + func mouseExited(with event: NSEvent) { + self.sendEvent(MouseExitedEvent(nsEvent: event)) + } + + func mouseMoved(with event: NSEvent) { + self.sendEvent(MouseMovedEvent(nsEvent: event)) + } + + func mouseDown(with event: NSEvent) { + self.sendEvent(MouseDownEvent(nsEvent: event)) + } + + func mouseDragged(with event: NSEvent) { + self.sendEvent(MouseDraggedEvent(nsEvent: event)) + } + + func mouseUp(with event: NSEvent) { + self.sendEvent(MouseUpEvent(nsEvent: event)) + } +} diff --git a/Sources/PlugIns/Mouse/TrackableView.swift b/Sources/PlugIns/Mouse/TrackableView.swift index 5928cfa..f991bbe 100644 --- a/Sources/PlugIns/Mouse/TrackableView.swift +++ b/Sources/PlugIns/Mouse/TrackableView.swift @@ -1,8 +1,30 @@ // -// File.swift -// +// TrackableView.swift +// // // Created by rrbox on 2023/10/09. // -import Foundation +import SpriteKit + +class MouseTrackableView: SKView { + var sceneTrackingArea: NSTrackingArea? + + func setTrackingArea() { + let scene = self.scene! + let trackingArea = NSTrackingArea( + rect: frame, + options: [.mouseEnteredAndExited, .mouseMoved, .activeAlways], + owner: scene) + self.addTrackingArea(trackingArea) + self.sceneTrackingArea = trackingArea + } + + override func updateTrackingAreas() { + if let t = self.sceneTrackingArea { + self.removeTrackingArea(t) + } + self.setTrackingArea() + } +} +