From 143a768cc724c93bd3522e6394029544f258d818 Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Tue, 26 Mar 2024 00:10:05 +0800 Subject: [PATCH 01/13] refactor: Refactor PlayerView --- .../Rendering/MTKRenderer/MTKRenderer.swift | 4 ++-- .../Rendering/MTKRenderer/PlayerView.swift | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index 49361cc9..ba3991a6 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -41,9 +41,9 @@ class MTKRenderer: NSObject, Renderer { /// Set ups the views for a single player game. func createSinglePlayerView(at superview: UIView) { - let playerView = PlayerView(superview: superview, device: self.device, drawDelegate: self) - playerView.setupSubviews() + let playerView = PlayerView.createPlayerView(superview: superview, device: self.device) playerView.setControlViewDelegate(self) + playerView.setDrawDelegate(self) self.playerView = playerView } } diff --git a/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift b/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift index 85cbc703..d7c76285 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift @@ -15,9 +15,8 @@ class PlayerView { var controlView: ControlView var overlayView: OverlayView - init(superview: UIView, device: MTLDevice, drawDelegate: MTKViewDelegate) { + private init(superview: UIView, device: MTLDevice) { self.sceneView = MTKView(frame: superview.frame, device: device) - self.sceneView.delegate = drawDelegate superview.addSubview(self.sceneView) self.overlayView = OverlayView(frame: superview.frame) @@ -36,7 +35,17 @@ class PlayerView { controlView.controlViewDelegate = delegate } + func setDrawDelegate(_ delegate: MTKViewDelegate) { + sceneView.delegate = drawDelegate + } + func updateOverlay(score: Int) { overlayView.update(score: score) } + + static func createPlayerView(superview: UIView, device: MTLDevice) -> PlayerView { + let playerView = PlayerView(superview: superview, device: device) + playerView.setupSubviews() + return playerView + } } From 5e98873af8334d3fb12299e3ee04320c9ac2a198 Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Tue, 26 Mar 2024 18:34:44 +0800 Subject: [PATCH 02/13] chore: Integrate use of camera with rendering --- .../Sources/SDPhysicsEngine/GameScene.swift | 29 +++++++---- .../Object/SDCameraObject.swift | 11 ++++ .../star-dash/GameBridge/GameBridge.swift | 7 ++- .../Rendering/MTKRenderer/MTKRenderer.swift | 48 ++++++++++++----- .../Rendering/MTKRenderer/PlayerView.swift | 4 +- .../Rendering/Utils/LayoutUtils.swift | 52 +++++++++++++++++++ .../Rendering/Utils/PlayerViewLayout.swift | 4 ++ star-dash/star-dash/ViewController.swift | 6 +-- 8 files changed, 131 insertions(+), 30 deletions(-) create mode 100644 star-dash/star-dash/Rendering/Utils/LayoutUtils.swift create mode 100644 star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift index c002f9e7..ff1d3b9f 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift @@ -8,6 +8,8 @@ public class GameScene: SKScene { private var objectMap: [SKNode: SDObject] = [:] + private cameraPlayerMap: [Int: SDCameraObject] + override public func sceneDidLoad() { super.sceneDidLoad() @@ -21,15 +23,31 @@ public class GameScene: SKScene { lastUpdateTime = currentTime return } - let deltaTime = currentTime - lastUpdateTime self.lastUpdateTime = currentTime + self.updateCameras() sceneDelegate?.update(self, deltaTime: deltaTime) } + + func updateCameras() { + for camera in cameraPlayerMap.values { + camera.update() + } + } + + func camera(of playerIndex: Int) -> SKCameraNode? { + cameraPlayerMap[playerIndex]?.node + } } extension GameScene: SDScene { + public func addPlayerObject(_ playerObject: SDObject) { + let camera = SDCameraObject() + addObject(camera) + addObject(playerObject) + } + public func addObject(_ object: SDObject) { guard objectMap[object.node] == nil else { return @@ -43,15 +61,6 @@ extension GameScene: SDScene { objectMap[object.node] = nil object.removeFromParent() } - - public func addCameraObject(_ cameraObject: SDCameraObject) { - addObject(cameraObject) - camera = cameraObject.cameraNode - } - - public func setCameraObjectXPosition(to x: CGFloat) { - camera?.position.x = x - } } extension GameScene: SKPhysicsContactDelegate { diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift index 320069ef..47ff22e1 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift @@ -2,9 +2,20 @@ import SpriteKit public class SDCameraObject: SDObject { let cameraNode: SKCameraNode + let player: SKObject? override public init() { cameraNode = SKCameraNode() super.init(node: cameraNode) } + + init(player: SKObject) { + self.player = player + cameraNode = SKCameraNode() + super.init(node: cameraNode) + } + + update() { + self.position = player.position + } } diff --git a/star-dash/star-dash/GameBridge/GameBridge.swift b/star-dash/star-dash/GameBridge/GameBridge.swift index 9a66db72..6307781d 100644 --- a/star-dash/star-dash/GameBridge/GameBridge.swift +++ b/star-dash/star-dash/GameBridge/GameBridge.swift @@ -84,7 +84,12 @@ class GameBridge { modules.forEach { $0.create(for: newObject, from: entity) } - self.scene.addObject(newObject) + + if type(of: entity) == PlayerEntity.self { + self.scene.addPlayerObject(newObject) + } else { + self.scene.addObject(newObject) + } } private func removeObject(from entityId: EntityId) { diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index ba3991a6..4a48bd46 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -1,6 +1,7 @@ import UIKit import SpriteKit import MetalKit +import SDPhysicsEngine /** `MTKRenderer` is a `Renderer` that uses MetalKit and SpriteKit to render @@ -10,23 +11,24 @@ import MetalKit and game information overlay is rendered through UIKit. */ class MTKRenderer: NSObject, Renderer { - var scene: SKScene + var scene: GameScene var device: MTLDevice var commandQueue: MTLCommandQueue var renderer: SKRenderer - var playerView: PlayerView? + var playerViews: [PlayerView] var viewDelegate: ViewDelegate? - init?(scene: SKScene) { + init?(scene: GameScene, numberOfPlayers) { self.scene = scene guard let device = MTLCreateSystemDefaultDevice(), let commandQueue = device.makeCommandQueue() else { return nil } + self.playerViews = [] self.device = device self.commandQueue = commandQueue self.renderer = SKRenderer(device: device) @@ -35,16 +37,37 @@ class MTKRenderer: NSObject, Renderer { super.init() } + func setupViews(at superview: UIView, for numberOfPlayers: Int) { + guard let layouts = LayoutUtils.layoutViews(superview: superview, for: numberOfPlayers) else { + return + } + + for layout in layouts { + let playerView = PlayerView.createPlayerView(layout: layout, device: self.device) + playerView.setControlViewDelegate(self) + playerView.setDrawDelegate(self) + self.playerViews.append(playerView) + } + } + + func camera(of view: MTKView) -> SKCameraNode? { + guard let playerIndex = playerIndex(from: view) { + return nil + } + + return self.scene.camera(of: playerIndex) + } + func updateOverlay(overlayInfo: OverlayInfo) { - playerView?.updateOverlay(score: overlayInfo.score) + playerViews[0]?.updateOverlay(score: overlayInfo.score) } - /// Set ups the views for a single player game. - func createSinglePlayerView(at superview: UIView) { - let playerView = PlayerView.createPlayerView(superview: superview, device: self.device) - playerView.setControlViewDelegate(self) - playerView.setDrawDelegate(self) - self.playerView = playerView + private func playerIndex(from mtkView: MTKView) -> Int? { + for i in 0.. PlayerView { - let playerView = PlayerView(superview: superview, device: device) + static func createPlayerView(layout: PlayerViewLayout, device: MTLDevice) -> PlayerView { + let playerView = PlayerView(superview: layout.superview, device: device) playerView.setupSubviews() return playerView } diff --git a/star-dash/star-dash/Rendering/Utils/LayoutUtils.swift b/star-dash/star-dash/Rendering/Utils/LayoutUtils.swift new file mode 100644 index 00000000..7a43bd01 --- /dev/null +++ b/star-dash/star-dash/Rendering/Utils/LayoutUtils.swift @@ -0,0 +1,52 @@ +class LayoutUtils { + + static func layoutViews(superview: UIView, for numberOfPlayers: Int) -> [PlayerViewLayout]? { + let layouts: [Int: (UIView) -> [PlayerViewLayout]] = [ + 1: createLayoutForSinglePlayer + ] + + guard let layoutMethod = layouts[numberOfPlayers]? else { + return nil + } + + return layoutMethod(superview) + } + + static func createLayoutForSinglePlayer(superview: UIView) -> [PlayerViewLayout] { + [PlayerViewLayout( + superview: superview, + rotation: 0 + )] + } + + static func createLayoutForTwoPlayers(superview: UIView) -> [PlayerViewLayout] { + let player1View = UIView() + let player2View = UIView() + + superview.addSubview(player1View) + superview.addSubview(player2View) + + // Add constraints to place them side by side + player1View.translatesAutoresizingMaskIntoConstraints = false + player2View.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + player1View.leadingAnchor.constraint(equalTo: superview.leadingAnchor), + player1View.topAnchor.constraint(equalTo: superview.topAnchor), + player1View.bottomAnchor.constraint(equalTo: superview.bottomAnchor), + player1View.widthAnchor.constraint(equalTo: superview.widthAnchor, multiplier: 0.5) + ]) + + NSLayoutConstraint.activate([ + player2View.leadingAnchor.constraint(equalTo: user1View.trailingAnchor), + player2View.trailingAnchor.constraint(equalTo: parentView.trailingAnchor), + player2View.topAnchor.constraint(equalTo: parentView.topAnchor), + player2View.bottomAnchor.constraint(equalTo: parentView.bottomAnchor) + ]) + + return [ + PlayerViewLayout(superview: player1View, rotation: 0), + PlayerViewLayout(superview: player2View, rotation: 0) + ] + } +} \ No newline at end of file diff --git a/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift b/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift new file mode 100644 index 00000000..cfc1db8e --- /dev/null +++ b/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift @@ -0,0 +1,4 @@ +struct PlayerViewLayout { + let superview: UIView + let rotation: Float +} \ No newline at end of file diff --git a/star-dash/star-dash/ViewController.swift b/star-dash/star-dash/ViewController.swift index 9f9b5cf9..a24cbe2c 100644 --- a/star-dash/star-dash/ViewController.swift +++ b/star-dash/star-dash/ViewController.swift @@ -33,7 +33,7 @@ class ViewController: UIViewController { } renderer.viewDelegate = self - renderer.createSinglePlayerView(at: self.view) + renderer.setupViews(at: self.view, for: 1) self.renderer = renderer } @@ -43,10 +43,6 @@ class ViewController: UIViewController { return } - let camera = SDCameraObject() - camera.position = CGPoint(x: scene.size.width / 2, y: scene.size.height / 2) - scene.addCameraObject(camera) - let background = SDSpriteObject(imageNamed: "GameBackground") background.position = CGPoint(x: scene.size.width / 2, y: scene.size.height / 2) background.zPosition = -1 From a590b0289334dcccc6084ab4df2b079082c64687 Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Tue, 26 Mar 2024 22:33:59 +0800 Subject: [PATCH 03/13] fix: Fix syntax issues --- .../Sources/SDPhysicsEngine/GameScene.swift | 10 ++++++--- .../Object/SDCameraObject.swift | 10 ++++++--- .../Sources/SDPhysicsEngine/SDScene.swift | 3 +-- star-dash/star-dash.xcodeproj/project.pbxproj | 18 ++++++++++++++- .../star-dash/GameBridge/GameBridge.swift | 2 +- .../Rendering/MTKRenderer/MTKRenderer.swift | 19 +++++----------- .../Rendering/MTKRenderer/PlayerView.swift | 2 +- star-dash/star-dash/Rendering/Renderer.swift | 2 +- .../Rendering/Utils/LayoutUtils.swift | 22 ++++++++++--------- .../Rendering/Utils/PlayerViewLayout.swift | 4 +++- star-dash/star-dash/ViewController.swift | 8 ------- 11 files changed, 56 insertions(+), 44 deletions(-) diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift index ff1d3b9f..fdc52eaf 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift @@ -8,7 +8,7 @@ public class GameScene: SKScene { private var objectMap: [SKNode: SDObject] = [:] - private cameraPlayerMap: [Int: SDCameraObject] + private var cameraPlayerMap: [Int: SDCameraObject] = [:] override public func sceneDidLoad() { super.sceneDidLoad() @@ -36,8 +36,12 @@ public class GameScene: SKScene { } } - func camera(of playerIndex: Int) -> SKCameraNode? { - cameraPlayerMap[playerIndex]?.node + public func useCamera(of playerIndex: Int) { + guard let cameraObject = cameraPlayerMap[playerIndex] else { + return + } + + self.camera = cameraObject.cameraNode } } diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift index 47ff22e1..6c944fe4 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift @@ -2,20 +2,24 @@ import SpriteKit public class SDCameraObject: SDObject { let cameraNode: SKCameraNode - let player: SKObject? + let player: SKNode? override public init() { + player = nil cameraNode = SKCameraNode() super.init(node: cameraNode) } - init(player: SKObject) { + init(player: SKNode) { self.player = player cameraNode = SKCameraNode() super.init(node: cameraNode) } - update() { + func update() { + guard let player = self.player else { + return + } self.position = player.position } } diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift index 893c9312..6e72bd0e 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift @@ -4,8 +4,7 @@ public protocol SDScene { var size: CGSize { get } + func addPlayerObject(_ playerObject: SDObject) func addObject(_ object: SDObject) func removeObject(_ object: SDObject) - func addCameraObject(_ cameraObject: SDCameraObject) - func setCameraObjectXPosition(to x: CGFloat) } diff --git a/star-dash/star-dash.xcodeproj/project.pbxproj b/star-dash/star-dash.xcodeproj/project.pbxproj index 683ff93c..fe354ed8 100644 --- a/star-dash/star-dash.xcodeproj/project.pbxproj +++ b/star-dash/star-dash.xcodeproj/project.pbxproj @@ -108,6 +108,8 @@ E69FDDE42BADC2F10089D5F3 /* SpriteConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDE32BADC2F10089D5F3 /* SpriteConstants.swift */; }; E69FDDE62BADD11B0089D5F3 /* StopMovingEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDE52BADD11B0089D5F3 /* StopMovingEvent.swift */; }; E6A011172BA5F4AD006904D9 /* EntitySyncInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A011162BA5F4AD006904D9 /* EntitySyncInterface.swift */; }; + E6A72FC52BB2E1E10015729E /* PlayerViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A72FC32BB2E1E10015729E /* PlayerViewLayout.swift */; }; + E6A72FC62BB2E1E10015729E /* LayoutUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A72FC42BB2E1E10015729E /* LayoutUtils.swift */; }; E6A745162BA057040080C1BE /* MTKRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745112BA057040080C1BE /* MTKRenderer.swift */; }; E6A745172BA057040080C1BE /* ControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745122BA057040080C1BE /* ControlView.swift */; }; E6A745182BA057040080C1BE /* Renderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745132BA057040080C1BE /* Renderer.swift */; }; @@ -256,6 +258,8 @@ E69FDDE32BADC2F10089D5F3 /* SpriteConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpriteConstants.swift; sourceTree = ""; }; E69FDDE52BADD11B0089D5F3 /* StopMovingEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StopMovingEvent.swift; sourceTree = ""; }; E6A011162BA5F4AD006904D9 /* EntitySyncInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntitySyncInterface.swift; sourceTree = ""; }; + E6A72FC32BB2E1E10015729E /* PlayerViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlayerViewLayout.swift; sourceTree = ""; }; + E6A72FC42BB2E1E10015729E /* LayoutUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutUtils.swift; sourceTree = ""; }; E6A745112BA057040080C1BE /* MTKRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTKRenderer.swift; sourceTree = ""; }; E6A745122BA057040080C1BE /* ControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlView.swift; sourceTree = ""; }; E6A745132BA057040080C1BE /* Renderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Renderer.swift; sourceTree = ""; }; @@ -618,11 +622,21 @@ path = GameBridge; sourceTree = ""; }; + E6A72FC22BB2E1E10015729E /* Utils */ = { + isa = PBXGroup; + children = ( + E6A72FC32BB2E1E10015729E /* PlayerViewLayout.swift */, + E6A72FC42BB2E1E10015729E /* LayoutUtils.swift */, + ); + path = Utils; + sourceTree = ""; + }; E6A745102BA057040080C1BE /* Rendering */ = { isa = PBXGroup; children = ( - E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */, + E6A72FC22BB2E1E10015729E /* Utils */, E6B5509F2BA15D2000DC7396 /* MTKRenderer */, + E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */, E6A745132BA057040080C1BE /* Renderer.swift */, E6B0AAD02BAAE3DC009CB939 /* ViewDelegate.swift */, E6B0AAD22BAAE438009CB939 /* ControlViewDelegate.swift */, @@ -838,6 +852,7 @@ 4E86605F2BA095E30035530D /* Collectible.swift in Sources */, E64361122BA4C2CD003850FD /* ObjectModule.swift in Sources */, 4E59E2532BAB3061007B3FA7 /* Database.swift in Sources */, + E6A72FC52BB2E1E10015729E /* PlayerViewLayout.swift in Sources */, 4E8660662BA097D40035530D /* PhysicsConstants.swift in Sources */, 143AA3952BA4DF1C009C28E7 /* MonsterAttackPlayerEvent.swift in Sources */, 143AA3932BA4DBE7009C28E7 /* PlayerMonsterContactEvent.swift in Sources */, @@ -879,6 +894,7 @@ E64361142BA4C2CD003850FD /* CreationModule.swift in Sources */, 4E59E2612BAB42FD007B3FA7 /* LevelPersistable.swift in Sources */, 460A200B2BB1D04F002597B8 /* AttackSystem.swift in Sources */, + E6A72FC62BB2E1E10015729E /* LayoutUtils.swift in Sources */, E6A745162BA057040080C1BE /* MTKRenderer.swift in Sources */, E6A745182BA057040080C1BE /* Renderer.swift in Sources */, 4E59E25F2BAB4134007B3FA7 /* EntityType.swift in Sources */, diff --git a/star-dash/star-dash/GameBridge/GameBridge.swift b/star-dash/star-dash/GameBridge/GameBridge.swift index 6307781d..78f2268c 100644 --- a/star-dash/star-dash/GameBridge/GameBridge.swift +++ b/star-dash/star-dash/GameBridge/GameBridge.swift @@ -85,7 +85,7 @@ class GameBridge { $0.create(for: newObject, from: entity) } - if type(of: entity) == PlayerEntity.self { + if type(of: entity) == Player.self { self.scene.addPlayerObject(newObject) } else { self.scene.addObject(newObject) diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index 4a48bd46..70cb96c5 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -21,7 +21,7 @@ class MTKRenderer: NSObject, Renderer { var viewDelegate: ViewDelegate? - init?(scene: GameScene, numberOfPlayers) { + init?(scene: GameScene) { self.scene = scene guard let device = MTLCreateSystemDefaultDevice(), @@ -50,20 +50,12 @@ class MTKRenderer: NSObject, Renderer { } } - func camera(of view: MTKView) -> SKCameraNode? { - guard let playerIndex = playerIndex(from: view) { - return nil - } - - return self.scene.camera(of: playerIndex) - } - func updateOverlay(overlayInfo: OverlayInfo) { - playerViews[0]?.updateOverlay(score: overlayInfo.score) + playerViews[0].updateOverlay(score: overlayInfo.score) } private func playerIndex(from mtkView: MTKView) -> Int? { - for i in 0.. [PlayerViewLayout]? { @@ -5,7 +7,7 @@ class LayoutUtils { 1: createLayoutForSinglePlayer ] - guard let layoutMethod = layouts[numberOfPlayers]? else { + guard let layoutMethod = layouts[numberOfPlayers] else { return nil } @@ -22,26 +24,26 @@ class LayoutUtils { static func createLayoutForTwoPlayers(superview: UIView) -> [PlayerViewLayout] { let player1View = UIView() let player2View = UIView() - + superview.addSubview(player1View) superview.addSubview(player2View) - + // Add constraints to place them side by side player1View.translatesAutoresizingMaskIntoConstraints = false player2View.translatesAutoresizingMaskIntoConstraints = false - + NSLayoutConstraint.activate([ player1View.leadingAnchor.constraint(equalTo: superview.leadingAnchor), player1View.topAnchor.constraint(equalTo: superview.topAnchor), player1View.bottomAnchor.constraint(equalTo: superview.bottomAnchor), player1View.widthAnchor.constraint(equalTo: superview.widthAnchor, multiplier: 0.5) ]) - + NSLayoutConstraint.activate([ - player2View.leadingAnchor.constraint(equalTo: user1View.trailingAnchor), - player2View.trailingAnchor.constraint(equalTo: parentView.trailingAnchor), - player2View.topAnchor.constraint(equalTo: parentView.topAnchor), - player2View.bottomAnchor.constraint(equalTo: parentView.bottomAnchor) + player2View.leadingAnchor.constraint(equalTo: player1View.trailingAnchor), + player2View.trailingAnchor.constraint(equalTo: superview.trailingAnchor), + player2View.topAnchor.constraint(equalTo: superview.topAnchor), + player2View.bottomAnchor.constraint(equalTo: superview.bottomAnchor) ]) return [ @@ -49,4 +51,4 @@ class LayoutUtils { PlayerViewLayout(superview: player2View, rotation: 0) ] } -} \ No newline at end of file +} diff --git a/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift b/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift index cfc1db8e..69c7e7bb 100644 --- a/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift +++ b/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift @@ -1,4 +1,6 @@ +import UIKit + struct PlayerViewLayout { let superview: UIView let rotation: Float -} \ No newline at end of file +} diff --git a/star-dash/star-dash/ViewController.swift b/star-dash/star-dash/ViewController.swift index a24cbe2c..bc5bbd8b 100644 --- a/star-dash/star-dash/ViewController.swift +++ b/star-dash/star-dash/ViewController.swift @@ -80,17 +80,9 @@ extension ViewController: SDSceneDelegate { gameEngine?.update(by: deltaTime) gameBridge?.syncFromEntities() - updateCameraObjectPosition(scene) updateOverlay() } - private func updateCameraObjectPosition(_ scene: SDScene) { - guard let playerPosition = gameEngine?.playerPosition() else { - return - } - scene.setCameraObjectXPosition(to: playerPosition.x) - } - private func updateOverlay() { guard let gameInfo = gameEngine?.gameInfo() else { return From f94f494292bea58bd55ff1ec43b6228addbb839d Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Wed, 27 Mar 2024 13:49:35 +0800 Subject: [PATCH 04/13] chore: Connect controls to player entities --- .../GameEngine/Entities/EntityManager.swift | 9 ++++--- .../star-dash/GameEngine/GameEngine.swift | 12 ++++----- .../Rendering/ControlViewDelegate.swift | 6 ++--- .../Rendering/MTKRenderer/MTKRenderer.swift | 26 ++++++++++++++++--- .../star-dash/Rendering/ViewDelegate.swift | 6 ++--- star-dash/star-dash/ViewController.swift | 12 ++++----- 6 files changed, 47 insertions(+), 24 deletions(-) diff --git a/star-dash/star-dash/GameEngine/Entities/EntityManager.swift b/star-dash/star-dash/GameEngine/Entities/EntityManager.swift index eb45f234..8346f1a1 100644 --- a/star-dash/star-dash/GameEngine/Entities/EntityManager.swift +++ b/star-dash/star-dash/GameEngine/Entities/EntityManager.swift @@ -58,10 +58,13 @@ class EntityManager { entityMap[entityId] } - func playerEntityId() -> EntityId? { + func playerEntityId(with: playerIndex) -> EntityId? { // TODO: Add parameter to specify the player index - for entityId in entityMap.keys where component(ofType: PlayerComponent.self, of: entityId) != nil { - return entityId + for entityId in entityMap.keys { + if let playerComponent = component(ofType: PlayerComponent.self, of: entityId), + playerComponent.playerIndex == playerIndex { + return entityId + } } return nil diff --git a/star-dash/star-dash/GameEngine/GameEngine.swift b/star-dash/star-dash/GameEngine/GameEngine.swift index 5acf3caa..7c817658 100644 --- a/star-dash/star-dash/GameEngine/GameEngine.swift +++ b/star-dash/star-dash/GameEngine/GameEngine.swift @@ -47,16 +47,16 @@ class GameEngine { eventManager.add(event: event) } - func handlePlayerJump() { - guard let playerEntityId = entityManager.playerEntityId() else { + func handlePlayerJump(playerIndex: playerIndex) { + guard let playerEntityId = entityManager.playerEntityId(with: playerIndex) else { return } eventManager.add(event: JumpEvent(on: playerEntityId, by: PhysicsConstants.jumpImpulse)) } - func handlePlayerMove(toLeft: Bool) { - guard let playerEntityId = entityManager.playerEntityId(), + func handlePlayerMove(toLeft: Bool, playerIndex: playerIndex) { + guard let playerEntityId = entityManager.playerEntityId(with: playerIndex), let playerComponent = entityManager.component(ofType: PlayerComponent.self, of: playerEntityId), playerComponent.canMove else { return @@ -65,8 +65,8 @@ class GameEngine { eventManager.add(event: MoveEvent(on: playerEntityId, toLeft: toLeft)) } - func handlePlayerStoppedMoving() { - guard let playerEntityId = entityManager.playerEntityId() else { + func handlePlayerStoppedMoving(playerIndex: playerIndex) { + guard let playerEntityId = entityManager.playerEntityId(with: playerIndex) else { return } diff --git a/star-dash/star-dash/Rendering/ControlViewDelegate.swift b/star-dash/star-dash/Rendering/ControlViewDelegate.swift index 0184c992..65c57091 100644 --- a/star-dash/star-dash/Rendering/ControlViewDelegate.swift +++ b/star-dash/star-dash/Rendering/ControlViewDelegate.swift @@ -1,6 +1,6 @@ protocol ControlViewDelegate: AnyObject { - func joystickMoved(toLeft: Bool) - func joystickReleased() - func jumpButtonPressed() + func joystickMoved(toLeft: Bool, from view: ControlView) + func joystickReleased(from view: ControlView) + func jumpButtonPressed(from view: ControlView) } diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index 70cb96c5..38cd30df 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -61,6 +61,14 @@ class MTKRenderer: NSObject, Renderer { return nil } + + private func playerIndex(from controlView: ControlView) -> Int? { + for i in 0.. Date: Wed, 27 Mar 2024 12:17:35 +0800 Subject: [PATCH 05/13] feat: Rendering for two players --- .../Sources/SDPhysicsEngine/GameScene.swift | 7 +++-- .../Object/SDCameraObject.swift | 9 ++++-- star-dash/star-dash.xcodeproj/project.pbxproj | 4 +++ star-dash/star-dash/Extensions/UIVIew.swift | 9 ++++++ .../Rendering/MTKRenderer/ControlView.swift | 6 ++-- .../Rendering/MTKRenderer/MTKRenderer.swift | 2 +- .../Rendering/MTKRenderer/PlayerView.swift | 18 ++++++++--- .../Rendering/Utils/LayoutUtils.swift | 31 ++++++------------- .../Rendering/Utils/PlayerViewLayout.swift | 2 +- star-dash/star-dash/ViewController.swift | 9 +++++- 10 files changed, 61 insertions(+), 36 deletions(-) create mode 100644 star-dash/star-dash/Extensions/UIVIew.swift diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift index fdc52eaf..960f0b60 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift @@ -36,18 +36,21 @@ public class GameScene: SKScene { } } - public func useCamera(of playerIndex: Int) { + public func useCamera(of playerIndex: Int, rotatedBy rotation: CGFloat) { guard let cameraObject = cameraPlayerMap[playerIndex] else { return } + cameraObject.zRotation = rotation self.camera = cameraObject.cameraNode } } extension GameScene: SDScene { public func addPlayerObject(_ playerObject: SDObject) { - let camera = SDCameraObject() + let camera = SDCameraObject(player: playerObject) + cameraPlayerMap[cameraPlayerMap.count] = camera + addObject(camera) addObject(playerObject) } diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift index 6c944fe4..86574d82 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift @@ -2,7 +2,7 @@ import SpriteKit public class SDCameraObject: SDObject { let cameraNode: SKCameraNode - let player: SKNode? + let player: SDObject? override public init() { player = nil @@ -10,11 +10,16 @@ public class SDCameraObject: SDObject { super.init(node: cameraNode) } - init(player: SKNode) { + init(player: SDObject) { self.player = player cameraNode = SKCameraNode() super.init(node: cameraNode) } + + var zRotation: CGFloat { + get { cameraNode.zRotation } + set { cameraNode.zRotation = newValue } + } func update() { guard let player = self.player else { diff --git a/star-dash/star-dash.xcodeproj/project.pbxproj b/star-dash/star-dash.xcodeproj/project.pbxproj index f481f76d..b8df1015 100644 --- a/star-dash/star-dash.xcodeproj/project.pbxproj +++ b/star-dash/star-dash.xcodeproj/project.pbxproj @@ -103,6 +103,7 @@ E64361132BA4C2CD003850FD /* PhysicsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610D2BA4C2CC003850FD /* PhysicsModule.swift */; }; E64361142BA4C2CD003850FD /* CreationModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610E2BA4C2CC003850FD /* CreationModule.swift */; }; E64361152BA4C2CD003850FD /* GameBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610F2BA4C2CC003850FD /* GameBridge.swift */; }; + E64F31672BB3D14600EC5371 /* UIVIew.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64F31662BB3D14600EC5371 /* UIVIew.swift */; }; E69EE9322BAC6CBB00033AB5 /* GameInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */; }; E69EE9342BAC6CC300033AB5 /* OverlayInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */; }; E69FDDE02BAD3DAD0089D5F3 /* PointsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */; }; @@ -255,6 +256,7 @@ E643610D2BA4C2CC003850FD /* PhysicsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsModule.swift; sourceTree = ""; }; E643610E2BA4C2CC003850FD /* CreationModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreationModule.swift; sourceTree = ""; }; E643610F2BA4C2CC003850FD /* GameBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameBridge.swift; sourceTree = ""; }; + E64F31662BB3D14600EC5371 /* UIVIew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIVIew.swift; sourceTree = ""; }; E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameInfo.swift; sourceTree = ""; }; E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverlayInfo.swift; sourceTree = ""; }; E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PointsComponent.swift; sourceTree = ""; }; @@ -309,6 +311,7 @@ isa = PBXGroup; children = ( 143AA38E2BA4D61A009C28E7 /* CGVector.swift */, + E64F31662BB3D14600EC5371 /* UIVIew.swift */, ); path = Extensions; sourceTree = ""; @@ -921,6 +924,7 @@ 4E630F372B9F91DE0008F887 /* PlayerSprite.swift in Sources */, 14970F502BA814D500CC1E8A /* ScoreComponent.swift in Sources */, E69FDDE42BADC2F10089D5F3 /* SpriteConstants.swift in Sources */, + E64F31672BB3D14600EC5371 /* UIVIew.swift in Sources */, 143AA3912BA4D7AC009C28E7 /* MonsterDeathEvent.swift in Sources */, E64361102BA4C2CD003850FD /* SpriteModule.swift in Sources */, 4604BBD52BA819C70078B84C /* InventoryComponent.swift in Sources */, diff --git a/star-dash/star-dash/Extensions/UIVIew.swift b/star-dash/star-dash/Extensions/UIVIew.swift new file mode 100644 index 00000000..6ad48311 --- /dev/null +++ b/star-dash/star-dash/Extensions/UIVIew.swift @@ -0,0 +1,9 @@ +import UIKit + +extension UIView { + convenience init(frame: CGRect, rotatedBy rotation: CGFloat) { + self.init(frame: frame.applying(CGAffineTransform(rotationAngle: rotation))) + self.transform = CGAffineTransform(rotationAngle: rotation) + self.center = CGPoint(x: frame.midX, y: frame.midY) + } +} diff --git a/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift b/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift index 1de39e27..4dbb6218 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift @@ -24,7 +24,7 @@ class ControlView: UIView { // MARK: Private methods for setup private func setupMovementControls() { - let joystickY = frame.height - buttonSize - buttonMargin + let joystickY = bounds.height - buttonSize - buttonMargin let joystickView = JoystickView(frame: CGRect( x: buttonMargin, y: joystickY, @@ -40,8 +40,8 @@ class ControlView: UIView { private func setupActionControls() { let jumpButton = UIButton(type: .custom) - let buttonX = frame.width - buttonSize - buttonMargin - let buttonY = frame.height - buttonSize - buttonMargin + let buttonX = bounds.width - buttonSize - buttonMargin + let buttonY = bounds.height - buttonSize - buttonMargin jumpButton.frame = CGRect(x: buttonX, y: buttonY, width: buttonSize, height: buttonSize) jumpButton.addTarget(self, action: #selector(jumpButtonTapped), for: .touchUpInside) diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index 38cd30df..99887992 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -86,7 +86,7 @@ extension MTKRenderer: MTKViewDelegate { let viewport = CGRect(x: 0, y: 0, width: view.drawableSize.width, height: view.drawableSize.height) renderer.update(atTime: CACurrentMediaTime()) - scene.useCamera(of: playerIndex) + scene.useCamera(of: playerIndex, rotatedBy: playerViews[playerIndex].rotation) renderer.render( withViewport: viewport, commandBuffer: commandBuffer, diff --git a/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift b/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift index d317fac7..d940b2a9 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift @@ -1,5 +1,6 @@ import UIKit import MetalKit +import CoreGraphics /** `PlayerView` is responsible for creating and coordinating the views @@ -11,18 +12,25 @@ import MetalKit 3. Overlay View: The game overlay to show information such as points */ class PlayerView { + let superview: UIView + var sceneView: MTKView var controlView: ControlView var overlayView: OverlayView - private init(superview: UIView, device: MTLDevice) { - self.sceneView = MTKView(frame: superview.frame, device: device) + let rotation: CGFloat + + private init(superview: UIView, rotation: CGFloat, device: MTLDevice) { + self.rotation = rotation + self.superview = superview + + self.sceneView = MTKView(frame: superview.bounds, device: device) superview.addSubview(self.sceneView) - self.overlayView = OverlayView(frame: superview.frame) + self.overlayView = OverlayView(frame: superview.bounds, rotatedBy: rotation) superview.addSubview(self.overlayView) - self.controlView = ControlView(frame: superview.frame) + self.controlView = ControlView(frame: superview.bounds, rotatedBy: rotation) superview.addSubview(self.controlView) } @@ -44,7 +52,7 @@ class PlayerView { } static func createPlayerView(layout: PlayerViewLayout, device: MTLDevice) -> PlayerView { - let playerView = PlayerView(superview: layout.superview, device: device) + let playerView = PlayerView(superview: layout.superview, rotation: layout.rotation, device: device) playerView.setupSubviews() return playerView } diff --git a/star-dash/star-dash/Rendering/Utils/LayoutUtils.swift b/star-dash/star-dash/Rendering/Utils/LayoutUtils.swift index 2cf7c349..045e28e3 100644 --- a/star-dash/star-dash/Rendering/Utils/LayoutUtils.swift +++ b/star-dash/star-dash/Rendering/Utils/LayoutUtils.swift @@ -1,10 +1,11 @@ import UIKit class LayoutUtils { - + static func layoutViews(superview: UIView, for numberOfPlayers: Int) -> [PlayerViewLayout]? { let layouts: [Int: (UIView) -> [PlayerViewLayout]] = [ - 1: createLayoutForSinglePlayer + 1: createLayoutForSinglePlayer, + 2: createLayoutForTwoPlayers ] guard let layoutMethod = layouts[numberOfPlayers] else { @@ -28,27 +29,15 @@ class LayoutUtils { superview.addSubview(player1View) superview.addSubview(player2View) - // Add constraints to place them side by side - player1View.translatesAutoresizingMaskIntoConstraints = false - player2View.translatesAutoresizingMaskIntoConstraints = false - - NSLayoutConstraint.activate([ - player1View.leadingAnchor.constraint(equalTo: superview.leadingAnchor), - player1View.topAnchor.constraint(equalTo: superview.topAnchor), - player1View.bottomAnchor.constraint(equalTo: superview.bottomAnchor), - player1View.widthAnchor.constraint(equalTo: superview.widthAnchor, multiplier: 0.5) - ]) - - NSLayoutConstraint.activate([ - player2View.leadingAnchor.constraint(equalTo: player1View.trailingAnchor), - player2View.trailingAnchor.constraint(equalTo: superview.trailingAnchor), - player2View.topAnchor.constraint(equalTo: superview.topAnchor), - player2View.bottomAnchor.constraint(equalTo: superview.bottomAnchor) - ]) + player1View.frame = CGRect(x: 0, y: 0, width: superview.frame.width / 2, height: superview.frame.height) + player2View.frame = CGRect(x: superview.frame.width / 2, + y: 0, + width: superview.frame.width / 2, + height: superview.frame.height) return [ - PlayerViewLayout(superview: player1View, rotation: 0), - PlayerViewLayout(superview: player2View, rotation: 0) + PlayerViewLayout(superview: player1View, rotation: .pi / 2), + PlayerViewLayout(superview: player2View, rotation: .pi * 3 / 2) ] } } diff --git a/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift b/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift index 69c7e7bb..4ecaa92f 100644 --- a/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift +++ b/star-dash/star-dash/Rendering/Utils/PlayerViewLayout.swift @@ -2,5 +2,5 @@ import UIKit struct PlayerViewLayout { let superview: UIView - let rotation: Float + let rotation: CGFloat } diff --git a/star-dash/star-dash/ViewController.swift b/star-dash/star-dash/ViewController.swift index eaf7a495..a47badbe 100644 --- a/star-dash/star-dash/ViewController.swift +++ b/star-dash/star-dash/ViewController.swift @@ -33,7 +33,7 @@ class ViewController: UIViewController { } renderer.viewDelegate = self - renderer.setupViews(at: self.view, for: 1) + renderer.setupViews(at: self.view, for: 2) self.renderer = renderer } @@ -55,6 +55,13 @@ class ViewController: UIViewController { ) player.setUpAndAdd(to: entityManager) + let player2 = Player( + playerIndex: 0, + position: CGPoint(x: scene.size.width / 2 + 25, y: scene.size.height / 2 + 200), + playerSprite: PlayerSprite.RedNose + ) + player2.setUpAndAdd(to: entityManager) + let floor = Floor(position: CGPoint(x: scene.size.width / 2, y: scene.size.height / 2 - 400)) floor.setUpAndAdd(to: entityManager) From ba97169d70d462113e1fa49c070c575c1dd11964 Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:00:27 +0800 Subject: [PATCH 06/13] fix: Fix syntax issues --- .../Sources/SDPhysicsEngine/GameScene.swift | 4 ++-- .../Sources/SDPhysicsEngine/SDScene.swift | 2 +- .../star-dash/Constants/PhysicsConstants.swift | 2 +- star-dash/star-dash/GameBridge/GameBridge.swift | 4 +++- .../GameEngine/Entities/EntityManager.swift | 4 ++-- star-dash/star-dash/GameEngine/GameEngine.swift | 16 ++++------------ .../Rendering/MTKRenderer/ControlView.swift | 10 +++++----- .../Rendering/MTKRenderer/MTKRenderer.swift | 6 +++--- star-dash/star-dash/ViewController.swift | 2 +- 9 files changed, 22 insertions(+), 28 deletions(-) diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift index 960f0b60..5b9e1d9c 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift @@ -47,9 +47,9 @@ public class GameScene: SKScene { } extension GameScene: SDScene { - public func addPlayerObject(_ playerObject: SDObject) { + public func addPlayerObject(_ playerObject: SDObject, playerIndex: Int) { let camera = SDCameraObject(player: playerObject) - cameraPlayerMap[cameraPlayerMap.count] = camera + cameraPlayerMap[playerIndex] = camera addObject(camera) addObject(playerObject) diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift index 6e72bd0e..cd1efa90 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift @@ -4,7 +4,7 @@ public protocol SDScene { var size: CGSize { get } - func addPlayerObject(_ playerObject: SDObject) + func addPlayerObject(_ playerObject: SDObject, playerIndex: Int) func addObject(_ object: SDObject) func removeObject(_ object: SDObject) } diff --git a/star-dash/star-dash/Constants/PhysicsConstants.swift b/star-dash/star-dash/Constants/PhysicsConstants.swift index ece5112b..8ba2679f 100644 --- a/star-dash/star-dash/Constants/PhysicsConstants.swift +++ b/star-dash/star-dash/Constants/PhysicsConstants.swift @@ -52,6 +52,6 @@ struct PhysicsConstants { } static let jumpImpulse = CGVector(dx: 15, dy: 250) - static let runVelocity = CGVector(dx: 15, dy: 0) + static let runVelocity = CGVector(dx: 60, dy: 0) static let maxRunVelocity = CGVector(dx: 250, dy: 0) } diff --git a/star-dash/star-dash/GameBridge/GameBridge.swift b/star-dash/star-dash/GameBridge/GameBridge.swift index 556b2086..e5cca642 100644 --- a/star-dash/star-dash/GameBridge/GameBridge.swift +++ b/star-dash/star-dash/GameBridge/GameBridge.swift @@ -87,7 +87,9 @@ class GameBridge { } if type(of: entity) == Player.self { - self.scene.addPlayerObject(newObject) + if let playerIndex = entityManager.component(ofType: PlayerComponent.self, of: entity.id)?.playerIndex { + self.scene.addPlayerObject(newObject, playerIndex: playerIndex) + } } else { self.scene.addObject(newObject) } diff --git a/star-dash/star-dash/GameEngine/Entities/EntityManager.swift b/star-dash/star-dash/GameEngine/Entities/EntityManager.swift index 8346f1a1..ed4c42d2 100644 --- a/star-dash/star-dash/GameEngine/Entities/EntityManager.swift +++ b/star-dash/star-dash/GameEngine/Entities/EntityManager.swift @@ -58,8 +58,8 @@ class EntityManager { entityMap[entityId] } - func playerEntityId(with: playerIndex) -> EntityId? { - // TODO: Add parameter to specify the player index + func playerEntityId(with playerIndex: Int) -> EntityId? { + // TODO: Add parameter to specify the player index for entityId in entityMap.keys { if let playerComponent = component(ofType: PlayerComponent.self, of: entityId), playerComponent.playerIndex == playerIndex { diff --git a/star-dash/star-dash/GameEngine/GameEngine.swift b/star-dash/star-dash/GameEngine/GameEngine.swift index 7c817658..76834f48 100644 --- a/star-dash/star-dash/GameEngine/GameEngine.swift +++ b/star-dash/star-dash/GameEngine/GameEngine.swift @@ -22,7 +22,7 @@ class GameEngine { func gameInfo() -> GameInfo? { guard let scoreSystem = systemManager.system(ofType: ScoreSystem.self), - let playerEntityId = entityManager.playerEntityId(), + let playerEntityId = entityManager.playerEntityId(with: 0), let score = scoreSystem.score(of: playerEntityId) else { return nil } @@ -47,7 +47,7 @@ class GameEngine { eventManager.add(event: event) } - func handlePlayerJump(playerIndex: playerIndex) { + func handlePlayerJump(playerIndex: Int) { guard let playerEntityId = entityManager.playerEntityId(with: playerIndex) else { return } @@ -55,7 +55,7 @@ class GameEngine { eventManager.add(event: JumpEvent(on: playerEntityId, by: PhysicsConstants.jumpImpulse)) } - func handlePlayerMove(toLeft: Bool, playerIndex: playerIndex) { + func handlePlayerMove(toLeft: Bool, playerIndex: Int) { guard let playerEntityId = entityManager.playerEntityId(with: playerIndex), let playerComponent = entityManager.component(ofType: PlayerComponent.self, of: playerEntityId), playerComponent.canMove else { @@ -65,7 +65,7 @@ class GameEngine { eventManager.add(event: MoveEvent(on: playerEntityId, toLeft: toLeft)) } - func handlePlayerStoppedMoving(playerIndex: playerIndex) { + func handlePlayerStoppedMoving(playerIndex: Int) { guard let playerEntityId = entityManager.playerEntityId(with: playerIndex) else { return } @@ -73,14 +73,6 @@ class GameEngine { eventManager.add(event: StopMovingEvent(on: playerEntityId)) } - func playerPosition() -> CGPoint? { - guard let playerEntityId = entityManager.playerEntityId(), - let positionComponent = entityManager.component(ofType: PositionComponent.self, of: playerEntityId) else { - return nil - } - return positionComponent.position - } - private func setUpSystems() { systemManager.add(PositionSystem(entityManager, dispatcher: self)) systemManager.add(PhysicsSystem(entityManager, dispatcher: self)) diff --git a/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift b/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift index 4dbb6218..e2ba34e0 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift @@ -62,7 +62,7 @@ class ControlView: UIView { @objc func jumpButtonTapped() { - controlViewDelegate?.jumpButtonPressed() + controlViewDelegate?.jumpButtonPressed(from: self) } override func touchesBegan(_ touches: Set, with event: UIEvent?) { @@ -80,7 +80,7 @@ class ControlView: UIView { // controlViewDelegate?.joystickMoved(toLeft: isLeft) // } let isLeft = firstTouch.location(in: joystickView).x < joystickView.center.x - controlViewDelegate?.joystickMoved(toLeft: isLeft) + controlViewDelegate?.joystickMoved(toLeft: isLeft, from: self) joystickView.moveJoystick(location: firstTouch.location(in: joystickView)) } @@ -93,7 +93,7 @@ class ControlView: UIView { return } - controlViewDelegate?.joystickReleased() + controlViewDelegate?.joystickReleased(from: self) joystickView?.returnJoystick() } @@ -105,7 +105,7 @@ class ControlView: UIView { let location = gesture.location(in: self) if gesture.state == .ended { - controlViewDelegate?.joystickReleased() + controlViewDelegate?.joystickReleased(from: self) joystickView.returnJoystick() return } @@ -114,7 +114,7 @@ class ControlView: UIView { joystickView.moveJoystick(location: gesture.location(in: joystickView)) if shouldSendMoveEvent(location: location) { let isLeft = gesture.location(in: joystickView).x < joystickView.center.x - controlViewDelegate?.joystickMoved(toLeft: isLeft) + controlViewDelegate?.joystickMoved(toLeft: isLeft, from: self) } } } diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index 99887992..67d5fbdc 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -104,7 +104,7 @@ extension MTKRenderer: ControlViewDelegate { return } - viewDelegate?.joystickMoved(toLeft: toLeft) + viewDelegate?.joystickMoved(toLeft: toLeft, playerIndex: playerIndex) } func joystickReleased(from view: ControlView) { @@ -112,7 +112,7 @@ extension MTKRenderer: ControlViewDelegate { return } - viewDelegate?.joystickReleased() + viewDelegate?.joystickReleased(playerIndex: playerIndex) } func jumpButtonPressed(from view: ControlView) { @@ -120,6 +120,6 @@ extension MTKRenderer: ControlViewDelegate { return } - viewDelegate?.jumpButtonPressed() + viewDelegate?.jumpButtonPressed(playerIndex: playerIndex) } } diff --git a/star-dash/star-dash/ViewController.swift b/star-dash/star-dash/ViewController.swift index a47badbe..2df99a1e 100644 --- a/star-dash/star-dash/ViewController.swift +++ b/star-dash/star-dash/ViewController.swift @@ -56,7 +56,7 @@ class ViewController: UIViewController { player.setUpAndAdd(to: entityManager) let player2 = Player( - playerIndex: 0, + playerIndex: 1, position: CGPoint(x: scene.size.width / 2 + 25, y: scene.size.height / 2 + 200), playerSprite: PlayerSprite.RedNose ) From e3f65549b39595115968d463c950ff51fbc6d3a7 Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:09:13 +0800 Subject: [PATCH 07/13] fix: Fix views from updating ahead of another --- .../Rendering/MTKRenderer/MTKRenderer.swift | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index 67d5fbdc..9a07262e 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -61,7 +61,7 @@ class MTKRenderer: NSObject, Renderer { return nil } - + private func playerIndex(from controlView: ControlView) -> Int? { for i in 0.. Date: Wed, 27 Mar 2024 15:24:30 +0800 Subject: [PATCH 08/13] chore: Reorganise rendering files --- star-dash/star-dash.xcodeproj/project.pbxproj | 30 +++++++++---------- .../{MTKRenderer => }/MTKRenderer.swift | 0 .../ControlView.swift | 0 .../ControlViewDelegate.swift | 0 .../JoystickView.swift | 0 .../OverlayView.swift | 0 .../PlayerView.swift | 0 7 files changed, 15 insertions(+), 15 deletions(-) rename star-dash/star-dash/Rendering/{MTKRenderer => }/MTKRenderer.swift (100%) rename star-dash/star-dash/Rendering/{MTKRenderer => PlayerView}/ControlView.swift (100%) rename star-dash/star-dash/Rendering/{ => PlayerView}/ControlViewDelegate.swift (100%) rename star-dash/star-dash/Rendering/{MTKRenderer => PlayerView}/JoystickView.swift (100%) rename star-dash/star-dash/Rendering/{MTKRenderer => PlayerView}/OverlayView.swift (100%) rename star-dash/star-dash/Rendering/{MTKRenderer => PlayerView}/PlayerView.swift (100%) diff --git a/star-dash/star-dash.xcodeproj/project.pbxproj b/star-dash/star-dash.xcodeproj/project.pbxproj index b8df1015..95ec75d1 100644 --- a/star-dash/star-dash.xcodeproj/project.pbxproj +++ b/star-dash/star-dash.xcodeproj/project.pbxproj @@ -621,6 +621,18 @@ path = SyncModule; sourceTree = ""; }; + E64F31682BB400CB00EC5371 /* PlayerView */ = { + isa = PBXGroup; + children = ( + E6A7451A2BA0C1890080C1BE /* PlayerView.swift */, + E6A7451C2BA0CAD90080C1BE /* JoystickView.swift */, + E6A745122BA057040080C1BE /* ControlView.swift */, + E6B550A02BA15E9C00DC7396 /* OverlayView.swift */, + E6B0AAD22BAAE438009CB939 /* ControlViewDelegate.swift */, + ); + path = PlayerView; + sourceTree = ""; + }; E6A011152BA5D111006904D9 /* GameBridge */ = { isa = PBXGroup; children = ( @@ -644,11 +656,11 @@ isa = PBXGroup; children = ( E6A72FC22BB2E1E10015729E /* Utils */, - E6B5509F2BA15D2000DC7396 /* MTKRenderer */, - E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */, + E64F31682BB400CB00EC5371 /* PlayerView */, E6A745132BA057040080C1BE /* Renderer.swift */, + E6A745112BA057040080C1BE /* MTKRenderer.swift */, E6B0AAD02BAAE3DC009CB939 /* ViewDelegate.swift */, - E6B0AAD22BAAE438009CB939 /* ControlViewDelegate.swift */, + E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */, ); path = Rendering; sourceTree = ""; @@ -660,18 +672,6 @@ name = Frameworks; sourceTree = ""; }; - E6B5509F2BA15D2000DC7396 /* MTKRenderer */ = { - isa = PBXGroup; - children = ( - E6A745112BA057040080C1BE /* MTKRenderer.swift */, - E6A7451A2BA0C1890080C1BE /* PlayerView.swift */, - E6A7451C2BA0CAD90080C1BE /* JoystickView.swift */, - E6A745122BA057040080C1BE /* ControlView.swift */, - E6B550A02BA15E9C00DC7396 /* OverlayView.swift */, - ); - path = MTKRenderer; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer.swift similarity index 100% rename from star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift rename to star-dash/star-dash/Rendering/MTKRenderer.swift diff --git a/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift b/star-dash/star-dash/Rendering/PlayerView/ControlView.swift similarity index 100% rename from star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift rename to star-dash/star-dash/Rendering/PlayerView/ControlView.swift diff --git a/star-dash/star-dash/Rendering/ControlViewDelegate.swift b/star-dash/star-dash/Rendering/PlayerView/ControlViewDelegate.swift similarity index 100% rename from star-dash/star-dash/Rendering/ControlViewDelegate.swift rename to star-dash/star-dash/Rendering/PlayerView/ControlViewDelegate.swift diff --git a/star-dash/star-dash/Rendering/MTKRenderer/JoystickView.swift b/star-dash/star-dash/Rendering/PlayerView/JoystickView.swift similarity index 100% rename from star-dash/star-dash/Rendering/MTKRenderer/JoystickView.swift rename to star-dash/star-dash/Rendering/PlayerView/JoystickView.swift diff --git a/star-dash/star-dash/Rendering/MTKRenderer/OverlayView.swift b/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift similarity index 100% rename from star-dash/star-dash/Rendering/MTKRenderer/OverlayView.swift rename to star-dash/star-dash/Rendering/PlayerView/OverlayView.swift diff --git a/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift b/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift similarity index 100% rename from star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift rename to star-dash/star-dash/Rendering/PlayerView/PlayerView.swift From bc36904e273dc8d9db3b99e13debc5cb24050f65 Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:55:59 +0800 Subject: [PATCH 09/13] refactor: Refactor overlay update logic --- .../star-dash/GameEngine/GameEngine.swift | 4 ++-- .../star-dash/Rendering/MTKRenderer.swift | 9 ++++---- .../Rendering/PlayerView/OverlayView.swift | 4 ++-- .../star-dash/Rendering/ViewDelegate.swift | 1 + star-dash/star-dash/ViewController.swift | 22 +++++++++---------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/star-dash/star-dash/GameEngine/GameEngine.swift b/star-dash/star-dash/GameEngine/GameEngine.swift index 76834f48..9f3913c3 100644 --- a/star-dash/star-dash/GameEngine/GameEngine.swift +++ b/star-dash/star-dash/GameEngine/GameEngine.swift @@ -20,9 +20,9 @@ class GameEngine { setUpSystems() } - func gameInfo() -> GameInfo? { + func gameInfo(forPlayer playerIndex: Int) -> GameInfo? { guard let scoreSystem = systemManager.system(ofType: ScoreSystem.self), - let playerEntityId = entityManager.playerEntityId(with: 0), + let playerEntityId = entityManager.playerEntityId(with: playerIndex), let score = scoreSystem.score(of: playerEntityId) else { return nil } diff --git a/star-dash/star-dash/Rendering/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer.swift index 9a07262e..11e9bcbf 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer.swift @@ -50,10 +50,6 @@ class MTKRenderer: NSObject, Renderer { } } - func updateOverlay(overlayInfo: OverlayInfo) { - playerViews[0].updateOverlay(score: overlayInfo.score) - } - private func playerIndex(from mtkView: MTKView) -> Int? { for i in 0.. OverlayInfo? } diff --git a/star-dash/star-dash/ViewController.swift b/star-dash/star-dash/ViewController.swift index 2df99a1e..f0321b43 100644 --- a/star-dash/star-dash/ViewController.swift +++ b/star-dash/star-dash/ViewController.swift @@ -86,18 +86,6 @@ extension ViewController: SDSceneDelegate { gameBridge?.syncToEntities() gameEngine?.update(by: deltaTime) gameBridge?.syncFromEntities() - - updateOverlay() - } - - private func updateOverlay() { - guard let gameInfo = gameEngine?.gameInfo() else { - return - } - - renderer?.updateOverlay(overlayInfo: OverlayInfo( - score: gameInfo.playerScore - )) } func contactOccurred(objectA: SDObject, objectB: SDObject, contactPoint: CGPoint) { @@ -123,4 +111,14 @@ extension ViewController: ViewDelegate { func jumpButtonPressed(playerIndex: Int) { gameEngine?.handlePlayerJump(playerIndex: playerIndex) } + + func overlayInfo(forPlayer playerIndex: Int) -> OverlayInfo? { + guard let gameInfo = gameEngine?.gameInfo(forPlayer: playerIndex) else { + return nil + } + + return OverlayInfo( + score: gameInfo.playerScore + ) + } } From 71990c1b417c6685a533058187e3284c60f7f42b Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Wed, 27 Mar 2024 16:08:04 +0800 Subject: [PATCH 10/13] fix: Fix syntax errors --- SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift | 4 ++-- .../Sources/SDPhysicsEngine/Object/SDCameraObject.swift | 2 +- star-dash/star-dash.xcodeproj/project.pbxproj | 8 ++++---- .../star-dash/Extensions/{UIVIew.swift => UIView.swift} | 0 .../star-dash/GameEngine/Entities/EntityManager.swift | 2 +- .../star-dash/Rendering/PlayerView/OverlayView.swift | 2 +- star-dash/star-dash/Rendering/PlayerView/PlayerView.swift | 4 ++-- star-dash/star-dash/Rendering/Renderer.swift | 1 - 8 files changed, 11 insertions(+), 12 deletions(-) rename star-dash/star-dash/Extensions/{UIVIew.swift => UIView.swift} (100%) diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift index 5b9e1d9c..f09e396c 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift @@ -40,7 +40,7 @@ public class GameScene: SKScene { guard let cameraObject = cameraPlayerMap[playerIndex] else { return } - + cameraObject.zRotation = rotation self.camera = cameraObject.cameraNode } @@ -50,7 +50,7 @@ extension GameScene: SDScene { public func addPlayerObject(_ playerObject: SDObject, playerIndex: Int) { let camera = SDCameraObject(player: playerObject) cameraPlayerMap[playerIndex] = camera - + addObject(camera) addObject(playerObject) } diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift index 86574d82..5dcdf1e9 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDCameraObject.swift @@ -15,7 +15,7 @@ public class SDCameraObject: SDObject { cameraNode = SKCameraNode() super.init(node: cameraNode) } - + var zRotation: CGFloat { get { cameraNode.zRotation } set { cameraNode.zRotation = newValue } diff --git a/star-dash/star-dash.xcodeproj/project.pbxproj b/star-dash/star-dash.xcodeproj/project.pbxproj index 95ec75d1..8996cba9 100644 --- a/star-dash/star-dash.xcodeproj/project.pbxproj +++ b/star-dash/star-dash.xcodeproj/project.pbxproj @@ -103,7 +103,7 @@ E64361132BA4C2CD003850FD /* PhysicsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610D2BA4C2CC003850FD /* PhysicsModule.swift */; }; E64361142BA4C2CD003850FD /* CreationModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610E2BA4C2CC003850FD /* CreationModule.swift */; }; E64361152BA4C2CD003850FD /* GameBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610F2BA4C2CC003850FD /* GameBridge.swift */; }; - E64F31672BB3D14600EC5371 /* UIVIew.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64F31662BB3D14600EC5371 /* UIVIew.swift */; }; + E64F31672BB3D14600EC5371 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64F31662BB3D14600EC5371 /* UIView.swift */; }; E69EE9322BAC6CBB00033AB5 /* GameInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */; }; E69EE9342BAC6CC300033AB5 /* OverlayInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */; }; E69FDDE02BAD3DAD0089D5F3 /* PointsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */; }; @@ -256,7 +256,7 @@ E643610D2BA4C2CC003850FD /* PhysicsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsModule.swift; sourceTree = ""; }; E643610E2BA4C2CC003850FD /* CreationModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreationModule.swift; sourceTree = ""; }; E643610F2BA4C2CC003850FD /* GameBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameBridge.swift; sourceTree = ""; }; - E64F31662BB3D14600EC5371 /* UIVIew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIVIew.swift; sourceTree = ""; }; + E64F31662BB3D14600EC5371 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameInfo.swift; sourceTree = ""; }; E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverlayInfo.swift; sourceTree = ""; }; E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PointsComponent.swift; sourceTree = ""; }; @@ -311,7 +311,7 @@ isa = PBXGroup; children = ( 143AA38E2BA4D61A009C28E7 /* CGVector.swift */, - E64F31662BB3D14600EC5371 /* UIVIew.swift */, + E64F31662BB3D14600EC5371 /* UIView.swift */, ); path = Extensions; sourceTree = ""; @@ -924,7 +924,7 @@ 4E630F372B9F91DE0008F887 /* PlayerSprite.swift in Sources */, 14970F502BA814D500CC1E8A /* ScoreComponent.swift in Sources */, E69FDDE42BADC2F10089D5F3 /* SpriteConstants.swift in Sources */, - E64F31672BB3D14600EC5371 /* UIVIew.swift in Sources */, + E64F31672BB3D14600EC5371 /* UIView.swift in Sources */, 143AA3912BA4D7AC009C28E7 /* MonsterDeathEvent.swift in Sources */, E64361102BA4C2CD003850FD /* SpriteModule.swift in Sources */, 4604BBD52BA819C70078B84C /* InventoryComponent.swift in Sources */, diff --git a/star-dash/star-dash/Extensions/UIVIew.swift b/star-dash/star-dash/Extensions/UIView.swift similarity index 100% rename from star-dash/star-dash/Extensions/UIVIew.swift rename to star-dash/star-dash/Extensions/UIView.swift diff --git a/star-dash/star-dash/GameEngine/Entities/EntityManager.swift b/star-dash/star-dash/GameEngine/Entities/EntityManager.swift index ed4c42d2..425dc39d 100644 --- a/star-dash/star-dash/GameEngine/Entities/EntityManager.swift +++ b/star-dash/star-dash/GameEngine/Entities/EntityManager.swift @@ -61,7 +61,7 @@ class EntityManager { func playerEntityId(with playerIndex: Int) -> EntityId? { // TODO: Add parameter to specify the player index for entityId in entityMap.keys { - if let playerComponent = component(ofType: PlayerComponent.self, of: entityId), + if let playerComponent = component(ofType: PlayerComponent.self, of: entityId), playerComponent.playerIndex == playerIndex { return entityId } diff --git a/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift b/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift index f9672dd8..c8cded44 100644 --- a/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift +++ b/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift @@ -22,7 +22,7 @@ class OverlayView: UIView { scoreLabel.leadingAnchor.constraint(greaterThanOrEqualTo: self.leadingAnchor, constant: margin) ]) - update(score: 0) + update(OverlayInfo(score: 0)) } func update(_ overlayInfo: OverlayInfo) { diff --git a/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift b/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift index d940b2a9..64e77f48 100644 --- a/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift +++ b/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift @@ -47,8 +47,8 @@ class PlayerView { sceneView.delegate = delegate } - func updateOverlay(score: Int) { - overlayView.update(score: score) + func update(_ overlayInfo: OverlayInfo) { + overlayView.update(overlayInfo) } static func createPlayerView(layout: PlayerViewLayout, device: MTLDevice) -> PlayerView { diff --git a/star-dash/star-dash/Rendering/Renderer.swift b/star-dash/star-dash/Rendering/Renderer.swift index 3e4048dc..f2ddabd4 100644 --- a/star-dash/star-dash/Rendering/Renderer.swift +++ b/star-dash/star-dash/Rendering/Renderer.swift @@ -4,6 +4,5 @@ import UIKit The `Renderer` protocol defines the requirements for an object responsible for rendering game objects onto a view. */ protocol Renderer { - func updateOverlay(overlayInfo: OverlayInfo) func setupViews(at rootView: UIView, for numberOfPlayers: Int) } From cd747c3e23b1e87762f2ec94cf7855063a6241cc Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Wed, 27 Mar 2024 16:22:49 +0800 Subject: [PATCH 11/13] chore: Add docs for UIView extension --- star-dash/star-dash/Extensions/UIView.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/star-dash/star-dash/Extensions/UIView.swift b/star-dash/star-dash/Extensions/UIView.swift index 6ad48311..0762e97e 100644 --- a/star-dash/star-dash/Extensions/UIView.swift +++ b/star-dash/star-dash/Extensions/UIView.swift @@ -1,5 +1,9 @@ import UIKit +/** + * The extension introduces an initisalisation method to add subviews + * to a frame that is rotated, however the view is not rotated. + */ extension UIView { convenience init(frame: CGRect, rotatedBy rotation: CGFloat) { self.init(frame: frame.applying(CGAffineTransform(rotationAngle: rotation))) From 5a92c5fd9c2e731ea9fc51f6e7034119842698b0 Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Wed, 27 Mar 2024 22:59:01 +0800 Subject: [PATCH 12/13] chore: Remove resolved todo --- star-dash/star-dash/GameEngine/Entities/EntityManager.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/star-dash/star-dash/GameEngine/Entities/EntityManager.swift b/star-dash/star-dash/GameEngine/Entities/EntityManager.swift index 425dc39d..57df69f9 100644 --- a/star-dash/star-dash/GameEngine/Entities/EntityManager.swift +++ b/star-dash/star-dash/GameEngine/Entities/EntityManager.swift @@ -59,7 +59,6 @@ class EntityManager { } func playerEntityId(with playerIndex: Int) -> EntityId? { - // TODO: Add parameter to specify the player index for entityId in entityMap.keys { if let playerComponent = component(ofType: PlayerComponent.self, of: entityId), playerComponent.playerIndex == playerIndex { From 208ff9ece87013446977da1b7e8b6c0bd29e1bf4 Mon Sep 17 00:00:00 2001 From: Goh Jun Yi <54541329+Junyi00@users.noreply.github.com> Date: Fri, 29 Mar 2024 02:25:37 +0800 Subject: [PATCH 13/13] fix: Fix syntax issues --- star-dash/star-dash.xcodeproj/project.pbxproj | 15 +++++++++++++-- star-dash/star-dash/GameEngine/GameEngine.swift | 6 +++--- .../Rendering/PlayerView/OverlayView.swift | 6 +++--- .../Rendering/PlayerView/PlayerView.swift | 8 +++++++- star-dash/star-dash/ViewController.swift | 5 ++--- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/star-dash/star-dash.xcodeproj/project.pbxproj b/star-dash/star-dash.xcodeproj/project.pbxproj index 025c8d24..12a4ba8b 100644 --- a/star-dash/star-dash.xcodeproj/project.pbxproj +++ b/star-dash/star-dash.xcodeproj/project.pbxproj @@ -55,7 +55,6 @@ 46D418242BA5D5280091A38B /* Tool+Collidable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D418232BA5D5280091A38B /* Tool+Collidable.swift */; }; 46D418262BA5D6500091A38B /* Wall+Collidable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D418252BA5D6500091A38B /* Wall+Collidable.swift */; }; 46D418282BA5D6800091A38B /* Floor+Collidable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46D418272BA5D6800091A38B /* Floor+Collidable.swift */; }; - 4E0905FD2BB4A15600DE666B /* MiniMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E0905FC2BB4A15600DE666B /* MiniMapView.swift */; }; 4E0905FF2BB4A4EB00DE666B /* PlayerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E0905FE2BB4A4EB00DE666B /* PlayerInfo.swift */; }; 4E3458DF2BA7490B00E817C6 /* EntityManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E3458DE2BA7490B00E817C6 /* EntityManagerTests.swift */; }; 4E3458E52BA75E6800E817C6 /* PositionComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E3458E42BA75E6800E817C6 /* PositionComponentTests.swift */; }; @@ -109,6 +108,7 @@ E64361142BA4C2CD003850FD /* CreationModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610E2BA4C2CC003850FD /* CreationModule.swift */; }; E64361152BA4C2CD003850FD /* GameBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610F2BA4C2CC003850FD /* GameBridge.swift */; }; E64F31672BB3D14600EC5371 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64F31662BB3D14600EC5371 /* UIView.swift */; }; + E660353D2BB5EAEE00397068 /* MiniMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E660353C2BB5EAEE00397068 /* MiniMapView.swift */; }; E69EE9322BAC6CBB00033AB5 /* GameInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */; }; E69EE9342BAC6CC300033AB5 /* OverlayInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */; }; E69FDDE02BAD3DAD0089D5F3 /* PointsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */; }; @@ -267,6 +267,7 @@ E643610E2BA4C2CC003850FD /* CreationModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreationModule.swift; sourceTree = ""; }; E643610F2BA4C2CC003850FD /* GameBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameBridge.swift; sourceTree = ""; }; E64F31662BB3D14600EC5371 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; + E660353C2BB5EAEE00397068 /* MiniMapView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MiniMapView.swift; sourceTree = ""; }; E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameInfo.swift; sourceTree = ""; }; E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverlayInfo.swift; sourceTree = ""; }; E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PointsComponent.swift; sourceTree = ""; }; @@ -514,6 +515,7 @@ 142D9F8E2BA15FBB005FE9E0 /* .swiftlint.yml */, 4E630EF32B9F7E070008F887 /* Products */, E6B1DC912BA34A5E00473563 /* Frameworks */, + E660353B2BB5EAD300397068 /* Recovered References */, ); sourceTree = ""; }; @@ -646,6 +648,7 @@ E64F31682BB400CB00EC5371 /* PlayerView */ = { isa = PBXGroup; children = ( + E660353C2BB5EAEE00397068 /* MiniMapView.swift */, E6A7451A2BA0C1890080C1BE /* PlayerView.swift */, E6A7451C2BA0CAD90080C1BE /* JoystickView.swift */, E6A745122BA057040080C1BE /* ControlView.swift */, @@ -655,6 +658,14 @@ path = PlayerView; sourceTree = ""; }; + E660353B2BB5EAD300397068 /* Recovered References */ = { + isa = PBXGroup; + children = ( + 4E0905FC2BB4A15600DE666B /* MiniMapView.swift */, + ); + name = "Recovered References"; + sourceTree = ""; + }; E6A011152BA5D111006904D9 /* GameBridge */ = { isa = PBXGroup; children = ( @@ -891,7 +902,6 @@ 143AA3952BA4DF1C009C28E7 /* MonsterAttackPlayerEvent.swift in Sources */, 143AA3932BA4DBE7009C28E7 /* PlayerMonsterContactEvent.swift in Sources */, 4E59E2682BADA7B6007B3FA7 /* CollectibleEntityPersistable.swift in Sources */, - 4E0905FD2BB4A15600DE666B /* MiniMapView.swift in Sources */, 46D418162BA5CBD60091A38B /* Collidable.swift in Sources */, 461148912BA1CDBF0073E7E1 /* SystemManager.swift in Sources */, 460A20112BB1E6DF002597B8 /* MonsterSystem.swift in Sources */, @@ -916,6 +926,7 @@ 4604BBD92BA81C940078B84C /* InventorySystem.swift in Sources */, 14E247952BA2CB480071FFC0 /* EventManager.swift in Sources */, 4EC561E32BB1E98400166DDC /* PlayerObstacleContactEvent.swift in Sources */, + E660353D2BB5EAEE00397068 /* MiniMapView.swift in Sources */, 4E630EF82B9F7E070008F887 /* SceneDelegate.swift in Sources */, 46C3B1C22BB467BB00F10574 /* EntityManagerInterface.swift in Sources */, E69FDDE02BAD3DAD0089D5F3 /* PointsComponent.swift in Sources */, diff --git a/star-dash/star-dash/GameEngine/GameEngine.swift b/star-dash/star-dash/GameEngine/GameEngine.swift index b782feb2..d29b6a5c 100644 --- a/star-dash/star-dash/GameEngine/GameEngine.swift +++ b/star-dash/star-dash/GameEngine/GameEngine.swift @@ -29,12 +29,12 @@ class GameEngine { return GameInfo( playerScore: score, - playersInfo: playersInfo() + playersInfo: playersInfo(of: playerIndex) ) } - func playersInfo() -> [PlayerInfo] { - guard let playerEntityId = entityManager.playerEntityId(), + func playersInfo(of playerIndex: Int) -> [PlayerInfo] { + guard let playerEntityId = entityManager.playerEntityId(with: playerIndex), let positionSystem = systemManager.system(ofType: PositionSystem.self) else { return [] } diff --git a/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift b/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift index c8cded44..f62ed778 100644 --- a/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift +++ b/star-dash/star-dash/Rendering/PlayerView/OverlayView.swift @@ -22,10 +22,10 @@ class OverlayView: UIView { scoreLabel.leadingAnchor.constraint(greaterThanOrEqualTo: self.leadingAnchor, constant: margin) ]) - update(OverlayInfo(score: 0)) + update(0) } - func update(_ overlayInfo: OverlayInfo) { - scoreLabel.text = "Score: \(overlayInfo.score)" + func update(_ score: Int) { + scoreLabel.text = "Score: \(score)" } } diff --git a/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift b/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift index 64e77f48..df60bfa2 100644 --- a/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift +++ b/star-dash/star-dash/Rendering/PlayerView/PlayerView.swift @@ -17,6 +17,7 @@ class PlayerView { var sceneView: MTKView var controlView: ControlView var overlayView: OverlayView + var minimapView: MiniMapView let rotation: CGFloat @@ -29,6 +30,9 @@ class PlayerView { self.overlayView = OverlayView(frame: superview.bounds, rotatedBy: rotation) superview.addSubview(self.overlayView) + + self.minimapView = MiniMapView(frame: superview.bounds, rotatedBy: rotation) + superview.addSubview(self.minimapView) self.controlView = ControlView(frame: superview.bounds, rotatedBy: rotation) superview.addSubview(self.controlView) @@ -37,6 +41,7 @@ class PlayerView { func setupSubviews() { self.controlView.setupSubviews() self.overlayView.setupSubviews() + self.minimapView.setupSubviews() } func setControlViewDelegate(_ delegate: ControlViewDelegate) { @@ -48,7 +53,8 @@ class PlayerView { } func update(_ overlayInfo: OverlayInfo) { - overlayView.update(overlayInfo) + overlayView.update(overlayInfo.score) + minimapView.update(playersInfo: overlayInfo.playersInfo) } static func createPlayerView(layout: PlayerViewLayout, device: MTLDevice) -> PlayerView { diff --git a/star-dash/star-dash/ViewController.swift b/star-dash/star-dash/ViewController.swift index cafaeab9..66680b09 100644 --- a/star-dash/star-dash/ViewController.swift +++ b/star-dash/star-dash/ViewController.swift @@ -56,8 +56,6 @@ class ViewController: UIViewController { playerIndex: 1, position: CGPoint(x: scene.size.width / 2, y: scene.size.height / 2 + 200)) - let floor = Floor(position: CGPoint(x: scene.size.width / 2, y: scene.size.height / 2 - 400)) - floor.setUpAndAdd(to: entityManager) EntityFactory.createAndAddFloor(to: gameEngine, position: CGPoint(x: scene.size.width / 2, y: scene.size.height / 2 - 400), size: CGSize(width: 8_000, height: 10)) @@ -110,7 +108,8 @@ extension ViewController: ViewDelegate { } return OverlayInfo( - score: gameInfo.playerScore + score: gameInfo.playerScore, + playersInfo: gameInfo.playersInfo ) } }