diff --git a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDSpriteObject.swift b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDSpriteObject.swift index f6954771..f158a7e6 100644 --- a/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDSpriteObject.swift +++ b/SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDSpriteObject.swift @@ -3,6 +3,7 @@ import SpriteKit public class SDSpriteObject: SDObject { let spriteNode: SKSpriteNode + static let textureActionKey = "animation" public var activeTexture: String? public init(imageNamed: String) { @@ -19,11 +20,16 @@ public class SDSpriteObject: SDObject { let texture = loadTexture(named: named) spriteNode.run(SKAction.repeatForever( SKAction.animate(with: texture, timePerFrame: TimeInterval(0.1), resize: false, restore: true) - )) + ), withKey: SDSpriteObject.textureActionKey) activeTexture = named } + public func cancelTexture() { + spriteNode.removeAction(forKey: SDSpriteObject.textureActionKey) + activeTexture = nil + } + private func loadTexture(named: String) -> [SKTexture] { let textureAtlas = SKTextureAtlas(named: named) var frames = [SKTexture]() diff --git a/star-dash/star-dash.xcodeproj/project.pbxproj b/star-dash/star-dash.xcodeproj/project.pbxproj index 868d487b..b72f66df 100644 --- a/star-dash/star-dash.xcodeproj/project.pbxproj +++ b/star-dash/star-dash.xcodeproj/project.pbxproj @@ -100,6 +100,8 @@ 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 */; }; + 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 */; }; E6A745162BA057040080C1BE /* MTKRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745112BA057040080C1BE /* MTKRenderer.swift */; }; E6A745172BA057040080C1BE /* ControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745122BA057040080C1BE /* ControlView.swift */; }; @@ -241,6 +243,8 @@ 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 = ""; }; + 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 = ""; }; 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 = ""; }; @@ -346,6 +350,7 @@ 14D14B792BA5AC1900386C3B /* CommonEvents */ = { isa = PBXGroup; children = ( + E69FDDE52BADD11B0089D5F3 /* StopMovingEvent.swift */, 14E2478D2BA22FCE0071FFC0 /* MoveEvent.swift */, 143AA38B2BA4D3E3009C28E7 /* JumpEvent.swift */, 14D14B722BA5A3CD00386C3B /* RemoveEvent.swift */, @@ -554,6 +559,7 @@ 4E86605D2BA095CC0035530D /* Constants */ = { isa = PBXGroup; children = ( + E69FDDE32BADC2F10089D5F3 /* SpriteConstants.swift */, E69FDDE12BAD3DC40089D5F3 /* EntityConstants.swift */, 4E8660652BA097D40035530D /* PhysicsConstants.swift */, 14970F552BA8177B00CC1E8A /* GameConstants.swift */, @@ -864,6 +870,7 @@ E6A745172BA057040080C1BE /* ControlView.swift in Sources */, 14970F562BA8177B00CC1E8A /* GameConstants.swift in Sources */, 1471B0A42BA6AAF200878B14 /* PlayerDeathEvent.swift in Sources */, + E69FDDE62BADD11B0089D5F3 /* StopMovingEvent.swift in Sources */, 46D418202BA5D3420091A38B /* Collectible+Collidable.swift in Sources */, E6A7451D2BA0CAD90080C1BE /* JoystickView.swift in Sources */, E6B550A12BA15E9C00DC7396 /* OverlayView.swift in Sources */, @@ -872,6 +879,7 @@ 4E630F342B9F8FC00008F887 /* Player.swift in Sources */, 4E630F372B9F91DE0008F887 /* PlayerSprite.swift in Sources */, 14970F502BA814D500CC1E8A /* ScoreComponent.swift in Sources */, + E69FDDE42BADC2F10089D5F3 /* SpriteConstants.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/Assets.xcassets/Star.imageset/Contents.json b/star-dash/star-dash/Assets.xcassets/Star.imageset/Contents.json new file mode 100644 index 00000000..a37c8724 --- /dev/null +++ b/star-dash/star-dash/Assets.xcassets/Star.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "star.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/star-dash/star-dash/Assets.xcassets/Star.imageset/star.png b/star-dash/star-dash/Assets.xcassets/Star.imageset/star.png new file mode 100644 index 00000000..7a6d4593 Binary files /dev/null and b/star-dash/star-dash/Assets.xcassets/Star.imageset/star.png differ diff --git a/star-dash/star-dash/Constants/EntityConstants.swift b/star-dash/star-dash/Constants/EntityConstants.swift index 46f593fd..d644fe64 100644 --- a/star-dash/star-dash/Constants/EntityConstants.swift +++ b/star-dash/star-dash/Constants/EntityConstants.swift @@ -1,9 +1,8 @@ import CoreGraphics struct EntityConstants { - struct CoinCollectible { + struct StarCollectible { static let points = 10 - static let sprite = "Coin" static let size = CGSize(width: 50, height: 50) } } diff --git a/star-dash/star-dash/Constants/SpriteConstants.swift b/star-dash/star-dash/Constants/SpriteConstants.swift new file mode 100644 index 00000000..0ccdd573 --- /dev/null +++ b/star-dash/star-dash/Constants/SpriteConstants.swift @@ -0,0 +1,12 @@ +struct TextureSet { + let run: String +} + +struct SpriteConstants { + static let PlayerRedNose = "PlayerRedNose" + static let PlayerRedNoseTexture = TextureSet( + run: "PlayerRedNoseRun" + ) + + static let star = "Star" +} diff --git a/star-dash/star-dash/Events/CommonEvents/MoveEvent.swift b/star-dash/star-dash/Events/CommonEvents/MoveEvent.swift index 433a13af..a4733baf 100644 --- a/star-dash/star-dash/Events/CommonEvents/MoveEvent.swift +++ b/star-dash/star-dash/Events/CommonEvents/MoveEvent.swift @@ -20,10 +20,13 @@ class MoveEvent: Event { } func execute(on target: EventModifiable) { - guard let physicsComponent = target.component(ofType: PhysicsComponent.self, ofEntity: entityId) else { + guard let physicsComponent = target.component(ofType: PhysicsComponent.self, ofEntity: entityId), + let spriteComponent = target.component(ofType: SpriteComponent.self, ofEntity: entityId), + let textureSet = spriteComponent.textureSet else { return } physicsComponent.velocity = (toLeft ? -1 : 1) * PhysicsConstants.runVelocity + spriteComponent.textureAtlas = textureSet.run } } diff --git a/star-dash/star-dash/Events/CommonEvents/StopMovingEvent.swift b/star-dash/star-dash/Events/CommonEvents/StopMovingEvent.swift new file mode 100644 index 00000000..e8b6b1c0 --- /dev/null +++ b/star-dash/star-dash/Events/CommonEvents/StopMovingEvent.swift @@ -0,0 +1,22 @@ +import Foundation + +class StopMovingEvent: Event { + let timestamp: Date + let entityId: EntityId + + init(on entityId: EntityId) { + timestamp = Date.now + self.entityId = entityId + } + + func execute(on target: EventModifiable) { + guard let physicsComponent = target.component(ofType: PhysicsComponent.self, ofEntity: entityId), + let spriteComponent = target.component(ofType: SpriteComponent.self, ofEntity: entityId), + let textureSet = spriteComponent.textureSet else { + return + } + + physicsComponent.velocity = .zero + spriteComponent.textureAtlas = nil + } +} diff --git a/star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift b/star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift index aa15e7c9..84fc0b64 100644 --- a/star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift +++ b/star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift @@ -17,9 +17,22 @@ class SpriteModule: SyncModule { return } - // if spriteComponent.image != spriteObject.activeTexture { - // spriteObject.runTexture(named: spriteComponent.image) - // } + if spriteComponent.textureAtlas == nil && spriteObject.activeTexture != nil { + spriteObject.cancelTexture() + return + } + + guard let textureAtlas = spriteComponent.textureAtlas else { + return // no texture to run + } + + if let activeTexture = spriteObject.activeTexture, + activeTexture == textureAtlas { + return // correct texture is already running + } + + spriteObject.cancelTexture() + spriteObject.runTexture(named: textureAtlas) } func create(for object: SDObject, from entity: Entity) { @@ -30,7 +43,7 @@ extension SpriteModule: CreationModule { func createObject(from entity: Entity) -> SDObject? { var newObject = SDObject() if let spriteComponent = entityManager.component(ofType: SpriteComponent.self, of: entity.id) { - let spriteObject = SDSpriteObject(imageNamed: "PlayerRedNose") + let spriteObject = SDSpriteObject(imageNamed: spriteComponent.image) if let size = spriteComponent.size { spriteObject.size = size diff --git a/star-dash/star-dash/GameEngine/Components/SpriteComponent.swift b/star-dash/star-dash/GameEngine/Components/SpriteComponent.swift index 6059e767..be13753c 100644 --- a/star-dash/star-dash/GameEngine/Components/SpriteComponent.swift +++ b/star-dash/star-dash/GameEngine/Components/SpriteComponent.swift @@ -8,20 +8,40 @@ import Foundation class SpriteComponent: Component { - // TODO: sprite could be single image or sprite set, could use enum to seperate, - // for sprite set will need to discuss how to rep animation var image: String + var textureSet: TextureSet? var textureAtlas: String? var size: CGSize? - init(id: ComponentId, entityId: EntityId, image: String, textureAtlas: String?, size: CGSize?) { + init( + id: ComponentId, + entityId: EntityId, + image: String, + textureSet: TextureSet?, + textureAtlas: String?, + size: CGSize? + ) { self.image = image self.size = size + self.textureSet = textureSet self.textureAtlas = textureAtlas super.init(id: id, entityId: entityId) } - convenience init(entityId: EntityId, image: String, textureAtlas: String?, size: CGSize?) { - self.init(id: UUID(), entityId: entityId, image: image, textureAtlas: textureAtlas, size: size) + convenience init( + entityId: EntityId, + image: String, + textureSet: TextureSet?, + textureAtlas: String?, + size: CGSize? + ) { + self.init( + id: UUID(), + entityId: entityId, + image: image, + textureSet: textureSet, + 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 f7d5d59c..b7544059 100644 --- a/star-dash/star-dash/GameEngine/Entities/GameEntities/Collectible.swift +++ b/star-dash/star-dash/GameEngine/Entities/GameEntities/Collectible.swift @@ -34,7 +34,13 @@ class Collectible: Entity { 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 spriteComponent = SpriteComponent( + entityId: self.id, + image: sprite, + textureSet: nil, + textureAtlas: nil, + size: size + ) let pointsComponent = PointsComponent(entityId: self.id, points: points) to.add(entity: self) @@ -44,12 +50,12 @@ class Collectible: Entity { to.add(component: pointsComponent) } - static func createCoinCollectible(position: CGPoint) -> Collectible { + static func createStarCollectible(position: CGPoint) -> Collectible { Collectible( position: position, - sprite: EntityConstants.CoinCollectible.sprite, - points: EntityConstants.CoinCollectible.points, - size: EntityConstants.CoinCollectible.size + sprite: SpriteConstants.star, + points: EntityConstants.StarCollectible.points, + size: EntityConstants.StarCollectible.size ) } } diff --git a/star-dash/star-dash/GameEngine/Entities/GameEntities/Player.swift b/star-dash/star-dash/GameEngine/Entities/GameEntities/Player.swift index de6c668c..041ad50b 100644 --- a/star-dash/star-dash/GameEngine/Entities/GameEntities/Player.swift +++ b/star-dash/star-dash/GameEngine/Entities/GameEntities/Player.swift @@ -36,8 +36,9 @@ class Player: Entity { physicsComponent.restitution = 0.0 let spriteComponent = SpriteComponent( entityId: self.id, - image: "PlayerRedNose", - textureAtlas: "", + image: SpriteConstants.PlayerRedNose, + textureSet: SpriteConstants.PlayerRedNoseTexture, + textureAtlas: nil, size: CGSize(width: 100, height: 140) ) let scoreComponent = ScoreComponent(entityId: self.id, score: 0) diff --git a/star-dash/star-dash/GameEngine/GameEngine.swift b/star-dash/star-dash/GameEngine/GameEngine.swift index 54ae9b84..7923be09 100644 --- a/star-dash/star-dash/GameEngine/GameEngine.swift +++ b/star-dash/star-dash/GameEngine/GameEngine.swift @@ -57,7 +57,6 @@ class GameEngine { func handlePlayerMove(toLeft: Bool) { guard let playerEntityId = entityManager.playerEntityId(), - let physicsComponent = entityManager.component(ofType: PhysicsComponent.self, of: playerEntityId), let playerComponent = entityManager.component(ofType: PlayerComponent.self, of: playerEntityId), playerComponent.canMove else { return @@ -66,6 +65,14 @@ class GameEngine { eventManager.add(event: MoveEvent(on: playerEntityId, toLeft: toLeft)) } + func handlePlayerStoppedMoving() { + guard let playerEntityId = entityManager.playerEntityId() else { + return + } + + eventManager.add(event: StopMovingEvent(on: playerEntityId)) + } + private func setUpSystems() { systemManager.add(PositionSystem(entityManager, dispatcher: self)) systemManager.add(PhysicsSystem(entityManager, dispatcher: self)) diff --git a/star-dash/star-dash/Persistence/Database.swift b/star-dash/star-dash/Persistence/Database.swift index b366a869..aad42064 100644 --- a/star-dash/star-dash/Persistence/Database.swift +++ b/star-dash/star-dash/Persistence/Database.swift @@ -240,7 +240,11 @@ extension Database { let jsonData = try Data(contentsOf: fileURL) // 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) + let levelPersistable = LevelPersistable( + id: levelData.id, + name: levelData.name, + size: levelData.size + ) insert(persistable: levelPersistable) for persistable in levelData.collectibles { insert(persistable: persistable) diff --git a/star-dash/star-dash/Rendering/ControlViewDelegate.swift b/star-dash/star-dash/Rendering/ControlViewDelegate.swift index a61d330f..0184c992 100644 --- a/star-dash/star-dash/Rendering/ControlViewDelegate.swift +++ b/star-dash/star-dash/Rendering/ControlViewDelegate.swift @@ -1,5 +1,6 @@ protocol ControlViewDelegate: AnyObject { func joystickMoved(toLeft: Bool) + func joystickReleased() func jumpButtonPressed() } diff --git a/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift b/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift index 2850aa52..6952acc6 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift @@ -65,13 +65,19 @@ class ControlView: UIView { override func touchesBegan(_ touches: Set, with event: UIEvent?) { super.touchesBegan(touches, with: event) - guard let firstTouch = touches.first, + guard let joystickView = joystickView, + let firstTouch = touches.first, firstTouch.location(in: self).x < self.frame.width / 2, touches.count == 1 else { return } - joystickView?.moveJoystick(location: firstTouch.location(in: joystickView)) + if shouldSendMoveEvent(location: firstTouch.location(in: self)) { + let isLeft = firstTouch.location(in: joystickView).x < joystickView.center.x + controlViewDelegate?.joystickMoved(toLeft: isLeft) + } + + joystickView.moveJoystick(location: firstTouch.location(in: joystickView)) } override func touchesEnded(_ touches: Set, with event: UIEvent?) { @@ -82,6 +88,7 @@ class ControlView: UIView { return } + controlViewDelegate?.joystickReleased() joystickView?.returnJoystick() } @@ -92,6 +99,7 @@ class ControlView: UIView { let location = gesture.location(in: self) if gesture.state == .ended { + controlViewDelegate?.joystickReleased() joystickView.returnJoystick() } else if location.x < self.frame.width / 2 { joystickView.moveJoystick(location: gesture.location(in: joystickView)) diff --git a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift index 7289eafc..fc3dc768 100644 --- a/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift +++ b/star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift @@ -78,6 +78,10 @@ extension MTKRenderer: ControlViewDelegate { viewDelegate?.joystickMoved(toLeft: toLeft) } + func joystickReleased() { + viewDelegate?.joystickReleased() + } + func jumpButtonPressed() { viewDelegate?.jumpButtonPressed() } diff --git a/star-dash/star-dash/Rendering/ViewDelegate.swift b/star-dash/star-dash/Rendering/ViewDelegate.swift index ffe4d356..05195180 100644 --- a/star-dash/star-dash/Rendering/ViewDelegate.swift +++ b/star-dash/star-dash/Rendering/ViewDelegate.swift @@ -1,5 +1,6 @@ protocol ViewDelegate: AnyObject { func joystickMoved(toLeft: Bool) + func joystickReleased() func jumpButtonPressed() } diff --git a/star-dash/star-dash/ViewController.swift b/star-dash/star-dash/ViewController.swift index f1ce2a83..ac4b904e 100644 --- a/star-dash/star-dash/ViewController.swift +++ b/star-dash/star-dash/ViewController.swift @@ -66,7 +66,7 @@ class ViewController: UIViewController { print("level not found") } - let collectible = Collectible.createCoinCollectible( + let collectible = Collectible.createStarCollectible( position: CGPoint(x: scene.size.width / 2 + 30, y: scene.size.height / 2 - 100) ) collectible.setUpAndAdd(to: entityManager) @@ -105,6 +105,10 @@ extension ViewController: ViewDelegate { gameEngine?.handlePlayerMove(toLeft: toLeft) } + func joystickReleased() { + gameEngine?.handlePlayerStoppedMoving() + } + func jumpButtonPressed() { gameEngine?.handlePlayerJump() }