diff --git a/TowerForge/TowerForge.xcodeproj/project.pbxproj b/TowerForge/TowerForge.xcodeproj/project.pbxproj index be8a3bb8..87ccf2ad 100644 --- a/TowerForge/TowerForge.xcodeproj/project.pbxproj +++ b/TowerForge/TowerForge.xcodeproj/project.pbxproj @@ -14,7 +14,7 @@ 3C9955A52BA47DC600D33FA5 /* BaseProjectile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9955A42BA47DC600D33FA5 /* BaseProjectile.swift */; }; 3C9955AD2BA483B100D33FA5 /* TFSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9955AC2BA483B100D33FA5 /* TFSystem.swift */; }; 3C9955AF2BA48FD200D33FA5 /* MeleeUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9955AE2BA48FD200D33FA5 /* MeleeUnit.swift */; }; - 3C9955B12BA4ACA100D33FA5 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9955B02BA4ACA100D33FA5 /* Arrow.swift */; }; + 3C9955B12BA4ACA100D33FA5 /* Bullet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9955B02BA4ACA100D33FA5 /* Bullet.swift */; }; 3C9955B42BA4B12000D33FA5 /* ArrowTower.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9955B32BA4B12000D33FA5 /* ArrowTower.swift */; }; 3C9955BA2BA5637200D33FA5 /* DamageEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9955B92BA5637200D33FA5 /* DamageEvent.swift */; }; 3C9955BC2BA563A800D33FA5 /* TFEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9955BB2BA563A800D33FA5 /* TFEvent.swift */; }; @@ -34,9 +34,12 @@ 3CE951512BAC8955008B2785 /* Renderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CE951502BAC8955008B2785 /* Renderable.swift */; }; 3CE951562BACA0CF008B2785 /* Collidable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CE951552BACA0CF008B2785 /* Collidable.swift */; }; 3CE951582BAD724D008B2785 /* TFContact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CE951572BAD724D008B2785 /* TFContact.swift */; }; + 3CE9515F2BADE2C5008B2785 /* ShootingSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CE9515E2BADE2C5008B2785 /* ShootingSystem.swift */; }; + 3CE951612BADE881008B2785 /* Spawnable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CE951602BADE881008B2785 /* Spawnable.swift */; }; + 3CE951632BAE037C008B2785 /* AiSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CE951622BAE037C008B2785 /* AiSystem.swift */; }; 5200624E2BA8D597000DBA30 /* AiComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5200624D2BA8D597000DBA30 /* AiComponent.swift */; }; 520062522BA8DA09000DBA30 /* UnitGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520062512BA8DA09000DBA30 /* UnitGenerator.swift */; }; - 520062562BA8E026000DBA30 /* Spawnable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520062552BA8E026000DBA30 /* Spawnable.swift */; }; + 520062562BA8E026000DBA30 /* PlayerSpawnable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520062552BA8E026000DBA30 /* PlayerSpawnable.swift */; }; 520062582BA8ED73000DBA30 /* HomeComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520062572BA8ED73000DBA30 /* HomeComponent.swift */; }; 523923E72BADC8530044BA61 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 523923E62BADC8530044BA61 /* Launch Screen.storyboard */; }; 52578B822BA61AAF00B4D76C /* PositionComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52578B812BA61AAF00B4D76C /* PositionComponent.swift */; }; @@ -104,7 +107,7 @@ 3C9955A42BA47DC600D33FA5 /* BaseProjectile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseProjectile.swift; sourceTree = ""; }; 3C9955AC2BA483B100D33FA5 /* TFSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TFSystem.swift; sourceTree = ""; }; 3C9955AE2BA48FD200D33FA5 /* MeleeUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeleeUnit.swift; sourceTree = ""; }; - 3C9955B02BA4ACA100D33FA5 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = ""; }; + 3C9955B02BA4ACA100D33FA5 /* Bullet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bullet.swift; sourceTree = ""; }; 3C9955B32BA4B12000D33FA5 /* ArrowTower.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowTower.swift; sourceTree = ""; }; 3C9955B92BA5637200D33FA5 /* DamageEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamageEvent.swift; sourceTree = ""; }; 3C9955BB2BA563A800D33FA5 /* TFEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TFEvent.swift; sourceTree = ""; }; @@ -124,9 +127,12 @@ 3CE951502BAC8955008B2785 /* Renderable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Renderable.swift; sourceTree = ""; }; 3CE951552BACA0CF008B2785 /* Collidable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collidable.swift; sourceTree = ""; }; 3CE951572BAD724D008B2785 /* TFContact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TFContact.swift; sourceTree = ""; }; + 3CE9515E2BADE2C5008B2785 /* ShootingSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShootingSystem.swift; sourceTree = ""; }; + 3CE951602BADE881008B2785 /* Spawnable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Spawnable.swift; sourceTree = ""; }; + 3CE951622BAE037C008B2785 /* AiSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AiSystem.swift; sourceTree = ""; }; 5200624D2BA8D597000DBA30 /* AiComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AiComponent.swift; sourceTree = ""; }; 520062512BA8DA09000DBA30 /* UnitGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitGenerator.swift; sourceTree = ""; }; - 520062552BA8E026000DBA30 /* Spawnable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Spawnable.swift; sourceTree = ""; }; + 520062552BA8E026000DBA30 /* PlayerSpawnable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerSpawnable.swift; sourceTree = ""; }; 520062572BA8ED73000DBA30 /* HomeComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeComponent.swift; sourceTree = ""; }; 523923E62BADC8530044BA61 /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; 52578B812BA61AAF00B4D76C /* PositionComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionComponent.swift; sourceTree = ""; }; @@ -203,7 +209,7 @@ children = ( 3CE9514C2BAC8668008B2785 /* Base Entities */, 3C9955AE2BA48FD200D33FA5 /* MeleeUnit.swift */, - 3C9955B02BA4ACA100D33FA5 /* Arrow.swift */, + 3C9955B02BA4ACA100D33FA5 /* Bullet.swift */, 3C9955B32BA4B12000D33FA5 /* ArrowTower.swift */, 52578B8B2BA627B200B4D76C /* Team.swift */, 529F91872BA6D7A7009551D9 /* SoldierUnit.swift */, @@ -232,6 +238,8 @@ 3C769A712BA58DE700F454F9 /* MovementSystem.swift */, 3C769A732BA591BD00F454F9 /* SpawnSystem.swift */, BA443D3C2BAD9557009F0FFB /* RemoveSystem.swift */, + 3CE9515E2BADE2C5008B2785 /* ShootingSystem.swift */, + 3CE951622BAE037C008B2785 /* AiSystem.swift */, ); path = Systems; sourceTree = ""; @@ -435,7 +443,8 @@ isa = PBXGroup; children = ( 52DF5FE82BA33F9700135367 /* Animatable.swift */, - 520062552BA8E026000DBA30 /* Spawnable.swift */, + 520062552BA8E026000DBA30 /* PlayerSpawnable.swift */, + 3CE951602BADE881008B2785 /* Spawnable.swift */, ); path = Protocols; sourceTree = ""; @@ -642,6 +651,8 @@ 52578B822BA61AAF00B4D76C /* PositionComponent.swift in Sources */, 3C9955A32BA47DBB00D33FA5 /* BaseUnit.swift in Sources */, 3C9955BA2BA5637200D33FA5 /* DamageEvent.swift in Sources */, + 3CE951632BAE037C008B2785 /* AiSystem.swift in Sources */, + 3CE9515F2BADE2C5008B2785 /* ShootingSystem.swift in Sources */, 3C9955CA2BA5888F00D33FA5 /* SpawnEvent.swift in Sources */, 3CE951582BAD724D008B2785 /* TFContact.swift in Sources */, 5295A2132BAAEA16005018A8 /* UnitNode.swift in Sources */, @@ -664,6 +675,7 @@ 3CE951562BACA0CF008B2785 /* Collidable.swift in Sources */, 52DF5FE62BA33AF300135367 /* TFSpriteNode.swift in Sources */, 3C9955B42BA4B12000D33FA5 /* ArrowTower.swift in Sources */, + 3CE951612BADE881008B2785 /* Spawnable.swift in Sources */, 52DF5FE92BA33F9700135367 /* Animatable.swift in Sources */, 3C9955AF2BA48FD200D33FA5 /* MeleeUnit.swift in Sources */, 5295A2022BA9FBD9005018A8 /* SceneManagerDelegate.swift in Sources */, @@ -671,7 +683,7 @@ 520062582BA8ED73000DBA30 /* HomeComponent.swift in Sources */, 52DF5FA82BA32B2300135367 /* AppDelegate.swift in Sources */, 3C769A742BA591BD00F454F9 /* SpawnSystem.swift in Sources */, - 3C9955B12BA4ACA100D33FA5 /* Arrow.swift in Sources */, + 3C9955B12BA4ACA100D33FA5 /* Bullet.swift in Sources */, 3CE9514F2BAC8936008B2785 /* Renderer.swift in Sources */, 3C769A722BA58DE700F454F9 /* MovementSystem.swift in Sources */, 52DF5FEB2BA3400C00135367 /* TFAnimatableNode.swift in Sources */, @@ -680,7 +692,7 @@ 52DF5FED2BA34D0300135367 /* TFComponent.swift in Sources */, 527E3A242BA613F000FE1628 /* PlayerComponent.swift in Sources */, 3C9955C52BA585DD00D33FA5 /* HealthSystem.swift in Sources */, - 520062562BA8E026000DBA30 /* Spawnable.swift in Sources */, + 520062562BA8E026000DBA30 /* PlayerSpawnable.swift in Sources */, 52DF5FFB2BA3601400135367 /* HealthComponent.swift in Sources */, 3C9955BC2BA563A800D33FA5 /* TFEvent.swift in Sources */, BA443D3F2BAD9774009F0FFB /* RemoveEvent.swift in Sources */, diff --git a/TowerForge/TowerForge/GameWorld.swift b/TowerForge/TowerForge/GameWorld.swift index b395cfa3..23e99e74 100644 --- a/TowerForge/TowerForge/GameWorld.swift +++ b/TowerForge/TowerForge/GameWorld.swift @@ -29,6 +29,7 @@ class GameWorld { } renderer = Renderer(target: self, scene: scene) + self.setUpSystems() self.setUpSelectionNode() self.setupTeam() } @@ -40,7 +41,6 @@ class GameWorld { systemManager.update(deltaTime) eventManager.executeEvents(in: self) - entityManager.update(deltaTime) renderer?.render() } @@ -91,6 +91,15 @@ class GameWorld { // TODO: Handle any separation logic here. } + private func setUpSystems() { + systemManager.add(system: HealthSystem(entityManager: entityManager, eventManager: eventManager)) + systemManager.add(system: MovementSystem(entityManager: entityManager, eventManager: eventManager)) + systemManager.add(system: RemoveSystem(entityManager: entityManager, eventManager: eventManager)) + systemManager.add(system: SpawnSystem(entityManager: entityManager, eventManager: eventManager)) + systemManager.add(system: ShootingSystem(entityManager: entityManager, eventManager: eventManager)) + systemManager.add(system: AiSystem(entityManager: entityManager, eventManager: eventManager)) + } + private func setUpSelectionNode() { selectionNode.delegate = grid scene?.addChild(selectionNode) diff --git a/TowerForge/TowerForge/Grid.swift b/TowerForge/TowerForge/Grid.swift index 2a843881..c7e74ef9 100644 --- a/TowerForge/TowerForge/Grid.swift +++ b/TowerForge/TowerForge/Grid.swift @@ -22,6 +22,12 @@ class Grid: UnitSelectionNodeDelegate { self.height = screenSize.height } + func unitSelectionNodeDidSpawn(ofType type: T.Type, position: CGPoint) { + let snapPosition = CGPoint(x: position.x, y: snapYPosition(yPosition: position.y)) + let unit = UnitGenerator.spawn(ofType: type, at: snapPosition, player: Player.ownPlayer) + entityManager.add(unit) + } + func generateTileMap(scene: SKScene) { let screenWidth = self.width let screenHeight = self.height @@ -41,14 +47,6 @@ class Grid: UnitSelectionNodeDelegate { } } } - func unitSelectionNodeDidSpawn(ofType type: T.Type, position: CGPoint) { - let snapPosition = CGPoint(x: position.x, y: snapYPosition(yPosition: position.y)) - let unit = UnitGenerator.spawn(ofType: type, - at: snapPosition, - player: Player.ownPlayer, - entityManager: entityManager) - entityManager.add(unit) - } private func snapYPosition(yPosition: Double) -> Double { let normalizedYPosition = normalizeYPosition(yPosition: yPosition) diff --git a/TowerForge/TowerForge/LevelManager/Components/AiComponent.swift b/TowerForge/TowerForge/LevelManager/Components/AiComponent.swift index 583300d1..758f841b 100644 --- a/TowerForge/TowerForge/LevelManager/Components/AiComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/AiComponent.swift @@ -10,10 +10,10 @@ import UIKit class AiComponent: TFComponent { private var entityManager: EntityManager - private var chosenUnit: (BaseUnit & Spawnable).Type? + private var chosenUnit: (TFEntity & PlayerSpawnable).Type? init(entityManager: EntityManager) { self.entityManager = entityManager - self.chosenUnit = SpawnableEntities.possibleUnits.randomElement() + self.chosenUnit = SpawnableEntities.playerSpawnableEntities.randomElement() super.init() } @@ -22,20 +22,17 @@ class AiComponent: TFComponent { let chosenUnit = chosenUnit else { return } - - // Generate random coordinates within the defined range let randomY = CGFloat.random(in: 0...UIScreen.main.bounds.height) if homeComponent.points >= chosenUnit.cost { let unit = UnitGenerator.spawn(ofType: chosenUnit, at: CGPoint(x: UIScreen.main.bounds.width, y: randomY), - player: .oppositePlayer, - entityManager: entityManager) + player: .oppositePlayer) homeComponent.decreasePoints(chosenUnit.cost) // Re-randomize the unit - self.chosenUnit = SpawnableEntities.possibleUnits.randomElement() + self.chosenUnit = SpawnableEntities.playerSpawnableEntities.randomElement() entityManager.add(unit) } } diff --git a/TowerForge/TowerForge/LevelManager/Components/GameComponents/DamageComponent.swift b/TowerForge/TowerForge/LevelManager/Components/GameComponents/DamageComponent.swift index cc5ac189..a3294f87 100644 --- a/TowerForge/TowerForge/LevelManager/Components/GameComponents/DamageComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/GameComponents/DamageComponent.swift @@ -6,20 +6,17 @@ // import Foundation -import CoreGraphics import SpriteKit class DamageComponent: TFComponent { private let attackRate: TimeInterval private var lastAttackTime = TimeInterval(0) - private let entityManager: EntityManager private let temporary: Bool let attackPower: CGFloat - init(attackRate: TimeInterval, attackPower: CGFloat, temporary: Bool, entityManager: EntityManager) { + init(attackRate: TimeInterval, attackPower: CGFloat, temporary: Bool) { self.attackRate = attackRate self.attackPower = attackPower - self.entityManager = entityManager self.temporary = temporary super.init() } @@ -28,8 +25,8 @@ class DamageComponent: TFComponent { CACurrentMediaTime() - lastAttackTime >= attackRate } - func damage(_ healthComponent: HealthComponent) -> DamageEvent? { - guard canDamage, let entityId = healthComponent.entity?.id else { + func damage(_ healthComponent: HealthComponent) -> TFEvent? { + guard canDamage, let enemyId = healthComponent.entity?.id, let id = entity?.id else { return nil } @@ -40,6 +37,11 @@ class DamageComponent: TFComponent { } lastAttackTime = CACurrentMediaTime() - return DamageEvent(on: entityId, at: lastAttackTime, with: attackPower) + let event = DamageEvent(on: enemyId, at: lastAttackTime, with: attackPower) + + if temporary { + return event.concurrentlyWith(RemoveEvent(on: id, at: lastAttackTime)) + } + return event } } diff --git a/TowerForge/TowerForge/LevelManager/Components/GameComponents/HealthComponent.swift b/TowerForge/TowerForge/LevelManager/Components/GameComponents/HealthComponent.swift index 614af0ce..355e9d71 100644 --- a/TowerForge/TowerForge/LevelManager/Components/GameComponents/HealthComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/GameComponents/HealthComponent.swift @@ -10,29 +10,16 @@ import Foundation class HealthComponent: TFComponent { var currentHealth: CGFloat var maxHealth: CGFloat - private let entityManager: EntityManager var isZero: Bool { currentHealth.isZero } - init(maxHealth: CGFloat, entityManager: EntityManager) { + init(maxHealth: CGFloat) { self.currentHealth = maxHealth self.maxHealth = maxHealth - self.entityManager = entityManager super.init() } - override func update(deltaTime: TimeInterval) { - if self.currentHealth <= 0 { - guard let entity = entity, - let spriteComponent = entity.component(ofType: SpriteComponent.self) else { - return - } - // Need to remove the entity entirely if the health goes to zero or less - self.entityManager.removeEntity(with: entity.id) - } - } - /// Adjusts health by the specified amount. func adjustHealth(amount: CGFloat) { if amount < 0 { diff --git a/TowerForge/TowerForge/LevelManager/Components/GameComponents/ShootingComponent.swift b/TowerForge/TowerForge/LevelManager/Components/GameComponents/ShootingComponent.swift index a3440b98..ab6beb3f 100644 --- a/TowerForge/TowerForge/LevelManager/Components/GameComponents/ShootingComponent.swift +++ b/TowerForge/TowerForge/LevelManager/Components/GameComponents/ShootingComponent.swift @@ -12,61 +12,37 @@ class ShootingComponent: TFComponent { var fireRate: TimeInterval // Delay between shots var range: CGFloat private var lastShotTime = TimeInterval(0) - private let entityManager: EntityManager let attackPower: CGFloat - init(fireRate: TimeInterval, range: CGFloat, entityManager: EntityManager, attackPower: CGFloat) { + init(fireRate: TimeInterval, range: CGFloat, attackPower: CGFloat) { self.fireRate = fireRate self.range = range - self.entityManager = entityManager self.attackPower = attackPower super.init() } - override func update(deltaTime: TimeInterval) { - super.update(deltaTime: deltaTime) + var canShoot: Bool { + CACurrentMediaTime() - lastShotTime >= fireRate + } - // Required components for the current Melee - guard let entity = entity, - let spriteComponent = entity.component(ofType: SpriteComponent.self), - let positionComponent = entity.component(ofType: PositionComponent.self) else { - return + func shoot(_ healthComponent: HealthComponent) -> SpawnEvent? { + guard canShoot, let entityA = self.entity, let entityB = healthComponent.entity else { + return nil } - // Loop opposite team's entities - for entity in entityManager.entities { - guard let playerComponent = entity.component(ofType: PlayerComponent.self) else { - return - } - if playerComponent.player == .ownPlayer { - return - } - // Get opposite team's components - guard let oppositeSpriteComponent = entity.component(ofType: SpriteComponent.self), - let oppositeHealthComponent = entity.component(ofType: HealthComponent.self), - let oppositePositionComponent = entity.component(ofType: PositionComponent.self) else { - return - } - - // Get the horizontal distance - let distanceBetween = (positionComponent.position.x - oppositePositionComponent.position.x) - - // Check if within range - if distanceBetween < range { - // TODO : Change the hard coded velocity value - let arrow = Arrow(position: positionComponent.position, - velocity: playerComponent.player.getDirectionVelocity(), - attackRate: 1.0, - entityManager: entityManager) - guard let arrowSpriteComponent = arrow.component(ofType: SpriteComponent.self) else { - return - } + guard let playerA = entityA.component(ofType: PlayerComponent.self)?.player, + let playerB = entityB.component(ofType: PlayerComponent.self)?.player, + playerA != playerB else { + return nil + } - // Check if can attack - if CACurrentMediaTime() - lastShotTime > fireRate { - lastShotTime = CACurrentMediaTime() - } - } + guard let positionA = entityA.component(ofType: PositionComponent.self)?.position, + let positionB = entityB.component(ofType: PositionComponent.self)?.position, + abs(positionA.x - positionB.x) <= range, abs(positionA.y - positionB.y) <= 50 else { + return nil } + + lastShotTime = CACurrentMediaTime() + return SpawnEvent(ofType: Bullet.self, timestamp: lastShotTime, position: positionA, player: playerA) } } diff --git a/TowerForge/TowerForge/LevelManager/Entities/ArrowTower.swift b/TowerForge/TowerForge/LevelManager/Entities/ArrowTower.swift index e96bb595..465fd37e 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/ArrowTower.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/ArrowTower.swift @@ -7,23 +7,25 @@ import Foundation -class ArrowTower: BaseTower { +class ArrowTower: BaseTower, PlayerSpawnable { + static let title: String = "arrowTower" static let textureNames = ["LightHouse-1"] static let size = CGSize(width: 100, height: 100) static let key = "arrowTower" static let maxHealth = 200.0 static let damage = 10.0 + static var cost = 10 static let fireRate = 1.0 - init(position: CGPoint, entityManager: EntityManager) { + required init(position: CGPoint, player: Player) { super.init(textureNames: ArrowTower.textureNames, size: ArrowTower.size, key: ArrowTower.key, position: position, - maxHealth: ArrowTower.maxHealth, entityManager: entityManager) + maxHealth: ArrowTower.maxHealth, + player: player) self.addComponent(ShootingComponent(fireRate: ArrowTower.fireRate, range: 1.0, - entityManager: entityManager, attackPower: ArrowTower.damage)) } } diff --git a/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseProjectile.swift b/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseProjectile.swift index 27ec05cd..03d58308 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseProjectile.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseProjectile.swift @@ -8,12 +8,13 @@ import Foundation class BaseProjectile: TFEntity { - init(textureNames: [String], size: CGSize, key: String, position: CGPoint, velocity: CGVector = .zero) { + init(textureNames: [String], size: CGSize, key: String, position: CGPoint, player: Player, velocity: CGVector = .zero) { super.init() createSpriteComponent(textureNames: textureNames, size: size, key: key, position: position) createMovableComponent(position: position, velocity: velocity) createPositionComponent(position: position) + createPlayerComponent(player: player) } private func createSpriteComponent(textureNames: [String], size: CGSize, key: String, position: CGPoint) { @@ -34,4 +35,9 @@ class BaseProjectile: TFEntity { let movableComponent = MovableComponent(position: position, velocity: velocity) self.addComponent(movableComponent) } + + private func createPlayerComponent(player: Player) { + let playerComponent = PlayerComponent(player: player) + self.addComponent(playerComponent) + } } diff --git a/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseTower.swift b/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseTower.swift index d2a13767..c60265be 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseTower.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseTower.swift @@ -13,12 +13,13 @@ class BaseTower: TFEntity { key: String, position: CGPoint, maxHealth: CGFloat, - entityManager: EntityManager) { + player: Player) { super.init() - createHealthComponent(maxHealth: maxHealth, entityManager: entityManager) + createHealthComponent(maxHealth: maxHealth) createSpriteComponent(textureNames: textureNames, size: size, key: key, position: position) createPositionComponent(position: position) + createPlayerComponent(player: player) } override func collide(with other: any Collidable) -> TFEvent? { @@ -34,15 +35,15 @@ class BaseTower: TFEntity { } override func collide(with damageComponent: DamageComponent) -> TFEvent? { - guard self.hasComponent(ofType: HealthComponent.self) else { + guard let healthComponent = self.component(ofType: HealthComponent.self) else { return nil } // No call to super here as super is done on collide with Collidable above. - return DamageEvent(on: self.id, at: Date().timeIntervalSince1970, with: damageComponent.attackPower) + return damageComponent.damage(healthComponent) } - private func createHealthComponent(maxHealth: CGFloat, entityManager: EntityManager) { - let healthComponent = HealthComponent(maxHealth: maxHealth, entityManager: entityManager) + private func createHealthComponent(maxHealth: CGFloat) { + let healthComponent = HealthComponent(maxHealth: maxHealth) self.addComponent(healthComponent) } private func createPositionComponent(position: CGPoint) { @@ -58,4 +59,9 @@ class BaseTower: TFEntity { animatableKey: key) self.addComponent(spriteComponent) } + + private func createPlayerComponent(player: Player) { + let playerComponent = PlayerComponent(player: player) + self.addComponent(playerComponent) + } } diff --git a/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseUnit.swift b/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseUnit.swift index 3eee9f92..c0b884d4 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseUnit.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/Base Entities/BaseUnit.swift @@ -7,43 +7,17 @@ import Foundation -enum UnitType { - case melee - case soldier - static let possibleUnits = [melee, soldier] - - var cost: Int { - switch self { - case .melee: - return MeleeUnit.cost - case .soldier: - return SoldierUnit.cost - } - } - - // TODO: A better way to do this - var title: String { - switch self { - case .melee: - return "melee" - case .soldier: - return "soldier" - } - } -} - class BaseUnit: TFEntity { init(textureNames: [String], size: CGSize, key: String, position: CGPoint, maxHealth: CGFloat, - entityManager: EntityManager, velocity: CGVector, player: Player) { super.init() createPlayerComponent(player: player) - createHealthComponent(maxHealth: maxHealth, entityManager: entityManager) + createHealthComponent(maxHealth: maxHealth) createSpriteComponent(textureNames: textureNames, size: size, key: key, position: position) createMovableComponent(position: position, velocity: velocity) createPositionComponent(position: position) @@ -62,17 +36,18 @@ class BaseUnit: TFEntity { } override func collide(with damageComponent: DamageComponent) -> TFEvent? { - guard self.hasComponent(ofType: HealthComponent.self) else { + guard let healthComponent = self.component(ofType: HealthComponent.self) else { return nil } // No call to super here as super is done on collide with Collidable above. - return DamageEvent(on: self.id, at: Date().timeIntervalSince1970, with: damageComponent.attackPower) + return damageComponent.damage(healthComponent) } - private func createHealthComponent(maxHealth: CGFloat, entityManager: EntityManager) { - let healthComponent = HealthComponent(maxHealth: maxHealth, entityManager: entityManager) + private func createHealthComponent(maxHealth: CGFloat) { + let healthComponent = HealthComponent(maxHealth: maxHealth) self.addComponent(healthComponent) } + private func createPositionComponent(position: CGPoint) { let positionComponent = PositionComponent(position: position) self.addComponent(positionComponent) @@ -91,6 +66,7 @@ class BaseUnit: TFEntity { let movableComponent = MovableComponent(position: position, velocity: velocity) self.addComponent(movableComponent) } + private func createPlayerComponent(player: Player) { let playerComponent = PlayerComponent(player: player) self.addComponent(playerComponent) diff --git a/TowerForge/TowerForge/LevelManager/Entities/Arrow.swift b/TowerForge/TowerForge/LevelManager/Entities/Bullet.swift similarity index 56% rename from TowerForge/TowerForge/LevelManager/Entities/Arrow.swift rename to TowerForge/TowerForge/LevelManager/Entities/Bullet.swift index 05b8e3b4..bf400ed7 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/Arrow.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/Bullet.swift @@ -1,28 +1,31 @@ // -// Arrow.swift +// Bullet.swift // TowerForge // // Created by Zheng Ze on 16/3/24. // import Foundation +import SpriteKit -class Arrow: BaseProjectile { - static let textureNames: [String] = [] +class Bullet: BaseProjectile, Spawnable { + static let textureNames: [String] = ["bullet"] static let size = CGSize(width: 10, height: 10) - static let key = "arrow" + static let key = "bullet" static let damage = 5.0 + static let attackRate = 1.0 + static let velocity = CGVector(dx: 100, dy: 0) - init(position: CGPoint, velocity: CGVector, attackRate: TimeInterval, entityManager: EntityManager) { - super.init(textureNames: Arrow.textureNames, - size: Arrow.size, - key: Arrow.key, + required init(position: CGPoint, player: Player) { + super.init(textureNames: Bullet.textureNames, + size: Bullet.size, + key: Bullet.key, position: position, - velocity: velocity) - self.addComponent(DamageComponent(attackRate: attackRate, - attackPower: Arrow.damage, - temporary: true, - entityManager: entityManager)) + player: player, + velocity: Bullet.velocity) + self.addComponent(DamageComponent(attackRate: Bullet.attackRate, + attackPower: Bullet.damage, + temporary: true)) } override func collide(with other: any Collidable) -> TFEvent? { diff --git a/TowerForge/TowerForge/LevelManager/Entities/MeleeUnit.swift b/TowerForge/TowerForge/LevelManager/Entities/MeleeUnit.swift index 5c350cb2..99521e9e 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/MeleeUnit.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/MeleeUnit.swift @@ -7,7 +7,7 @@ import Foundation -class MeleeUnit: BaseUnit, Spawnable { +class MeleeUnit: BaseUnit, PlayerSpawnable { static let title: String = "melee" static let textureNames = ["melee-1", "melee-2"] static let size = CGSize(width: 100, height: 100) @@ -18,20 +18,17 @@ class MeleeUnit: BaseUnit, Spawnable { static let attackRate = 1.0 static let velocity = CGVector(dx: 10.0, dy: 0.0) - required init(position: CGPoint, entityManager: EntityManager, player: Player) { + required init(position: CGPoint, player: Player) { super.init(textureNames: MeleeUnit.textureNames, size: MeleeUnit.size, key: MeleeUnit.key, - position: position, maxHealth: MeleeUnit.maxHealth, - entityManager: entityManager, velocity: MeleeUnit.velocity, player: player) self.addComponent(DamageComponent(attackRate: MeleeUnit.attackRate, attackPower: MeleeUnit.damage, - temporary: false, - entityManager: entityManager)) + temporary: false)) } override func collide(with other: any Collidable) -> (any TFEvent)? { diff --git a/TowerForge/TowerForge/LevelManager/Entities/SoldierUnit.swift b/TowerForge/TowerForge/LevelManager/Entities/SoldierUnit.swift index a419d880..c1a49d53 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/SoldierUnit.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/SoldierUnit.swift @@ -7,8 +7,7 @@ import Foundation -class SoldierUnit: BaseUnit, Spawnable { - +class SoldierUnit: BaseUnit, PlayerSpawnable { static let title: String = "soldier" static let textureNames = ["Shooter-1", "Shooter-2"] static let size = CGSize(width: 100, height: 100) @@ -16,23 +15,22 @@ class SoldierUnit: BaseUnit, Spawnable { static let maxHealth = 100.0 static let damage = 10.0 static var cost = 5 - static let attackRate = 10.0 + static let attackRate = 1.0 static let velocity = CGVector(dx: 10.0, dy: 0.0) + static let range = 400.0 + static let attackPower = 10.0 - required init(position: CGPoint, entityManager: EntityManager, player: Player) { + required init(position: CGPoint, player: Player) { super.init(textureNames: SoldierUnit.textureNames, size: SoldierUnit.size, key: SoldierUnit.key, position: position, maxHealth: SoldierUnit.maxHealth, - entityManager: entityManager, velocity: SoldierUnit.velocity, player: player) self.addComponent(ShootingComponent(fireRate: SoldierUnit.attackRate, - range: 1.0, - entityManager: entityManager, - attackPower: 10.0 - )) + range: SoldierUnit.range, + attackPower: SoldierUnit.attackPower)) } } diff --git a/TowerForge/TowerForge/LevelManager/Entities/SpawnableEntities.swift b/TowerForge/TowerForge/LevelManager/Entities/SpawnableEntities.swift index 05e3f77b..064dbca9 100644 --- a/TowerForge/TowerForge/LevelManager/Entities/SpawnableEntities.swift +++ b/TowerForge/TowerForge/LevelManager/Entities/SpawnableEntities.swift @@ -8,6 +8,5 @@ import Foundation struct SpawnableEntities { - static let possibleUnits: [(BaseUnit & Spawnable).Type] = [MeleeUnit.self, - SoldierUnit.self] + static let playerSpawnableEntities: [(TFEntity & PlayerSpawnable).Type] = [MeleeUnit.self, SoldierUnit.self] } diff --git a/TowerForge/TowerForge/LevelManager/EntityManager.swift b/TowerForge/TowerForge/LevelManager/EntityManager.swift index a5ba14b9..7c6cff99 100644 --- a/TowerForge/TowerForge/LevelManager/EntityManager.swift +++ b/TowerForge/TowerForge/LevelManager/EntityManager.swift @@ -41,13 +41,4 @@ class EntityManager { func components(ofType type: T.Type) -> [T] { entities.compactMap { $0.component(ofType: type) } } - - // TODO update to be changed to systems - func update(_ deltaTime: TimeInterval) { - for entity in entities { - for component in entity.components.values { - component.update(deltaTime: deltaTime) - } - } - } } diff --git a/TowerForge/TowerForge/LevelManager/Events/EventManager.swift b/TowerForge/TowerForge/LevelManager/Events/EventManager.swift index e7cc799c..7410e532 100644 --- a/TowerForge/TowerForge/LevelManager/Events/EventManager.swift +++ b/TowerForge/TowerForge/LevelManager/Events/EventManager.swift @@ -21,7 +21,7 @@ class EventManager { func executeEvents(in target: EventTarget) { while !eventQueue.isEmpty { let currentEvent = eventQueue.removeFirst() - + print(currentEvent) if let output = currentEvent.execute(in: target) { output.events.forEach { eventQueue.append($0) } } diff --git a/TowerForge/TowerForge/LevelManager/Events/Implemented Events/DamageEvent.swift b/TowerForge/TowerForge/LevelManager/Events/Implemented Events/DamageEvent.swift index fdb4e0a6..35c31f9e 100644 --- a/TowerForge/TowerForge/LevelManager/Events/Implemented Events/DamageEvent.swift +++ b/TowerForge/TowerForge/LevelManager/Events/Implemented Events/DamageEvent.swift @@ -23,13 +23,12 @@ struct DamageEvent: TFEvent { guard let healthSystem = target.system(ofType: HealthSystem.self) else { return nil } - let healthIsZero = healthSystem.modifyHealth(for: entityId, with: damage) + let healthIsZero = healthSystem.modifyHealth(for: entityId, with: -damage) + var eventOutput = EventOutput() if healthIsZero { - var newEventOutput = EventOutput() - newEventOutput.add(RemoveEvent(on: entityId, at: timestamp)) - return newEventOutput + eventOutput.add(RemoveEvent(on: entityId, at: timestamp)) } - return EventOutput() + return eventOutput } } diff --git a/TowerForge/TowerForge/LevelManager/Events/Implemented Events/SpawnEvent.swift b/TowerForge/TowerForge/LevelManager/Events/Implemented Events/SpawnEvent.swift index e4ada9a6..772cf97b 100644 --- a/TowerForge/TowerForge/LevelManager/Events/Implemented Events/SpawnEvent.swift +++ b/TowerForge/TowerForge/LevelManager/Events/Implemented Events/SpawnEvent.swift @@ -3,23 +3,18 @@ import Foundation struct SpawnEvent: TFEvent { let timestamp: TimeInterval let entityId: UUID + let entity: TFEntity - private let position: CGPoint - private let velocity: CGVector - - init(timestamp: TimeInterval, entityId: UUID, position: CGPoint, velocity: CGVector) { + init(ofType type: T.Type, timestamp: TimeInterval, position: CGPoint, player: Player) { + self.entity = type.init(position: position, player: player) self.timestamp = timestamp - self.entityId = entityId - self.position = position - self.velocity = velocity + self.entityId = entity.id } func execute(in target: any EventTarget) -> EventOutput? { guard let spawnSystem = target.system(ofType: SpawnSystem.self) else { return nil } - var entity = TFEntity() - entity.addComponent(MovableComponent(position: position, velocity: velocity)) spawnSystem.handleSpawn(with: entity) return EventOutput() } diff --git a/TowerForge/TowerForge/LevelManager/Generators/UnitGenerator.swift b/TowerForge/TowerForge/LevelManager/Generators/UnitGenerator.swift index d2c80180..197c866a 100644 --- a/TowerForge/TowerForge/LevelManager/Generators/UnitGenerator.swift +++ b/TowerForge/TowerForge/LevelManager/Generators/UnitGenerator.swift @@ -9,9 +9,8 @@ import Foundation import SpriteKit class UnitGenerator { - static func spawn(ofType type: T.Type, at position: CGPoint, - player: Player, entityManager: EntityManager) -> T { - let unit = type.init(position: position, entityManager: entityManager, player: player) + static func spawn(ofType type: T.Type, at position: CGPoint, player: Player) -> T { + let unit = type.init(position: position, player: player) return unit } } diff --git a/TowerForge/TowerForge/LevelManager/SystemManager.swift b/TowerForge/TowerForge/LevelManager/SystemManager.swift index ab19cfde..6c413d84 100644 --- a/TowerForge/TowerForge/LevelManager/SystemManager.swift +++ b/TowerForge/TowerForge/LevelManager/SystemManager.swift @@ -8,11 +8,25 @@ import Foundation class SystemManager { + var systems: [String: TFSystem] = [:] func system(ofType type: T.Type) -> T? { - nil + systems[String(describing: T.self)] as? T } func update(_ deltaTime: TimeInterval) { + for system in systems.values where system.isActive { + system.update(within: deltaTime) + } + } + + func add(system: T) { + guard systems[String(describing: T.self)] == nil else { + return + } + systems[String(describing: T.self)] = system + } + func remove(ofType type: T.Type) { + systems.removeValue(forKey: String(describing: type.self)) } } diff --git a/TowerForge/TowerForge/LevelManager/Systems/AiSystem.swift b/TowerForge/TowerForge/LevelManager/Systems/AiSystem.swift new file mode 100644 index 00000000..ef76f05b --- /dev/null +++ b/TowerForge/TowerForge/LevelManager/Systems/AiSystem.swift @@ -0,0 +1,35 @@ +// +// AiSystem.swift +// TowerForge +// +// Created by Zheng Ze on 23/3/24. +// + +import Foundation + +class AiSystem: TFSystem { + var isActive = true + weak var entityManager: EntityManager? + weak var eventManager: EventManager? + + init(entityManager: EntityManager, eventManager: EventManager) { + self.entityManager = entityManager + self.eventManager = eventManager + } + + func update(within time: CGFloat) { + guard let entityManager = entityManager, let eventManager = eventManager else { + return + } + + let homeComponents = entityManager.components(ofType: HomeComponent.self) + for homeComponent in homeComponents { + homeComponent.update(deltaTime: time) + } + + let aiComponents = entityManager.components(ofType: AiComponent.self) + for aiComponent in aiComponents { + aiComponent.update(deltaTime: time) + } + } +} diff --git a/TowerForge/TowerForge/LevelManager/Systems/HealthSystem.swift b/TowerForge/TowerForge/LevelManager/Systems/HealthSystem.swift index ec9df187..73913223 100644 --- a/TowerForge/TowerForge/LevelManager/Systems/HealthSystem.swift +++ b/TowerForge/TowerForge/LevelManager/Systems/HealthSystem.swift @@ -1,7 +1,7 @@ import Foundation class HealthSystem: TFSystem { - var isActive = false + var isActive = true weak var entityManager: EntityManager? weak var eventManager: EventManager? diff --git a/TowerForge/TowerForge/LevelManager/Systems/MovementSystem.swift b/TowerForge/TowerForge/LevelManager/Systems/MovementSystem.swift index 3de4ab49..424eb340 100644 --- a/TowerForge/TowerForge/LevelManager/Systems/MovementSystem.swift +++ b/TowerForge/TowerForge/LevelManager/Systems/MovementSystem.swift @@ -1,7 +1,7 @@ import Foundation class MovementSystem: TFSystem { - var isActive = false + var isActive = true weak var entityManager: EntityManager? weak var eventManager: EventManager? diff --git a/TowerForge/TowerForge/LevelManager/Systems/RemoveSystem.swift b/TowerForge/TowerForge/LevelManager/Systems/RemoveSystem.swift index 8e299b08..c8aac08f 100644 --- a/TowerForge/TowerForge/LevelManager/Systems/RemoveSystem.swift +++ b/TowerForge/TowerForge/LevelManager/Systems/RemoveSystem.swift @@ -1,7 +1,7 @@ import Foundation class RemoveSystem: TFSystem { - var isActive = false + var isActive = true weak var entityManager: EntityManager? weak var eventManager: EventManager? @@ -15,5 +15,4 @@ class RemoveSystem: TFSystem { func handleRemove(for entityId: UUID) { entityManager?.removeEntity(with: entityId) } - } diff --git a/TowerForge/TowerForge/LevelManager/Systems/ShootingSystem.swift b/TowerForge/TowerForge/LevelManager/Systems/ShootingSystem.swift new file mode 100644 index 00000000..006ebddc --- /dev/null +++ b/TowerForge/TowerForge/LevelManager/Systems/ShootingSystem.swift @@ -0,0 +1,40 @@ +// +// ShootingSystem.swift +// TowerForge +// +// Created by Zheng Ze on 23/3/24. +// + +import Foundation + +class ShootingSystem: TFSystem { + var isActive = true + weak var entityManager: EntityManager? + weak var eventManager: EventManager? + + init(entityManager: EntityManager, eventManager: EventManager) { + self.entityManager = entityManager + self.eventManager = eventManager + } + + func update(within time: CGFloat) { + guard let entityManager = entityManager, let eventManager = eventManager else { + return + } + let shootingComponents = entityManager.components(ofType: ShootingComponent.self).filter({ $0.canShoot }) + let targetableHealthComponents = entityManager.components(ofType: HealthComponent.self).filter({ + $0.entity?.hasComponent(ofType: PositionComponent.self) ?? false + }) + + for shootingComponent in shootingComponents { + for healthComponent in targetableHealthComponents { + guard let event = shootingComponent.shoot(healthComponent) else { + continue + } + + eventManager.add(event) + break + } + } + } +} diff --git a/TowerForge/TowerForge/LevelManager/Systems/SpawnSystem.swift b/TowerForge/TowerForge/LevelManager/Systems/SpawnSystem.swift index 6f2a4810..aade6440 100644 --- a/TowerForge/TowerForge/LevelManager/Systems/SpawnSystem.swift +++ b/TowerForge/TowerForge/LevelManager/Systems/SpawnSystem.swift @@ -1,7 +1,7 @@ import Foundation class SpawnSystem: TFSystem { - var isActive = false + var isActive = true weak var entityManager: EntityManager? weak var eventManager: EventManager? @@ -15,5 +15,4 @@ class SpawnSystem: TFSystem { func handleSpawn(with entity: TFEntity) { entityManager?.add(entity) } - } diff --git a/TowerForge/TowerForge/LevelManager/TFEntity.swift b/TowerForge/TowerForge/LevelManager/TFEntity.swift index 4e7bc4f7..6ca64142 100644 --- a/TowerForge/TowerForge/LevelManager/TFEntity.swift +++ b/TowerForge/TowerForge/LevelManager/TFEntity.swift @@ -39,7 +39,7 @@ class TFEntity: Collidable { } func removeComponent(ofType type: T.Type) { - guard let componentToBeRemoved = component(ofType: T.self) else { + guard let componentToBeRemoved = component(ofType: type.self) else { return } componentToBeRemoved.willRemoveFromEntity() diff --git a/TowerForge/TowerForge/Nodes/UnitNode.swift b/TowerForge/TowerForge/Nodes/UnitNode.swift index 92b3cdcd..83375004 100644 --- a/TowerForge/TowerForge/Nodes/UnitNode.swift +++ b/TowerForge/TowerForge/Nodes/UnitNode.swift @@ -13,7 +13,7 @@ protocol UnitNodeDelegate: AnyObject { } class UnitNode: TFSpriteNode { - let type: (BaseUnit & Spawnable).Type + let type: (TFEntity & PlayerSpawnable).Type weak var delegate: UnitNodeDelegate? var purchasable = true var teamController: TeamController? @@ -21,7 +21,7 @@ class UnitNode: TFSpriteNode { var unitCostLabel: SKLabelNode! var backgroundNode: SKSpriteNode! - init(ofType type: T.Type) { + init(ofType type: T.Type) { self.type = type super.init(imageName: type.title, height: 200.0, width: 140.0) diff --git a/TowerForge/TowerForge/Nodes/UnitSelectionNode.swift b/TowerForge/TowerForge/Nodes/UnitSelectionNode.swift index 04e85e31..47a1d486 100644 --- a/TowerForge/TowerForge/Nodes/UnitSelectionNode.swift +++ b/TowerForge/TowerForge/Nodes/UnitSelectionNode.swift @@ -9,7 +9,7 @@ import Foundation import UIKit protocol UnitSelectionNodeDelegate: AnyObject { - func unitSelectionNodeDidSpawn(ofType type: T.Type, position: CGPoint) + func unitSelectionNodeDidSpawn(ofType type: T.Type, position: CGPoint) } class UnitSelectionNode: TFSpriteNode, UnitNodeDelegate { @@ -26,7 +26,7 @@ class UnitSelectionNode: TFSpriteNode, UnitNodeDelegate { super.init(textures: nil, height: 200.0, width: 100.0) isUserInteractionEnabled = true - let possibleUnits: [(BaseUnit & Spawnable).Type] = SpawnableEntities.possibleUnits + let possibleUnits: [(TFEntity & PlayerSpawnable).Type] = SpawnableEntities.playerSpawnableEntities for type in possibleUnits { let unitNode = UnitNode(ofType: type) unitNodes.append(unitNode) diff --git a/TowerForge/TowerForge/Protocols/PlayerSpawnable.swift b/TowerForge/TowerForge/Protocols/PlayerSpawnable.swift new file mode 100644 index 00000000..3ba891a6 --- /dev/null +++ b/TowerForge/TowerForge/Protocols/PlayerSpawnable.swift @@ -0,0 +1,13 @@ +// +// Spawnable.swift +// TowerForge +// +// Created by Vanessa Mae on 19/03/24. +// + +import Foundation + +protocol PlayerSpawnable: Spawnable { + static var cost: Int { get set } + static var title: String { get } +} diff --git a/TowerForge/TowerForge/Protocols/Spawnable.swift b/TowerForge/TowerForge/Protocols/Spawnable.swift index a54c3f97..4ac1df5f 100644 --- a/TowerForge/TowerForge/Protocols/Spawnable.swift +++ b/TowerForge/TowerForge/Protocols/Spawnable.swift @@ -2,13 +2,11 @@ // Spawnable.swift // TowerForge // -// Created by Vanessa Mae on 19/03/24. +// Created by Zheng Ze on 23/3/24. // import Foundation protocol Spawnable { - init(position: CGPoint, entityManager: EntityManager, player: Player) - static var cost: Int { get set } - static var title: String { get } + init(position: CGPoint, player: Player) }