Skip to content

Commit

Permalink
Merge pull request #84 from Ark-Kit/feat/new-separate-physics-systems
Browse files Browse the repository at this point in the history
[ark-physics-kit] feat: separate sync to and update systems
  • Loading branch information
didymental authored Apr 16, 2024
2 parents 715e1e6 + defc212 commit aa412de
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 131 deletions.
12 changes: 8 additions & 4 deletions ArkKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
02E0E8F42BA283180043E2BA /* UIKitRect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E0E8F32BA283180043E2BA /* UIKitRect.swift */; };
02E0E8F62BA283940043E2BA /* UIKitPolygon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E0E8F52BA283940043E2BA /* UIKitPolygon.swift */; };
02E0E8F82BA284540043E2BA /* UIKitBitmap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E0E8F72BA284540043E2BA /* UIKitBitmap.swift */; };
280CD3B72BA7391100372C5D /* ArkPhysicsSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 280CD3B62BA7391100372C5D /* ArkPhysicsSystem.swift */; };
280CD3B72BA7391100372C5D /* ArkPhysicsUpdateSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 280CD3B62BA7391100372C5D /* ArkPhysicsUpdateSystem.swift */; };
280CD3B92BA7391700372C5D /* PhysicsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 280CD3B82BA7391700372C5D /* PhysicsComponent.swift */; };
280CD3BC2BA73CF900372C5D /* ArkSKPhysicsBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 280CD3BB2BA73CF900372C5D /* ArkSKPhysicsBody.swift */; };
280CD3C42BA7419400372C5D /* ArkPhysicsContactUpdateDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 280CD3C32BA7419400372C5D /* ArkPhysicsContactUpdateDelegate.swift */; };
Expand All @@ -165,6 +165,7 @@
282248532BA82E5800850D7F /* SKPhysicsBodyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282248522BA82E5800850D7F /* SKPhysicsBodyManager.swift */; };
28548F502BCD9CA700C49404 /* ArkEntityRemovalSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28548F4F2BCD9CA700C49404 /* ArkEntityRemovalSystem.swift */; };
28548F522BCD9CB900C49404 /* ToRemoveComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28548F512BCD9CB900C49404 /* ToRemoveComponent.swift */; };
28548F542BCD9EA000C49404 /* ArkPhysicsSyncSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28548F532BCD9EA000C49404 /* ArkPhysicsSyncSystem.swift */; };
286C09C02BADD0BB000343B1 /* TankGameMapBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286C09BF2BADD0BB000343B1 /* TankGameMapBuilder.swift */; };
286C09C22BADD5FB000343B1 /* TankGameTerrainObjectBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286C09C12BADD5FB000343B1 /* TankGameTerrainObjectBuilder.swift */; };
287B00552BC16E6C002F0114 /* TankHPComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287B00542BC16E6C002F0114 /* TankHPComponent.swift */; };
Expand Down Expand Up @@ -434,7 +435,7 @@
02E0E8F32BA283180043E2BA /* UIKitRect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitRect.swift; sourceTree = "<group>"; };
02E0E8F52BA283940043E2BA /* UIKitPolygon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitPolygon.swift; sourceTree = "<group>"; };
02E0E8F72BA284540043E2BA /* UIKitBitmap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitBitmap.swift; sourceTree = "<group>"; };
280CD3B62BA7391100372C5D /* ArkPhysicsSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArkPhysicsSystem.swift; sourceTree = "<group>"; };
280CD3B62BA7391100372C5D /* ArkPhysicsUpdateSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArkPhysicsUpdateSystem.swift; sourceTree = "<group>"; };
280CD3B82BA7391700372C5D /* PhysicsComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhysicsComponent.swift; sourceTree = "<group>"; };
280CD3BB2BA73CF900372C5D /* ArkSKPhysicsBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArkSKPhysicsBody.swift; sourceTree = "<group>"; };
280CD3C32BA7419400372C5D /* ArkPhysicsContactUpdateDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArkPhysicsContactUpdateDelegate.swift; sourceTree = "<group>"; };
Expand All @@ -453,6 +454,7 @@
282248522BA82E5800850D7F /* SKPhysicsBodyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SKPhysicsBodyManager.swift; sourceTree = "<group>"; };
28548F4F2BCD9CA700C49404 /* ArkEntityRemovalSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArkEntityRemovalSystem.swift; sourceTree = "<group>"; };
28548F512BCD9CB900C49404 /* ToRemoveComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToRemoveComponent.swift; sourceTree = "<group>"; };
28548F532BCD9EA000C49404 /* ArkPhysicsSyncSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArkPhysicsSyncSystem.swift; sourceTree = "<group>"; };
286C09BF2BADD0BB000343B1 /* TankGameMapBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TankGameMapBuilder.swift; sourceTree = "<group>"; };
286C09C12BADD5FB000343B1 /* TankGameTerrainObjectBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TankGameTerrainObjectBuilder.swift; sourceTree = "<group>"; };
287B00542BC16E6C002F0114 /* TankHPComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TankHPComponent.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1151,7 +1153,8 @@
children = (
280CD3D72BA7FA9A00372C5D /* ark-physics-facade */,
280CD3CC2BA74E3100372C5D /* sprite-kit-physics-facade */,
280CD3B62BA7391100372C5D /* ArkPhysicsSystem.swift */,
280CD3B62BA7391100372C5D /* ArkPhysicsUpdateSystem.swift */,
28548F532BCD9EA000C49404 /* ArkPhysicsSyncSystem.swift */,
280CD3B82BA7391700372C5D /* PhysicsComponent.swift */,
28844EA02BA881E60037A7F6 /* DemoPhysicsComponent.swift */,
);
Expand Down Expand Up @@ -1946,6 +1949,7 @@
02B3C64E2BCD8507002331A0 /* ArkPlayerStateSetupDelegate.swift in Sources */,
945441042BC9178400E90ECE /* SnakeGame.swift in Sources */,
ADA847FD2BBC4B5500B19378 /* AbstractNetworkService.swift in Sources */,
28548F542BCD9EA000C49404 /* ArkPhysicsSyncSystem.swift in Sources */,
02C3951E2BA849490075F1CA /* CircleRenderableComponent.swift in Sources */,
9479A3AF2BA952E300F99013 /* AbstractShape.swift in Sources */,
02E0E8EE2BA280BD0043E2BA /* UIKitShape.swift in Sources */,
Expand Down Expand Up @@ -2091,7 +2095,7 @@
AD787A842B9C6C78003EBBD0 /* Component.swift in Sources */,
945441252BC99D8800E90ECE /* SnakeGridPositionComponent.swift in Sources */,
8F5573BF2BA425E4007030C8 /* ShapeRenderable.swift in Sources */,
280CD3B72BA7391100372C5D /* ArkPhysicsSystem.swift in Sources */,
280CD3B72BA7391100372C5D /* ArkPhysicsUpdateSystem.swift in Sources */,
28EFCB252BCCA7CC0059A908 /* ArkECSWrapper.swift in Sources */,
280CD3D62BA7F8CC00372C5D /* SKPhysicsScene.swift in Sources */,
941BE21E2BC0EC1900707997 /* ArkProtocol.swift in Sources */,
Expand Down
18 changes: 11 additions & 7 deletions ArkKit/app/utils/set-up/ArkSetUpStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,25 +132,29 @@ extension ArkSetUpStrategy {

let simulator = SKSimulator(size: CGSize(width: worldWidth, height: worldHeight))
ark.gameLoop = simulator
let physicsSystem = ArkPhysicsSystem(simulator: simulator,
eventManager: ark.arkState.eventManager,
arkECS: ark.arkState.arkECS)
let physicsUpdateSystem = ArkPhysicsUpdateSystem(simulator: simulator,
eventManager: ark.arkState.eventManager,
arkECS: ark.arkState.arkECS)
let animationSystem = ArkAnimationSystem()
let canvasSystem = ArkCanvasSystem()
let timeSystem = ArkTimeSystem()
let cameraSystem = ArkCameraSystem()
let entityRemovalSystem = ArkEntityRemovalSystem()
ark.arkState.arkECS.addSystem(timeSystem)
ark.arkState.arkECS.addSystem(physicsSystem)
ark.arkState.arkECS.addSystem(physicsUpdateSystem)
ark.arkState.arkECS.addSystem(animationSystem)
ark.arkState.arkECS.addSystem(canvasSystem)
ark.arkState.arkECS.addSystem(cameraSystem)
ark.arkState.arkECS.addSystem(entityRemovalSystem)

// inject dependency into game loop
simulator.physicsScene?.sceneContactUpdateDelegate = physicsSystem
simulator.physicsScene?.sceneUpdateLoopDelegate = physicsSystem
ark.gameLoop?.updatePhysicsSceneDelegate = physicsSystem
let physicsSyncSystem = ArkPhysicsSyncSystem(simulator: simulator,
eventManager: ark.arkState.eventManager,
arkECS: ark.arkState.arkECS)
ark.arkState.arkECS.addSystem(physicsSyncSystem)
simulator.physicsScene?.sceneContactUpdateDelegate = physicsSyncSystem
simulator.physicsScene?.sceneUpdateLoopDelegate = physicsSyncSystem
ark.gameLoop?.updatePhysicsSceneDelegate = physicsSyncSystem
}

func setupMultiplayerGameLoop() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import Foundation

/**
* A system which updates all running animation instances in ArkECS after the given delta.
* A system which syncs from the physics world.
*/
class ArkPhysicsSystem: UpdateSystem {
class ArkPhysicsSyncSystem: UpdateSystem {
var active: Bool
var simulator: AbstractPhysicsArkSimulator
var scene: AbstractArkPhysicsScene?
var eventManager: ArkEventManager
var arkECS: ArkECS
Expand All @@ -16,15 +15,12 @@ class ArkPhysicsSystem: UpdateSystem {
arkECS: ArkECS,
active: Bool = true) {
self.active = active
self.simulator = simulator
self.scene = simulator.physicsScene
self.eventManager = eventManager
self.arkECS = arkECS
}

func update(deltaTime: TimeInterval, arkECS: ArkECS) {
let physicsComponents = getPhysicsComponents(arkECS)
syncToPhysicsEngine(physicsComponents, arkECS: arkECS)
}

private func getPhysicsComponents(_ arkECS: ArkECS) -> [(Entity, PhysicsComponent)] {
Expand All @@ -48,109 +44,6 @@ class ArkPhysicsSystem: UpdateSystem {
})
}

func syncToPhysicsEngine(_ physicsComponents: [(Entity, PhysicsComponent)], arkECS: ArkECS) {
for (entity, physics) in physicsComponents {
handlePhysicsComponentRemovalIfNeeded(for: entity, using: physics, arkECS: arkECS)

if let toRemoveComponent = arkECS.getComponent(ofType: ToRemoveComponent.self, for: entity),
toRemoveComponent.toBeRemoved {
return }

guard let positionComponent = arkECS.getComponent(ofType: PositionComponent.self, for: entity),
let rotationComponent = arkECS.getComponent(ofType: RotationComponent.self, for: entity) else {
continue }

syncPhysicsBody(for: entity,
position: positionComponent,
rotation: rotationComponent,
physics: physics,
arkECS: arkECS)
}
}

private func handlePhysicsComponentRemovalIfNeeded(for entity: Entity,
using physics: PhysicsComponent,
arkECS: ArkECS) {
guard let toRemoveComponent = arkECS.getComponent(ofType: ToRemoveComponent.self, for: entity),
toRemoveComponent.toBeRemoved else {
return }

scene?.removePhysicsBody(for: entity)
arkECS.removeEntity(entity)
}

private func syncPhysicsBody(for entity: Entity, position: PositionComponent,
rotation: RotationComponent, physics: PhysicsComponent, arkECS: ArkECS) {
if var physicsBody = scene?.getPhysicsBody(for: entity) {
updatePhysicsBody(&physicsBody, position: position, rotation: rotation, physics: physics)
} else {
createPhysicsBody(for: entity, positionComponent: position,
rotationComponent: rotation, physicsComponent: physics)
}

applyPhysicsImpulses(for: entity, with: physics, arkECS: arkECS)
}

private func applyPhysicsImpulses(for entity: Entity, with physics: PhysicsComponent, arkECS: ArkECS) {
if physics.impulse != .zero {
scene?.apply(impulse: physics.impulse, to: entity)
apply(impulse: .zero, to: entity, arkECS: arkECS)
}
if physics.angularImpulse != .zero {
scene?.apply(angularImpulse: physics.angularImpulse, to: entity)
apply(angularImpulse: .zero, to: entity, arkECS: arkECS)
}
}

private func createPhysicsBody(for entity: Entity,
positionComponent: PositionComponent,
rotationComponent: RotationComponent,
physicsComponent: PhysicsComponent) {
var physicsBody: AbstractArkPhysicsBody?
if physicsComponent.shape == .circle, let radius = physicsComponent.radius {
physicsBody = scene?.createCirclePhysicsBody(for: entity,
withRadius: radius,
at: positionComponent.position)
} else if physicsComponent.shape == .rectangle, let size = physicsComponent.size {
physicsBody = scene?.createRectanglePhysicsBody(for: entity,
withSize: size,
at: positionComponent.position)
} else if physicsComponent.shape == .polygon, let vertices = physicsComponent.vertices {
physicsBody = scene?.createPolygonPhysicsBody(for: entity,
withVertices: vertices,
at: positionComponent.position)
}

if var physicsBody = physicsBody {
updatePhysicsBody(&physicsBody, position: positionComponent,
rotation: rotationComponent, physics: physicsComponent)
}
}

private func updatePhysicsBody(_ physicsBody: inout AbstractArkPhysicsBody,
position: PositionComponent,
rotation: RotationComponent,
physics: PhysicsComponent) {
physicsBody.position = position.position
physicsBody.zRotation = rotation.angleInRadians ?? physicsBody.zRotation
updateOptionalPhysicsBodyProperties(&physicsBody, with: physics)
}

private func updateOptionalPhysicsBodyProperties(_ physicsBody: inout AbstractArkPhysicsBody,
with physicsComponent: PhysicsComponent) {
physicsBody.mass = physicsComponent.mass ?? physicsBody.mass
physicsBody.velocity = physicsComponent.velocity
physicsBody.affectedByGravity = physicsComponent.affectedByGravity
physicsBody.linearDamping = physicsComponent.linearDamping
physicsBody.isDynamic = physicsComponent.isDynamic
physicsBody.allowsRotation = physicsComponent.allowsRotation
physicsBody.restitution = physicsComponent.restitution
physicsBody.friction = physicsComponent.friction
physicsBody.categoryBitMask = physicsComponent.categoryBitMask
physicsBody.collisionBitMask = physicsComponent.collisionBitMask
physicsBody.contactTestBitMask = physicsComponent.contactTestBitMask
}

// MARK: Impulse application
func apply(impulse: CGVector, to entity: Entity, arkECS: ArkECS) {
guard var physicsComponent: PhysicsComponent =
Expand All @@ -172,12 +65,12 @@ class ArkPhysicsSystem: UpdateSystem {

// MARK: Handle Collision
func handleCollisionBegan(between entityA: Entity, and entityB: Entity) {
var arkCollisionEvent = makeCollisionEvent(ArkCollisionBeganEvent.self, entityA, entityB)
let arkCollisionEvent = makeCollisionEvent(ArkCollisionBeganEvent.self, entityA, entityB)
self.eventManager.emit(arkCollisionEvent)
}

func handleCollisionEnd(between entityA: Entity, and entityB: Entity) {
var arkCollisionEvent = makeCollisionEvent(ArkCollisionEndedEvent.self, entityA, entityB)
let arkCollisionEvent = makeCollisionEvent(ArkCollisionEndedEvent.self, entityA, entityB)
self.eventManager.emit(arkCollisionEvent)
}

Expand All @@ -196,7 +89,7 @@ class ArkPhysicsSystem: UpdateSystem {
}
}

extension ArkPhysicsSystem: ArkPhysicsContactUpdateDelegate {
extension ArkPhysicsSyncSystem: ArkPhysicsContactUpdateDelegate {
func didContactBegin(between entityA: Entity, and entityB: Entity) {
handleCollisionBegan(between: entityA, and: entityB)
}
Expand All @@ -206,7 +99,7 @@ extension ArkPhysicsSystem: ArkPhysicsContactUpdateDelegate {
}
}

extension ArkPhysicsSystem: ArkPhysicsSceneUpdateLoopDelegate {
extension ArkPhysicsSyncSystem: ArkPhysicsSceneUpdateLoopDelegate {
func update(_ deltaTime: TimeInterval) {
syncFromPhysicsEngine()
}
Expand Down
Loading

0 comments on commit aa412de

Please sign in to comment.