diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift index 77903c85..68a4ebcc 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift @@ -38,6 +38,11 @@ extension GameScene: SDScene { objectMap[object.node] = object addChild(object.node) } + + public func removeObject(_ object: SDObject) { + objectMap[object.node] = nil + object.removeFromParent() + } } extension GameScene: SKPhysicsContactDelegate { diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDObject.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDObject.swift index 3549ee9a..f66db885 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDObject.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDObject.swift @@ -39,4 +39,8 @@ public class SDObject { public var physicsBody: SDPhysicsBody? { willSet { node.physicsBody = newValue?.body } } + + func removeFromParent() { + node.removeFromParent() + } } diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift index 79f0fe83..c35a3142 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift @@ -5,4 +5,5 @@ public protocol SDScene { var size: CGSize { get } func addObject(_ object: SDObject) + func removeObject(_ object: SDObject) } diff --git a/star-dash/star-dash.xcodeproj/project.pbxproj b/star-dash/star-dash.xcodeproj/project.pbxproj index 49f2d6f0..868d487b 100644 --- a/star-dash/star-dash.xcodeproj/project.pbxproj +++ b/star-dash/star-dash.xcodeproj/project.pbxproj @@ -62,6 +62,10 @@ 4E59E25F2BAB4134007B3FA7 /* EntityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E59E25E2BAB4134007B3FA7 /* EntityType.swift */; }; 4E59E2612BAB42FD007B3FA7 /* LevelPersistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E59E2602BAB42FD007B3FA7 /* LevelPersistable.swift */; }; 4E59E2632BACB9E2007B3FA7 /* LevelData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E59E2622BACB9E2007B3FA7 /* LevelData.swift */; }; + 4E59E2662BADA79A007B3FA7 /* MonsterEntityPersistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E59E2652BADA79A007B3FA7 /* MonsterEntityPersistable.swift */; }; + 4E59E2682BADA7B6007B3FA7 /* CollectibleEntityPersistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E59E2672BADA7B6007B3FA7 /* CollectibleEntityPersistable.swift */; }; + 4E59E26A2BADA7C7007B3FA7 /* ToolEntityPersistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E59E2692BADA7C7007B3FA7 /* ToolEntityPersistable.swift */; }; + 4E59E26C2BADA7DD007B3FA7 /* ObstacleEntityPersistable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E59E26B2BADA7DD007B3FA7 /* ObstacleEntityPersistable.swift */; }; 4E630EF62B9F7E070008F887 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E630EF52B9F7E070008F887 /* AppDelegate.swift */; }; 4E630EF82B9F7E070008F887 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E630EF72B9F7E070008F887 /* SceneDelegate.swift */; }; 4E630EFA2B9F7E070008F887 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E630EF92B9F7E070008F887 /* ViewController.swift */; }; @@ -92,6 +96,10 @@ 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 */; }; + 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 */; }; + E69FDDE22BAD3DC40089D5F3 /* EntityConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDE12BAD3DC40089D5F3 /* EntityConstants.swift */; }; E6A011172BA5F4AD006904D9 /* EntitySyncInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A011162BA5F4AD006904D9 /* EntitySyncInterface.swift */; }; E6A745162BA057040080C1BE /* MTKRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745112BA057040080C1BE /* MTKRenderer.swift */; }; E6A745172BA057040080C1BE /* ControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745122BA057040080C1BE /* ControlView.swift */; }; @@ -191,6 +199,10 @@ 4E59E25E2BAB4134007B3FA7 /* EntityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityType.swift; sourceTree = ""; }; 4E59E2602BAB42FD007B3FA7 /* LevelPersistable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LevelPersistable.swift; sourceTree = ""; }; 4E59E2622BACB9E2007B3FA7 /* LevelData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LevelData.swift; sourceTree = ""; }; + 4E59E2652BADA79A007B3FA7 /* MonsterEntityPersistable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MonsterEntityPersistable.swift; sourceTree = ""; }; + 4E59E2672BADA7B6007B3FA7 /* CollectibleEntityPersistable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectibleEntityPersistable.swift; sourceTree = ""; }; + 4E59E2692BADA7C7007B3FA7 /* ToolEntityPersistable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolEntityPersistable.swift; sourceTree = ""; }; + 4E59E26B2BADA7DD007B3FA7 /* ObstacleEntityPersistable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObstacleEntityPersistable.swift; sourceTree = ""; }; 4E630EF22B9F7E070008F887 /* star-dash.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "star-dash.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 4E630EF52B9F7E070008F887 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 4E630EF72B9F7E070008F887 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -225,6 +237,10 @@ 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 = ""; }; + 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 = ""; }; + E69FDDE12BAD3DC40089D5F3 /* EntityConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntityConstants.swift; sourceTree = ""; }; E6A011162BA5F4AD006904D9 /* EntitySyncInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntitySyncInterface.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 = ""; }; @@ -360,6 +376,7 @@ 4E630F282B9F7EC20008F887 /* Components */, 4E630F252B9F7E500008F887 /* Entities */, 46B8C0992BA328D900498705 /* GameEngine.swift */, + E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */, ); path = GameEngine; sourceTree = ""; @@ -409,6 +426,10 @@ 4E59E2522BAB3061007B3FA7 /* Database.swift */, 4E59E25C2BAB405A007B3FA7 /* EntityPersistable.swift */, 4E59E2602BAB42FD007B3FA7 /* LevelPersistable.swift */, + 4E59E2652BADA79A007B3FA7 /* MonsterEntityPersistable.swift */, + 4E59E26B2BADA7DD007B3FA7 /* ObstacleEntityPersistable.swift */, + 4E59E2672BADA7B6007B3FA7 /* CollectibleEntityPersistable.swift */, + 4E59E2692BADA7C7007B3FA7 /* ToolEntityPersistable.swift */, ); path = Persistence; sourceTree = ""; @@ -508,6 +529,7 @@ 4E630F282B9F7EC20008F887 /* Components */ = { isa = PBXGroup; children = ( + E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */, E6B34A462BAA03AF0009A60B /* PlayerComponent.swift */, 4E630F292B9F7EF60008F887 /* PositionComponent.swift */, 14970F4F2BA814D500CC1E8A /* ScoreComponent.swift */, @@ -532,6 +554,7 @@ 4E86605D2BA095CC0035530D /* Constants */ = { isa = PBXGroup; children = ( + E69FDDE12BAD3DC40089D5F3 /* EntityConstants.swift */, 4E8660652BA097D40035530D /* PhysicsConstants.swift */, 14970F552BA8177B00CC1E8A /* GameConstants.swift */, ); @@ -577,6 +600,7 @@ E6A745102BA057040080C1BE /* Rendering */ = { isa = PBXGroup; children = ( + E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */, E6B5509F2BA15D2000DC7396 /* MTKRenderer */, E6A745132BA057040080C1BE /* Renderer.swift */, E6B0AAD02BAAE3DC009CB939 /* ViewDelegate.swift */, @@ -773,6 +797,8 @@ 46D418182BA5CD840091A38B /* Player+Collidable.swift in Sources */, 4E59E25B2BAB3FDB007B3FA7 /* Level.swift in Sources */, 46D4181E2BA5D2620091A38B /* Monster+Collidable.swift in Sources */, + 4E59E2662BADA79A007B3FA7 /* MonsterEntityPersistable.swift in Sources */, + E69EE9342BAC6CC300033AB5 /* OverlayInfo.swift in Sources */, E6B1DC902BA34A4800473563 /* SDPhysicsEngine in Sources */, 4E630F272B9F7E770008F887 /* Entity.swift in Sources */, 4E630F2C2B9F7F460008F887 /* Component.swift in Sources */, @@ -794,6 +820,7 @@ 4E8660662BA097D40035530D /* PhysicsConstants.swift in Sources */, 143AA3952BA4DF1C009C28E7 /* MonsterAttackPlayerEvent.swift in Sources */, 143AA3932BA4DBE7009C28E7 /* PlayerMonsterContactEvent.swift in Sources */, + 4E59E2682BADA7B6007B3FA7 /* CollectibleEntityPersistable.swift in Sources */, 46D418162BA5CBD60091A38B /* Collidable.swift in Sources */, 461148912BA1CDBF0073E7E1 /* SystemManager.swift in Sources */, 4E59E2512BAB2EAE007B3FA7 /* StorageManager.swift in Sources */, @@ -805,20 +832,24 @@ 4E630F322B9F887C0008F887 /* PhysicsComponent.swift in Sources */, 4E59E25D2BAB405A007B3FA7 /* EntityPersistable.swift in Sources */, 1471B0AD2BA6AE4E00878B14 /* UseGrappleHookEvent.swift in Sources */, + 4E59E26C2BADA7DD007B3FA7 /* ObstacleEntityPersistable.swift in Sources */, 4E630EF62B9F7E070008F887 /* AppDelegate.swift in Sources */, 461148962BA1D53D0073E7E1 /* PositionSystem.swift in Sources */, 143AA38C2BA4D3E3009C28E7 /* JumpEvent.swift in Sources */, 4E630F2A2B9F7EF60008F887 /* PositionComponent.swift in Sources */, 46D418132BA5C9930091A38B /* Floor.swift in Sources */, E64361152BA4C2CD003850FD /* GameBridge.swift in Sources */, + 4E59E26A2BADA7C7007B3FA7 /* ToolEntityPersistable.swift in Sources */, E6B0AAD32BAAE438009CB939 /* ControlViewDelegate.swift in Sources */, 4604BBD92BA81C940078B84C /* InventorySystem.swift in Sources */, 14E247952BA2CB480071FFC0 /* EventManager.swift in Sources */, 4E630EF82B9F7E070008F887 /* SceneDelegate.swift in Sources */, + E69FDDE02BAD3DAD0089D5F3 /* PointsComponent.swift in Sources */, 14970F542BA8163300CC1E8A /* ScoreSystem.swift in Sources */, E64361112BA4C2CD003850FD /* SyncModule.swift in Sources */, E6A7451B2BA0C1890080C1BE /* PlayerView.swift in Sources */, 46D418282BA5D6800091A38B /* Floor+Collidable.swift in Sources */, + E69EE9322BAC6CBB00033AB5 /* GameInfo.swift in Sources */, 46D418222BA5D4E60091A38B /* Obstacle+Collidable.swift in Sources */, E638B9CF2BAB3C5D00931CC2 /* TeleportEvent.swift in Sources */, E6A745162BA057040080C1BE /* MTKRenderer.swift in Sources */, @@ -837,6 +868,7 @@ E6A7451D2BA0CAD90080C1BE /* JoystickView.swift in Sources */, E6B550A12BA15E9C00DC7396 /* OverlayView.swift in Sources */, 46D418262BA5D6500091A38B /* Wall+Collidable.swift in Sources */, + E69FDDE22BAD3DC40089D5F3 /* EntityConstants.swift in Sources */, 4E630F342B9F8FC00008F887 /* Player.swift in Sources */, 4E630F372B9F91DE0008F887 /* PlayerSprite.swift in Sources */, 14970F502BA814D500CC1E8A /* ScoreComponent.swift in Sources */, diff --git a/star-dash/star-dash/Constants/EntityConstants.swift b/star-dash/star-dash/Constants/EntityConstants.swift new file mode 100644 index 00000000..46f593fd --- /dev/null +++ b/star-dash/star-dash/Constants/EntityConstants.swift @@ -0,0 +1,9 @@ +import CoreGraphics + +struct EntityConstants { + struct CoinCollectible { + static let points = 10 + static let sprite = "Coin" + static let size = CGSize(width: 50, height: 50) + } +} diff --git a/star-dash/star-dash/Constants/PhysicsConstants.swift b/star-dash/star-dash/Constants/PhysicsConstants.swift index 7a7e0dc4..c8e40f38 100644 --- a/star-dash/star-dash/Constants/PhysicsConstants.swift +++ b/star-dash/star-dash/Constants/PhysicsConstants.swift @@ -21,15 +21,25 @@ struct PhysicsConstants { } struct CollisionMask { - static let player = CollisionCategory.max ^ CollisionCategory.player + static let player = CollisionCategory.max ^ CollisionCategory.player ^ CollisionCategory.collectible static let monster = CollisionCategory.player | CollisionCategory.tool - static let collectible = CollisionCategory.player + static let collectible = CollisionCategory.none static let obstacle = CollisionCategory.player | CollisionCategory.monster | CollisionMask.tool static let tool = CollisionCategory.max ^ CollisionCategory.collectible ^ CollisionCategory.tool static let wall = CollisionCategory.player | CollisionCategory.monster | CollisionCategory.tool static let floor = CollisionCategory.player | CollisionCategory.monster | CollisionCategory.tool } + struct ContactMask { + static let player = CollisionCategory.floor | CollisionCategory.collectible + static let monster = CollisionCategory.player + static let collectible = CollisionCategory.player + static let obstacle = CollisionCategory.none + static let tool = CollisionCategory.obstacle + static let wall = CollisionCategory.tool | CollisionCategory.player + static let floor = CollisionCategory.player + } + struct Dimensions { // TODO: determine appropriate size for each static let player = CGSize(width: 60, height: 60) diff --git a/star-dash/star-dash/Events/PlayerEvents/PickupCollectibleEvent.swift b/star-dash/star-dash/Events/PlayerEvents/PickupCollectibleEvent.swift index a0ab9821..b4a94aad 100644 --- a/star-dash/star-dash/Events/PlayerEvents/PickupCollectibleEvent.swift +++ b/star-dash/star-dash/Events/PlayerEvents/PickupCollectibleEvent.swift @@ -20,10 +20,11 @@ class PickupCollectibleEvent: Event { } func execute(on target: EventModifiable) { - guard let scoreSystem = target.system(ofType: ScoreSystem.self) else { + guard let scoreSystem = target.system(ofType: ScoreSystem.self), + let pointsComponent = target.component(ofType: PointsComponent.self, ofEntity: collectibleEntityId) else { return } - scoreSystem.applyScoreChange(to: entityId, scoreChange: GameConstants.ScoreChange.pickupCollectible) + scoreSystem.applyScoreChange(to: entityId, scoreChange: pointsComponent.points) target.add(event: RemoveEvent(on: collectibleEntityId)) } } diff --git a/star-dash/star-dash/GameBridge/GameBridge.swift b/star-dash/star-dash/GameBridge/GameBridge.swift index a71662ba..9a66db72 100644 --- a/star-dash/star-dash/GameBridge/GameBridge.swift +++ b/star-dash/star-dash/GameBridge/GameBridge.swift @@ -88,5 +88,13 @@ class GameBridge { } private func removeObject(from entityId: EntityId) { + guard let object = entitiesMap[entityId] else { + return + } + + entitiesMap[entityId] = nil + objectsMap[object.id] = nil + + self.scene.removeObject(object) } } diff --git a/star-dash/star-dash/GameBridge/SyncModule/PhysicsModule.swift b/star-dash/star-dash/GameBridge/SyncModule/PhysicsModule.swift index e9e4e622..b20a5a82 100644 --- a/star-dash/star-dash/GameBridge/SyncModule/PhysicsModule.swift +++ b/star-dash/star-dash/GameBridge/SyncModule/PhysicsModule.swift @@ -38,6 +38,7 @@ class PhysicsModule: SyncModule { object.physicsBody = createRectanglePhysicsBody(physicsComponent: physicsComponent) object.physicsBody?.restitution = physicsComponent.restitution object.physicsBody?.isDynamic = physicsComponent.isDynamic + object.physicsBody?.affectedByGravity = physicsComponent.affectedByGravity object.physicsBody?.categoryBitMask = physicsComponent.categoryBitMask object.physicsBody?.contactTestMask = physicsComponent.contactTestMask object.physicsBody?.collisionBitMask = physicsComponent.collisionBitMask diff --git a/star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift b/star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift index a08c9705..aa15e7c9 100644 --- a/star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift +++ b/star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift @@ -31,7 +31,11 @@ extension SpriteModule: CreationModule { var newObject = SDObject() if let spriteComponent = entityManager.component(ofType: SpriteComponent.self, of: entity.id) { let spriteObject = SDSpriteObject(imageNamed: "PlayerRedNose") - spriteObject.size = CGSize(width: 100, height: 140) + + if let size = spriteComponent.size { + spriteObject.size = size + } + newObject = spriteObject } diff --git a/star-dash/star-dash/GameEngine/Components/PointsComponent.swift b/star-dash/star-dash/GameEngine/Components/PointsComponent.swift new file mode 100644 index 00000000..752e9ebf --- /dev/null +++ b/star-dash/star-dash/GameEngine/Components/PointsComponent.swift @@ -0,0 +1,14 @@ +import Foundation + +class PointsComponent: Component { + let points: Int + + init(id: UUID, entityId: UUID, points: Int) { + self.points = points + super.init(id: id, entityId: entityId) + } + + convenience init(entityId: UUID, points: Int) { + self.init(id: UUID(), entityId: entityId, points: points) + } +} diff --git a/star-dash/star-dash/GameEngine/Components/SpriteComponent.swift b/star-dash/star-dash/GameEngine/Components/SpriteComponent.swift index 585fac6d..6059e767 100644 --- a/star-dash/star-dash/GameEngine/Components/SpriteComponent.swift +++ b/star-dash/star-dash/GameEngine/Components/SpriteComponent.swift @@ -12,16 +12,16 @@ class SpriteComponent: Component { // for sprite set will need to discuss how to rep animation var image: String var textureAtlas: String? - var size: CGSize + var size: CGSize? - init(id: ComponentId, entityId: EntityId, image: String, textureAtlas: String?, size: CGSize) { + init(id: ComponentId, entityId: EntityId, image: String, textureAtlas: String?, size: CGSize?) { self.image = image self.size = size self.textureAtlas = textureAtlas super.init(id: id, entityId: entityId) } - convenience init(entityId: EntityId, image: String, textureAtlas: String?, size: CGSize) { + convenience init(entityId: EntityId, image: String, textureAtlas: String?, size: CGSize?) { self.init(id: UUID(), entityId: entityId, image: image, textureAtlas: textureAtlas, size: size) } } diff --git a/star-dash/star-dash/GameEngine/Entities/GameEntities/Collectible.swift b/star-dash/star-dash/GameEngine/Entities/GameEntities/Collectible.swift index bb0d7c39..f7d5d59c 100644 --- a/star-dash/star-dash/GameEngine/Entities/GameEntities/Collectible.swift +++ b/star-dash/star-dash/GameEngine/Entities/GameEntities/Collectible.swift @@ -10,23 +10,46 @@ import Foundation class Collectible: Entity { let id: EntityId private let position: CGPoint + private let sprite: String + private let points: Int + private let size: CGSize - init(id: EntityId, position: CGPoint) { + init(id: EntityId, position: CGPoint, sprite: String, points: Int, size: CGSize) { self.id = id self.position = position + self.sprite = sprite + self.points = points + self.size = size } - convenience init(position: CGPoint) { - self.init(id: UUID(), position: position) + convenience init(position: CGPoint, sprite: String, points: Int, size: CGSize) { + self.init(id: UUID(), position: position, sprite: sprite, points: points, size: size) } func setUpAndAdd(to: EntityManager) { let positionComponent = PositionComponent(entityId: self.id, position: self.position, rotation: .zero) - let physicsComponent = PhysicsComponent(entityId: self.id, size: PhysicsConstants.Dimensions.collectible) + let physicsComponent = PhysicsComponent(entityId: self.id, size: self.size) + physicsComponent.affectedByGravity = false + physicsComponent.isDynamic = false + physicsComponent.categoryBitMask = PhysicsConstants.CollisionCategory.collectible + physicsComponent.contactTestMask = PhysicsConstants.ContactMask.collectible physicsComponent.collisionBitMask = PhysicsConstants.CollisionMask.collectible + let spriteComponent = SpriteComponent(entityId: self.id, image: sprite, textureAtlas: nil, size: size) + let pointsComponent = PointsComponent(entityId: self.id, points: points) to.add(entity: self) to.add(component: positionComponent) to.add(component: physicsComponent) + to.add(component: spriteComponent) + to.add(component: pointsComponent) + } + + static func createCoinCollectible(position: CGPoint) -> Collectible { + Collectible( + position: position, + sprite: EntityConstants.CoinCollectible.sprite, + points: EntityConstants.CoinCollectible.points, + size: EntityConstants.CoinCollectible.size + ) } } diff --git a/star-dash/star-dash/GameEngine/Entities/GameEntities/Floor.swift b/star-dash/star-dash/GameEngine/Entities/GameEntities/Floor.swift index 51b3f76f..72627b0c 100644 --- a/star-dash/star-dash/GameEngine/Entities/GameEntities/Floor.swift +++ b/star-dash/star-dash/GameEngine/Entities/GameEntities/Floor.swift @@ -27,7 +27,7 @@ class Floor: Entity { physicsComponent.restitution = 0.0 physicsComponent.isDynamic = false physicsComponent.categoryBitMask = PhysicsConstants.CollisionCategory.floor - physicsComponent.contactTestMask = PhysicsConstants.CollisionCategory.player + physicsComponent.contactTestMask = PhysicsConstants.ContactMask.floor physicsComponent.collisionBitMask = PhysicsConstants.CollisionMask.floor to.add(entity: self) diff --git a/star-dash/star-dash/GameEngine/Entities/GameEntities/Monster.swift b/star-dash/star-dash/GameEngine/Entities/GameEntities/Monster.swift index 1f3cef06..9e710602 100644 --- a/star-dash/star-dash/GameEngine/Entities/GameEntities/Monster.swift +++ b/star-dash/star-dash/GameEngine/Entities/GameEntities/Monster.swift @@ -10,19 +10,24 @@ import Foundation class Monster: Entity { let id: EntityId private let position: CGPoint - - init(id: EntityId, position: CGPoint) { + private let health: Int + private let sprite: String + private let size: CGSize + init(id: EntityId, position: CGPoint, health: Int, sprite: String, size: CGSize) { self.id = id self.position = position + self.health = health + self.sprite = sprite + self.size = size } - convenience init(position: CGPoint) { - self.init(id: UUID(), position: position) + convenience init(position: CGPoint, health: Int, sprite: String, size: CGSize) { + self.init(id: UUID(), position: position, health: health, sprite: sprite, size: size) } func setUpAndAdd(to: EntityManager) { let positionComponent = PositionComponent(entityId: self.id, position: self.position, rotation: .zero) - let healthComponent = HealthComponent(entityId: self.id, health: GameConstants.InitialHealth.monster) + let healthComponent = HealthComponent(entityId: self.id, health: self.health) let physicsComponent = PhysicsComponent(entityId: self.id, size: PhysicsConstants.Dimensions.monster) physicsComponent.collisionBitMask = PhysicsConstants.CollisionMask.monster physicsComponent.affectedByGravity = true diff --git a/star-dash/star-dash/GameEngine/Entities/GameEntities/Obstacle.swift b/star-dash/star-dash/GameEngine/Entities/GameEntities/Obstacle.swift index 117a8460..64df290f 100644 --- a/star-dash/star-dash/GameEngine/Entities/GameEntities/Obstacle.swift +++ b/star-dash/star-dash/GameEngine/Entities/GameEntities/Obstacle.swift @@ -10,14 +10,17 @@ import Foundation class Obstacle: Entity { let id: EntityId private let position: CGPoint - - init(id: EntityId, position: CGPoint) { + private let sprite: String + private let size: CGSize + init(id: EntityId, position: CGPoint, sprite: String, size: CGSize) { self.id = id self.position = position + self.sprite = sprite + self.size = size } - convenience init(position: CGPoint) { - self.init(id: UUID(), position: position) + convenience init(position: CGPoint, sprite: String, size: CGSize) { + self.init(id: UUID(), position: position, sprite: sprite, size: size) } func setUpAndAdd(to: EntityManager) { diff --git a/star-dash/star-dash/GameEngine/Entities/GameEntities/Player.swift b/star-dash/star-dash/GameEngine/Entities/GameEntities/Player.swift index 0c0d1b90..de6c668c 100644 --- a/star-dash/star-dash/GameEngine/Entities/GameEntities/Player.swift +++ b/star-dash/star-dash/GameEngine/Entities/GameEntities/Player.swift @@ -30,11 +30,16 @@ class Player: Entity { let healthComponent = HealthComponent(entityId: self.id, health: GameConstants.InitialHealth.player) let physicsComponent = PhysicsComponent(entityId: self.id, size: PhysicsConstants.Dimensions.player) physicsComponent.categoryBitMask = PhysicsConstants.CollisionCategory.player - physicsComponent.contactTestMask = PhysicsConstants.CollisionCategory.floor + physicsComponent.contactTestMask = PhysicsConstants.ContactMask.player physicsComponent.collisionBitMask = PhysicsConstants.CollisionMask.player physicsComponent.affectedByGravity = true physicsComponent.restitution = 0.0 - let spriteComponent = SpriteComponent(entityId: self.id, image: "", textureAtlas: "", size: .zero) + let spriteComponent = SpriteComponent( + entityId: self.id, + image: "PlayerRedNose", + textureAtlas: "", + size: CGSize(width: 100, height: 140) + ) let scoreComponent = ScoreComponent(entityId: self.id, score: 0) to.add(entity: self) diff --git a/star-dash/star-dash/GameEngine/Entities/GameEntities/Tool.swift b/star-dash/star-dash/GameEngine/Entities/GameEntities/Tool.swift index 411810bd..6fdb0940 100644 --- a/star-dash/star-dash/GameEngine/Entities/GameEntities/Tool.swift +++ b/star-dash/star-dash/GameEngine/Entities/GameEntities/Tool.swift @@ -10,14 +10,17 @@ import Foundation class Tool: Entity { let id: EntityId private let position: CGPoint - - init(id: EntityId, position: CGPoint) { + private let sprite: String + private let size: CGSize + init(id: EntityId, position: CGPoint, sprite: String, size: CGSize) { self.id = id self.position = position + self.sprite = sprite + self.size = size } - convenience init(position: CGPoint) { - self.init(id: UUID(), position: position) + convenience init(position: CGPoint, sprite: String, size: CGSize) { + self.init(id: UUID(), position: position, sprite: sprite, size: size) } func setUpAndAdd(to: EntityManager) { diff --git a/star-dash/star-dash/GameEngine/GameEngine.swift b/star-dash/star-dash/GameEngine/GameEngine.swift index 207872fc..54ae9b84 100644 --- a/star-dash/star-dash/GameEngine/GameEngine.swift +++ b/star-dash/star-dash/GameEngine/GameEngine.swift @@ -20,6 +20,18 @@ class GameEngine { setUpSystems() } + func gameInfo() -> GameInfo? { + guard let scoreSystem = systemManager.system(ofType: ScoreSystem.self), + let playerEntityId = entityManager.playerEntityId(), + let score = scoreSystem.score(of: playerEntityId) else { + return nil + } + + return GameInfo( + playerScore: score + ) + } + func update(by deltaTime: TimeInterval) { systemManager.update(by: deltaTime) eventManager.executeAll(on: self) @@ -57,6 +69,7 @@ class GameEngine { private func setUpSystems() { systemManager.add(PositionSystem(entityManager, dispatcher: self)) systemManager.add(PhysicsSystem(entityManager, dispatcher: self)) + systemManager.add(ScoreSystem(entityManager, dispatcher: self)) } } diff --git a/star-dash/star-dash/GameEngine/GameInfo.swift b/star-dash/star-dash/GameEngine/GameInfo.swift new file mode 100644 index 00000000..3ca81506 --- /dev/null +++ b/star-dash/star-dash/GameEngine/GameInfo.swift @@ -0,0 +1,3 @@ +struct GameInfo { + let playerScore: Int +} diff --git a/star-dash/star-dash/GameEngine/Systems/ScoreSystem.swift b/star-dash/star-dash/GameEngine/Systems/ScoreSystem.swift index cc058f12..14ed8fc4 100644 --- a/star-dash/star-dash/GameEngine/Systems/ScoreSystem.swift +++ b/star-dash/star-dash/GameEngine/Systems/ScoreSystem.swift @@ -18,6 +18,14 @@ class ScoreSystem: System { self.dispatcher = dispatcher } + func score(of entityId: EntityId) -> Int? { + guard let scoreComponent = getScoreComponent(of: entityId) else { + return nil + } + + return scoreComponent.score + } + func applyScoreChange(to entityId: EntityId, scoreChange: Int) { guard let scoreComponent = getScoreComponent(of: entityId) else { return diff --git a/star-dash/star-dash/Persistence/CollectibleEntityPersistable.swift b/star-dash/star-dash/Persistence/CollectibleEntityPersistable.swift new file mode 100644 index 00000000..f5e4d63b --- /dev/null +++ b/star-dash/star-dash/Persistence/CollectibleEntityPersistable.swift @@ -0,0 +1,19 @@ +// +// CollectibleEntityPersistable.swift +// star-dash +// +// Created by Lau Rui han on 22/3/24. +// + +import Foundation +struct CollectibleEntityPersistable: Codable, EntityPersistable { + + var levelId: Int64 + var position: CGPoint + var sprite: String + var points: Int + var size: CGSize + func toEntity() -> Entity { + Collectible(position: self.position, sprite: self.sprite, points: self.points, size: self.size) + } +} diff --git a/star-dash/star-dash/Persistence/Data/LevelData.swift b/star-dash/star-dash/Persistence/Data/LevelData.swift index 07c3a3c8..2cfaf90a 100644 --- a/star-dash/star-dash/Persistence/Data/LevelData.swift +++ b/star-dash/star-dash/Persistence/Data/LevelData.swift @@ -10,7 +10,9 @@ import Foundation struct LevelData: Codable { var id: Int64 var name: String - var entities: [EntityPersistable] var size: CGSize - + var monsters: [MonsterEntityPersistable] + var obstacles: [ObstacleEntityPersistable] + var collectibles: [CollectibleEntityPersistable] + var tools: [ToolEntityPersistable] } diff --git a/star-dash/star-dash/Persistence/Data/data.json b/star-dash/star-dash/Persistence/Data/data.json index e6b72eb0..1d27e975 100644 --- a/star-dash/star-dash/Persistence/Data/data.json +++ b/star-dash/star-dash/Persistence/Data/data.json @@ -2,16 +2,40 @@ "id": 0, "name": "1", "size": [1000, 200], - "entities": [ + "obstacles": [ { "levelId": 0, - "entityType": "obstacle", - "position": [100, 100] + "sprite": "", + "position": [100, 200], + "size": [10,10] }, - { - "levelId": 0, - "entityType": "obstacle", - "position": [200, 200] - } + + ], + "collectibles": [ + { + "levelId": 0, + "sprite": "", + "position": [200, 200], + "size": [10,10], + "points": 10 + } + ], + + "tools": [ + { + "levelId": 0, + "sprite": "", + "position": [300, 200], + "size": [10,10] + }, + ], + "monsters": [ + { + "levelId": 0, + "sprite": "", + "position": [400, 100], + "size": [10,10], + "health": 100 + }, ] } diff --git a/star-dash/star-dash/Persistence/Database.swift b/star-dash/star-dash/Persistence/Database.swift index 08d586e2..b366a869 100644 --- a/star-dash/star-dash/Persistence/Database.swift +++ b/star-dash/star-dash/Persistence/Database.swift @@ -13,10 +13,21 @@ struct Database { static let DIR_DB = "StarDashDB" static let DB_NAME = "stardash.sqlite3" private let levelTable = Table("level") - private let entityTable = Table("entity") + private let collectibleTable = Table("collectible") + private let obstacleTable = Table("obstacle") + private let toolTable = Table("tool") + private let monsterTable = Table("monster") private var db: Connection? - + // Define a dictionary to map entity types to tables + let tableMap: [ObjectIdentifier: Table] init() { + tableMap = [ + ObjectIdentifier(CollectibleEntityPersistable.self): self.collectibleTable, + ObjectIdentifier(ToolEntityPersistable.self): self.toolTable, + ObjectIdentifier(ObstacleEntityPersistable.self): self.obstacleTable, + ObjectIdentifier(MonsterEntityPersistable.self): self.monsterTable + ] + if let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first { let dirPath = docDir.appendingPathComponent(Self.DIR_DB) @@ -46,14 +57,22 @@ struct Database { } do { try db.run(levelTable.drop()) - try db.run(entityTable.drop()) - } catch {} + try db.run(obstacleTable.drop()) + try db.run(collectibleTable.drop()) + try db.run(toolTable.drop()) + try db.run(monsterTable.drop()) + } catch { + print("Error deleting table \(error)") + } } private func createAllTables() { createLevelTable() - createEntityTable() + createCollectibleTable() + createToolTable() + createMonsterTable() + createObstacleTable() } private func createLevelTable() { @@ -74,55 +93,142 @@ struct Database { print("Error creating table \(error)") } } - - private func createEntityTable() { + + private func createCollectibleTable() { guard let db = db else { return } let id = Expression("id") let levelId = Expression("levelId") - let name = Expression("entityType") let position = Expression("position") + let sprite = Expression("sprite") + let points = Expression("points") + let size = Expression("size") + do { - try db.run( entityTable.create { table in + try db.run( collectibleTable.create { table in + table.column(id, primaryKey: .autoincrement) + table.column(levelId) + table.column(position) + table.column(sprite) + table.column(points) + table.column(size) + + }) + print("Collectible table created") + } catch { + print("Error creating table \(error)") + } + } + + private func createObstacleTable() { + guard let db = db else { + return + } + let id = Expression("id") + let levelId = Expression("levelId") + let position = Expression("position") + let sprite = Expression("sprite") + let size = Expression("size") + + do { + try db.run( obstacleTable.create { table in table.column(id, primaryKey: .autoincrement) table.column(levelId) - table.column(name) table.column(position) + table.column(sprite) + table.column(size) }) - print("Entity table created") + print("Obstacle table created") } catch { print("Error creating table \(error)") } } - - func insertLevelPersistable(levelPersistable: LevelPersistable) { + private func createToolTable() { + guard let db = db else { + return + } + let id = Expression("id") + let levelId = Expression("levelId") + let position = Expression("position") + let sprite = Expression("sprite") + let size = Expression("size") + + do { + try db.run( toolTable.create { table in + table.column(id, primaryKey: .autoincrement) + table.column(levelId) + table.column(position) + table.column(sprite) + table.column(size) + + }) + print("Tool table created") + } catch { + print("Error creating table \(error)") + } + } + private func createMonsterTable() { + guard let db = db else { + return + } + let id = Expression("id") + let levelId = Expression("levelId") + let position = Expression("position") + let sprite = Expression("sprite") + let size = Expression("size") + let health = Expression("health") + + do { + try db.run( monsterTable.create { table in + table.column(id, primaryKey: .autoincrement) + table.column(levelId) + table.column(position) + table.column(sprite) + table.column(size) + table.column(health) + + }) + print("Monster table created") + } catch { + print("Error creating table \(error)") + } + } + + func insert(persistable: LevelPersistable) { guard let database = db else { return } do { - let insert = try self.levelTable.insert(levelPersistable) + let insert = try self.levelTable.insert(persistable) try database.run(insert) } catch { print("Error saving level \(error)") } } - func insertEntityPersistable(entityPersistable: EntityPersistable) { + func insert(persistable: T) { guard let database = db else { return } do { - let insert = try self.entityTable.insert(entityPersistable) + // Get the corresponding table for the type + guard let table = self.tableMap[ObjectIdentifier(T.self)] else { + print("Unsupported entity type") + return + } + + let insert = try table.insert(persistable) try database.run(insert) } catch { - print("Error saving entity \(error)") + print("Error saving level \(error)") } } + } extension Database { @@ -135,10 +241,20 @@ extension Database { // Decode JSON data into LevelData let levelData = try JSONDecoder().decode(LevelData.self, from: jsonData) let levelPersistable = LevelPersistable(id: levelData.id, name: levelData.name, size: levelData.size) - insertLevelPersistable(levelPersistable: levelPersistable) - for entityPersistable in levelData.entities { - insertEntityPersistable(entityPersistable: entityPersistable) + insert(persistable: levelPersistable) + for persistable in levelData.collectibles { + insert(persistable: persistable) + } + for persistable in levelData.tools { + insert(persistable: persistable) } + for persistable in levelData.obstacles { + insert(persistable: persistable) + } + for persistable in levelData.monsters { + insert(persistable: persistable) + } + } catch { print("Error reading or decoding JSON: \(error)") } @@ -149,21 +265,20 @@ extension Database { print(error) } } - + func getLevelPersistable(id: Int64) -> LevelPersistable? { guard let database = db else { return nil } let idColumn = Expression("id") - do { let loadedLevel: [LevelPersistable] = try database.prepare(levelTable.filter(id == idColumn)).map { row in let persistable: LevelPersistable = try row.decode() return persistable - + } - if loadedLevel.isEmpty{ + if loadedLevel.isEmpty { return nil } return loadedLevel[0] @@ -173,27 +288,37 @@ extension Database { return nil } } - - func getEntityPersistables(levelId: Int64) -> [EntityPersistable] { + + func getAllEntities(levelId: Int64) -> [EntityPersistable] { guard let database = db else { - return [] - } - let idColumn = Expression("levelId") + return [] + } + var entities: [EntityPersistable] = [] + let levelIdColumn = Expression("levelId") + do { + entities += try database.prepare(collectibleTable.filter(levelId == levelIdColumn)).map { row in + let persistable: CollectibleEntityPersistable = try row.decode() + return persistable + } + entities += try database.prepare(toolTable.filter(levelId == levelIdColumn)).map { row in + let persistable: ToolEntityPersistable = try row.decode() + return persistable + } + entities += try database.prepare(obstacleTable.filter(levelId == levelIdColumn)).map { row in + let persistable: ObstacleEntityPersistable = try row.decode() + return persistable + } + entities += try database.prepare(monsterTable.filter(levelId == levelIdColumn)).map { row in + let persistable: MonsterEntityPersistable = try row.decode() + return persistable + } + } catch { + print("Error retriving \(error)") - do { - let loadedEntity: [EntityPersistable] = - try database.prepare(entityTable.filter(levelId == idColumn)).map { row in - let persistable: EntityPersistable = try row.decode() - return persistable - - } - - return loadedEntity + } + + return entities - } catch { - print("Error fetching entity \(error)") - return [] - } } - + } diff --git a/star-dash/star-dash/Persistence/EntityPersistable.swift b/star-dash/star-dash/Persistence/EntityPersistable.swift index a53aff57..2d564b3f 100644 --- a/star-dash/star-dash/Persistence/EntityPersistable.swift +++ b/star-dash/star-dash/Persistence/EntityPersistable.swift @@ -7,22 +7,6 @@ import Foundation -struct EntityPersistable: Codable { - var levelId: Int64 - var entityType: EntityType - var position: CGPoint - static var entityMap: [EntityType: (CGPoint) -> Entity] = [ - .Monster: { position in Monster(position: position) }, - .Collectible: { position in Collectible(position: position) }, - .Obstacle: { position in Obstacle(position: position) }, - .Tool: { position in Tool(position: position) } - ] - - func toEntity() -> Entity? { - - guard let entity = EntityPersistable.entityMap[self.entityType] else { - return nil - } - return entity(self.position) - } +protocol EntityPersistable: Codable { + func toEntity() -> Entity } diff --git a/star-dash/star-dash/Persistence/MonsterEntityPersistable.swift b/star-dash/star-dash/Persistence/MonsterEntityPersistable.swift new file mode 100644 index 00000000..7eb012ab --- /dev/null +++ b/star-dash/star-dash/Persistence/MonsterEntityPersistable.swift @@ -0,0 +1,21 @@ +// +// MonsterEntityPersistable.swift +// star-dash +// +// Created by Lau Rui han on 22/3/24. +// + +import Foundation + +struct MonsterEntityPersistable: Codable, EntityPersistable { + + var levelId: Int64 + var position: CGPoint + var sprite: String + var health: Int + var size: CGSize + + func toEntity() -> Entity { + Monster(position: self.position, health: self.health, sprite: self.sprite, size: self.size) + } +} diff --git a/star-dash/star-dash/Persistence/ObstacleEntityPersistable.swift b/star-dash/star-dash/Persistence/ObstacleEntityPersistable.swift new file mode 100644 index 00000000..e2e0d723 --- /dev/null +++ b/star-dash/star-dash/Persistence/ObstacleEntityPersistable.swift @@ -0,0 +1,18 @@ +// +// ObstacleEntityPersistable.swift +// star-dash +// +// Created by Lau Rui han on 22/3/24. +// + +import Foundation +struct ObstacleEntityPersistable: Codable, EntityPersistable { + + var levelId: Int64 + var position: CGPoint + var sprite: String + var size: CGSize + func toEntity() -> Entity { + Obstacle(position: self.position, sprite: self.sprite, size: self.size) + } +} diff --git a/star-dash/star-dash/Persistence/StorageManager.swift b/star-dash/star-dash/Persistence/StorageManager.swift index 1786f722..f60b5e24 100644 --- a/star-dash/star-dash/Persistence/StorageManager.swift +++ b/star-dash/star-dash/Persistence/StorageManager.swift @@ -16,7 +16,7 @@ class StorageManager { func getLevel(id: Int64) -> Level? { if let levelPersistable = self.database.getLevelPersistable(id: id) { - let entityPersistables = self.database.getEntityPersistables(levelId: id) + let entityPersistables = self.database.getAllEntities(levelId: id) return Level(levelPersistable: levelPersistable, entityPersistables: entityPersistables) } return nil diff --git a/star-dash/star-dash/Persistence/ToolEntityPersistable.swift b/star-dash/star-dash/Persistence/ToolEntityPersistable.swift new file mode 100644 index 00000000..5b41bccb --- /dev/null +++ b/star-dash/star-dash/Persistence/ToolEntityPersistable.swift @@ -0,0 +1,19 @@ +// +// ToolEntityPersistable.swift +// star-dash +// +// Created by Lau Rui han on 22/3/24. +// + +import Foundation +struct ToolEntityPersistable: Codable, EntityPersistable { + + var levelId: Int64 + var position: CGPoint + var sprite: String + var size: CGSize + + func toEntity() -> Entity { + Tool(position: self.position, sprite: self.sprite, size: self.size) + } +} diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index dbd7042b..7289eafc 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -35,6 +35,10 @@ class MTKRenderer: NSObject, Renderer { super.init() } + func updateOverlay(overlayInfo: OverlayInfo) { + playerView?.updateOverlay(score: overlayInfo.score) + } + /// Set ups the views for a single player game. func createSinglePlayerView(at superview: UIView) { let playerView = PlayerView(superview: superview, device: self.device, drawDelegate: self) diff --git a/star-dash/star-dash/Rendering/MTKRenderer/OverlayView.swift b/star-dash/star-dash/Rendering/MTKRenderer/OverlayView.swift index 10334cad..dd49363e 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/OverlayView.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/OverlayView.swift @@ -11,10 +11,9 @@ class OverlayView: UIView { let scoreLabel = UILabel() func setupSubviews() { - scoreLabel.text = "Score: 0" scoreLabel.numberOfLines = 1 scoreLabel.translatesAutoresizingMaskIntoConstraints = false - scoreLabel.textColor = .white + scoreLabel.textColor = .black addSubview(scoreLabel) NSLayoutConstraint.activate([ @@ -22,5 +21,11 @@ class OverlayView: UIView { scoreLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -1 * margin), scoreLabel.leadingAnchor.constraint(greaterThanOrEqualTo: self.leadingAnchor, constant: margin) ]) + + update(score: 0) + } + + func update(score: Int) { + scoreLabel.text = "Score: \(score)" } } diff --git a/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift b/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift index aa65fff2..85cbc703 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/PlayerView.swift @@ -35,4 +35,8 @@ class PlayerView { func setControlViewDelegate(_ delegate: ControlViewDelegate) { controlView.controlViewDelegate = delegate } + + func updateOverlay(score: Int) { + overlayView.update(score: score) + } } diff --git a/star-dash/star-dash/Rendering/OverlayInfo.swift b/star-dash/star-dash/Rendering/OverlayInfo.swift new file mode 100644 index 00000000..39078791 --- /dev/null +++ b/star-dash/star-dash/Rendering/OverlayInfo.swift @@ -0,0 +1,3 @@ +struct OverlayInfo { + let score: Int +} diff --git a/star-dash/star-dash/Rendering/Renderer.swift b/star-dash/star-dash/Rendering/Renderer.swift index 89278d8b..1cd7c11c 100644 --- a/star-dash/star-dash/Rendering/Renderer.swift +++ b/star-dash/star-dash/Rendering/Renderer.swift @@ -4,5 +4,6 @@ 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 createSinglePlayerView(at rootView: UIView) } diff --git a/star-dash/star-dash/ViewController.swift b/star-dash/star-dash/ViewController.swift index 3a6fb4c5..f1ce2a83 100644 --- a/star-dash/star-dash/ViewController.swift +++ b/star-dash/star-dash/ViewController.swift @@ -57,7 +57,7 @@ class ViewController: UIViewController { let floor = Floor(position: CGPoint(x: scene.size.width / 2, y: scene.size.height / 2 - 400)) floor.setUpAndAdd(to: entityManager) - + if let level = self.storageManager?.getLevel(id: 0) { for entity in level.entities { entity.setUpAndAdd(to: entityManager) @@ -65,6 +65,11 @@ class ViewController: UIViewController { } else { print("level not found") } + + let collectible = Collectible.createCoinCollectible( + position: CGPoint(x: scene.size.width / 2 + 30, y: scene.size.height / 2 - 100) + ) + collectible.setUpAndAdd(to: entityManager) } } @@ -74,6 +79,14 @@ extension ViewController: SDSceneDelegate { gameBridge?.syncToEntities() gameEngine?.update(by: deltaTime) gameBridge?.syncFromEntities() + + guard let gameInfo = gameEngine?.gameInfo() else { + return + } + + renderer?.updateOverlay(overlayInfo: OverlayInfo( + score: gameInfo.playerScore + )) } func contactOccured(objectA: SDObject, objectB: SDObject, contactPoint: CGPoint) {