diff --git a/GoldWars/GoldWars.xcodeproj/project.pbxproj b/GoldWars/GoldWars.xcodeproj/project.pbxproj index c92245c..4982277 100644 --- a/GoldWars/GoldWars.xcodeproj/project.pbxproj +++ b/GoldWars/GoldWars.xcodeproj/project.pbxproj @@ -16,17 +16,16 @@ 110360EE244B101B008610AF /* GoldWarsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110360ED244B101B008610AF /* GoldWarsTests.swift */; }; 11036113244B3E30008610AF /* MenuScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11036112244B3E30008610AF /* MenuScene.swift */; }; 116060F7245C57D2004E5A36 /* EntityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116060F6245C57D2004E5A36 /* EntityManager.swift */; }; - 11738A3B24508F68004426F1 /* UnitType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11738A3A24508F68004426F1 /* UnitType.swift */; }; - 2086465C2461B66200817C23 /* TimerComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2086465B2461B66200817C23 /* TimerComponent.swift */; }; 3E67854024728368007B9DE4 /* CElements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E67853F24728368007B9DE4 /* CElements.swift */; }; 3E6785422472CBEC007B9DE4 /* Way.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E6785412472CBEC007B9DE4 /* Way.swift */; }; 3E6785442472CC27007B9DE4 /* DefaultWayComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E6785432472CC27007B9DE4 /* DefaultWayComponent.swift */; }; - 3EBD242C245D8044003CECE7 /* GameCenterHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EBD242B245D8044003CECE7 /* GameCenterHelper.swift */; }; + 3EAD889524801B6A0048A10A /* RoundTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EAD889424801B6A0048A10A /* RoundTimer.swift */; }; 3EBD242E245D9332003CECE7 /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EBD242D245D9332003CECE7 /* Team.swift */; }; 3F745DF0246F48FC00CE7375 /* PlayerMoveType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F745DEF246F48FC00CE7375 /* PlayerMoveType.swift */; }; + 3F79FFE02486F7CD003F79C3 /* Explosion.sks in Resources */ = {isa = PBXBuildFile; fileRef = 3F79FFDF2486F7CD003F79C3 /* Explosion.sks */; }; 3FE19DB5246C7A22004827AB /* RoundCalculatorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FE19DB4246C7A22004827AB /* RoundCalculatorService.swift */; }; - 8BB6FF402472B8F000162BBD /* SkillButtonNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB6FF3F2472B8F000162BBD /* SkillButtonNode.swift */; }; - 9E04AFAF245E2B73002D5CFC /* AttackActionComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04AFAE245E2B73002D5CFC /* AttackActionComponent.swift */; }; + 8BB6FF402472B8F000162BBD /* SingeClickButtonNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BB6FF3F2472B8F000162BBD /* SingeClickButtonNode.swift */; }; + 9E0E459724796262009817A6 /* GameCenterManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E0E459624796262009817A6 /* GameCenterManager.swift */; }; 9E11FF79245CD81100EED3BE /* Fire.sks in Resources */ = {isa = PBXBuildFile; fileRef = 9E11FF77245CD81100EED3BE /* Fire.sks */; }; 9E174C82245DD81D00209FF0 /* ButtonNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E174C81245DD81D00209FF0 /* ButtonNode.swift */; }; 9E174C84245DD8CE00209FF0 /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E174C83245DD8CE00209FF0 /* Button.swift */; }; @@ -36,30 +35,20 @@ 9E78ACB6245C9A5300526FF7 /* GameKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E78ACB5245C9A5300526FF7 /* GameKit.framework */; }; 9E78ACB8245CB75B00526FF7 /* TeamComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E78ACB7245CB75B00526FF7 /* TeamComponent.swift */; }; 9E78ACBA245CBDAF00526FF7 /* HUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E78ACB9245CBDAF00526FF7 /* HUD.swift */; }; - 9E78ACBE245CC9C000526FF7 /* AtkBoostSkillComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E78ACBD245CC9C000526FF7 /* AtkBoostSkillComponent.swift */; }; - 9E78ACC2245CC9EE00526FF7 /* DefBoostSkillComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E78ACC1245CC9EE00526FF7 /* DefBoostSkillComponent.swift */; }; - 9E78ACC4245CCA3600526FF7 /* SpySkillComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E78ACC3245CCA3600526FF7 /* SpySkillComponent.swift */; }; 9EA3ABE9245C6DAA006BC61D /* DefaultBaseComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA3ABE8245C6DAA006BC61D /* DefaultBaseComponent.swift */; }; 9EA3ABEB245C6DFA006BC61D /* BaseNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA3ABEA245C6DFA006BC61D /* BaseNode.swift */; }; - 9EA3ABED245C8143006BC61D /* ModalBackgroundComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA3ABEC245C8143006BC61D /* ModalBackgroundComponent.swift */; }; - 9EA3ABEF245C834B006BC61D /* ModalContentComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA3ABEE245C834B006BC61D /* ModalContentComponent.swift */; }; - 9EBFD7552462CF5A00E1E219 /* SliderComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBFD7542462CF5A00E1E219 /* SliderComponent.swift */; }; 9EC239E1246878A900952F74 /* MultiplayerNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC239E0246878A900952F74 /* MultiplayerNetwork.swift */; }; 9EC2FBA72476B1EC00ABF11F /* PlayerInfoComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC2FBA62476B1EC00ABF11F /* PlayerInfoComponent.swift */; }; 9EC7E48B2461FBF700396BCD /* SliderNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC7E48A2461FBF700396BCD /* SliderNode.swift */; }; 9EC86B9F245C88A300796EF3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC86B9E245C88A300796EF3 /* Modal.swift */; }; - 9EC86BA6245C8AD000796EF3 /* ModalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC86BA5245C8AD000796EF3 /* ModalType.swift */; }; 9EEDE02D246FCD770096C735 /* SpinningLogoEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EEDE02C246FCD770096C735 /* SpinningLogoEntity.swift */; }; 9EEDE02F246FCD800096C735 /* SpinningLogoComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EEDE02E246FCD800096C735 /* SpinningLogoComponent.swift */; }; - AB1D759D245DD18100671525 /* TwoPlayerDefaultTestMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB1D759B245DD18100671525 /* TwoPlayerDefaultTestMap.swift */; }; - AB1D75A0245DEC0500671525 /* MapFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB1D759F245DEC0500671525 /* MapFactory.swift */; }; - AB21D7D5246C748A00B09CBA /* TwoPlayerMapGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB21D7D4246C748A00B09CBA /* TwoPlayerMapGenerator.swift */; }; + AB21D7D5246C748A00B09CBA /* MapFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB21D7D4246C748A00B09CBA /* MapFactory.swift */; }; ABA03DA0244BD54F00A66916 /* Base.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABA03D9F244BD54F00A66916 /* Base.swift */; }; - AE151589245F18EF001D363E /* MatchmakingHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE151588245F18EF001D363E /* MatchmakingHelper.swift */; }; - AEBF3AFF246EB146004F7CD5 /* CancelBtnNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEBF3AFE246EB146004F7CD5 /* CancelBtnNode.swift */; }; - AEBF3B01246EB187004F7CD5 /* CancelBtnComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEBF3B00246EB187004F7CD5 /* CancelBtnComponent.swift */; }; + ABC0C3732481509300387B8F /* MapUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC0C3722481509300387B8F /* MapUtils.swift */; }; C04783EE2468583F004961FB /* intro-music.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C04783ED2468583F004961FB /* intro-music.mp3 */; }; C04783F024685995004961FB /* SettingsScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04783EF24685995004961FB /* SettingsScene.swift */; }; + C05BB9C4247D890C00411249 /* SliderComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05BB9C3247D890C00411249 /* SliderComponent.swift */; }; C05FAED62468559D0006AF2E /* SoundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C05FAED52468559D0006AF2E /* SoundManager.swift */; }; C064E9A8246C0EA50022B228 /* LabelNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C064E9A7246C0EA50022B228 /* LabelNode.swift */; }; C064E9AA246C114C0022B228 /* LabelComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C064E9A9246C114C0022B228 /* LabelComponent.swift */; }; @@ -91,17 +80,16 @@ 110360EF244B101B008610AF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 11036112244B3E30008610AF /* MenuScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuScene.swift; sourceTree = ""; }; 116060F6245C57D2004E5A36 /* EntityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityManager.swift; sourceTree = ""; }; - 11738A3A24508F68004426F1 /* UnitType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnitType.swift; sourceTree = ""; }; - 2086465B2461B66200817C23 /* TimerComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerComponent.swift; sourceTree = ""; }; 3E67853F24728368007B9DE4 /* CElements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CElements.swift; sourceTree = ""; }; 3E6785412472CBEC007B9DE4 /* Way.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Way.swift; sourceTree = ""; }; 3E6785432472CC27007B9DE4 /* DefaultWayComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultWayComponent.swift; sourceTree = ""; }; - 3EBD242B245D8044003CECE7 /* GameCenterHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameCenterHelper.swift; sourceTree = ""; }; + 3EAD889424801B6A0048A10A /* RoundTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundTimer.swift; sourceTree = ""; }; 3EBD242D245D9332003CECE7 /* Team.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Team.swift; sourceTree = ""; }; 3F745DEF246F48FC00CE7375 /* PlayerMoveType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerMoveType.swift; sourceTree = ""; }; + 3F79FFDF2486F7CD003F79C3 /* Explosion.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Explosion.sks; sourceTree = ""; }; 3FE19DB4246C7A22004827AB /* RoundCalculatorService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundCalculatorService.swift; sourceTree = ""; }; - 8BB6FF3F2472B8F000162BBD /* SkillButtonNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkillButtonNode.swift; sourceTree = ""; }; - 9E04AFAE245E2B73002D5CFC /* AttackActionComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttackActionComponent.swift; sourceTree = ""; }; + 8BB6FF3F2472B8F000162BBD /* SingeClickButtonNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingeClickButtonNode.swift; sourceTree = ""; }; + 9E0E459624796262009817A6 /* GameCenterManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameCenterManager.swift; sourceTree = ""; }; 9E11FF77245CD81100EED3BE /* Fire.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Fire.sks; sourceTree = ""; }; 9E174C81245DD81D00209FF0 /* ButtonNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonNode.swift; sourceTree = ""; }; 9E174C83245DD8CE00209FF0 /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; @@ -111,31 +99,21 @@ 9E78ACB5245C9A5300526FF7 /* GameKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System/Library/Frameworks/GameKit.framework; sourceTree = SDKROOT; }; 9E78ACB7245CB75B00526FF7 /* TeamComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeamComponent.swift; sourceTree = ""; }; 9E78ACB9245CBDAF00526FF7 /* HUD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUD.swift; sourceTree = ""; }; - 9E78ACBD245CC9C000526FF7 /* AtkBoostSkillComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtkBoostSkillComponent.swift; sourceTree = ""; }; - 9E78ACC1245CC9EE00526FF7 /* DefBoostSkillComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefBoostSkillComponent.swift; sourceTree = ""; }; - 9E78ACC3245CCA3600526FF7 /* SpySkillComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpySkillComponent.swift; sourceTree = ""; }; 9EA3ABE8245C6DAA006BC61D /* DefaultBaseComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultBaseComponent.swift; sourceTree = ""; wrapsLines = 1; }; 9EA3ABEA245C6DFA006BC61D /* BaseNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNode.swift; sourceTree = ""; }; - 9EA3ABEC245C8143006BC61D /* ModalBackgroundComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalBackgroundComponent.swift; sourceTree = ""; }; - 9EA3ABEE245C834B006BC61D /* ModalContentComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalContentComponent.swift; sourceTree = ""; }; - 9EBFD7542462CF5A00E1E219 /* SliderComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderComponent.swift; sourceTree = ""; }; 9EC239E0246878A900952F74 /* MultiplayerNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultiplayerNetwork.swift; sourceTree = ""; }; 9EC2FBA62476B1EC00ABF11F /* PlayerInfoComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerInfoComponent.swift; sourceTree = ""; }; 9EC7E48A2461FBF700396BCD /* SliderNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderNode.swift; sourceTree = ""; }; 9EC86B9E245C88A300796EF3 /* Modal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modal.swift; sourceTree = ""; }; - 9EC86BA5245C8AD000796EF3 /* ModalType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalType.swift; sourceTree = ""; }; 9ECD3699245C91F7008DEEBD /* GoldWars.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GoldWars.entitlements; sourceTree = ""; }; 9EEDE02C246FCD770096C735 /* SpinningLogoEntity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinningLogoEntity.swift; sourceTree = ""; }; 9EEDE02E246FCD800096C735 /* SpinningLogoComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpinningLogoComponent.swift; sourceTree = ""; }; - AB1D759B245DD18100671525 /* TwoPlayerDefaultTestMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwoPlayerDefaultTestMap.swift; sourceTree = ""; }; - AB1D759F245DEC0500671525 /* MapFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapFactory.swift; sourceTree = ""; }; - AB21D7D4246C748A00B09CBA /* TwoPlayerMapGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoPlayerMapGenerator.swift; sourceTree = ""; }; + AB21D7D4246C748A00B09CBA /* MapFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapFactory.swift; sourceTree = ""; }; ABA03D9F244BD54F00A66916 /* Base.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Base.swift; sourceTree = ""; }; - AE151588245F18EF001D363E /* MatchmakingHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MatchmakingHelper.swift; sourceTree = ""; }; - AEBF3AFE246EB146004F7CD5 /* CancelBtnNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelBtnNode.swift; sourceTree = ""; }; - AEBF3B00246EB187004F7CD5 /* CancelBtnComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CancelBtnComponent.swift; sourceTree = ""; }; + ABC0C3722481509300387B8F /* MapUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapUtils.swift; sourceTree = ""; }; C04783ED2468583F004961FB /* intro-music.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = "intro-music.mp3"; sourceTree = ""; }; C04783EF24685995004961FB /* SettingsScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScene.swift; sourceTree = ""; }; + C05BB9C3247D890C00411249 /* SliderComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderComponent.swift; sourceTree = ""; }; C05FAED52468559D0006AF2E /* SoundManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoundManager.swift; sourceTree = ""; }; C064E9A7246C0EA50022B228 /* LabelNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelNode.swift; sourceTree = ""; }; C064E9A9246C114C0022B228 /* LabelComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelComponent.swift; sourceTree = ""; }; @@ -200,15 +178,10 @@ 9EC239E0246878A900952F74 /* MultiplayerNetwork.swift */, C099579B246C5E5C0016AA22 /* DataService.swift */, 110360E4244B101B008610AF /* Info.plist */, - AE151588245F18EF001D363E /* MatchmakingHelper.swift */, 3FE19DB4246C7A22004827AB /* RoundCalculatorService.swift */, - 3EBD242B245D8044003CECE7 /* GameCenterHelper.swift */, - AEBF3B00246EB187004F7CD5 /* CancelBtnComponent.swift */, - AEBF3AFE246EB146004F7CD5 /* CancelBtnNode.swift */, + 9E0E459624796262009817A6 /* GameCenterManager.swift */, C04783EF24685995004961FB /* SettingsScene.swift */, - C064E9A7246C0EA50022B228 /* LabelNode.swift */, - C064E9A9246C114C0022B228 /* LabelComponent.swift */, - C064E9AB246C151F0022B228 /* Label.swift */, + 3EAD889424801B6A0048A10A /* RoundTimer.swift */, ); path = GoldWars; sourceTree = ""; @@ -225,25 +198,20 @@ 116060F4245C56EA004E5A36 /* Components */ = { isa = PBXGroup; children = ( - 9EEDE02E246FCD800096C735 /* SpinningLogoComponent.swift */, + 9E174C87245DF1FF00209FF0 /* BackgroundComponent.swift */, + 9EA3ABEA245C6DFA006BC61D /* BaseNode.swift */, + 9E174C85245DD91500209FF0 /* ButtonComponent.swift */, 9E174C81245DD81D00209FF0 /* ButtonNode.swift */, 9EA3ABE8245C6DAA006BC61D /* DefaultBaseComponent.swift */, - 9EA3ABEC245C8143006BC61D /* ModalBackgroundComponent.swift */, - 9EA3ABEE245C834B006BC61D /* ModalContentComponent.swift */, - 9EA3ABEA245C6DFA006BC61D /* BaseNode.swift */, - 9E78ACB7245CB75B00526FF7 /* TeamComponent.swift */, - 9E78ACBD245CC9C000526FF7 /* AtkBoostSkillComponent.swift */, - 9E78ACC3245CCA3600526FF7 /* SpySkillComponent.swift */, - 9E78ACC1245CC9EE00526FF7 /* DefBoostSkillComponent.swift */, - 9E174C85245DD91500209FF0 /* ButtonComponent.swift */, - 9E174C87245DF1FF00209FF0 /* BackgroundComponent.swift */, - 9E04AFAE245E2B73002D5CFC /* AttackActionComponent.swift */, - 2086465B2461B66200817C23 /* TimerComponent.swift */, - 9EBFD7542462CF5A00E1E219 /* SliderComponent.swift */, - 9EC7E48A2461FBF700396BCD /* SliderNode.swift */, 3E6785432472CC27007B9DE4 /* DefaultWayComponent.swift */, - 8BB6FF3F2472B8F000162BBD /* SkillButtonNode.swift */, + C064E9A9246C114C0022B228 /* LabelComponent.swift */, + C064E9A7246C0EA50022B228 /* LabelNode.swift */, 9EC2FBA62476B1EC00ABF11F /* PlayerInfoComponent.swift */, + 8BB6FF3F2472B8F000162BBD /* SingeClickButtonNode.swift */, + C05BB9C3247D890C00411249 /* SliderComponent.swift */, + 9EC7E48A2461FBF700396BCD /* SliderNode.swift */, + 9EEDE02E246FCD800096C735 /* SpinningLogoComponent.swift */, + 9E78ACB7245CB75B00526FF7 /* TeamComponent.swift */, ); path = Components; sourceTree = ""; @@ -259,6 +227,7 @@ 9EC86B9E245C88A300796EF3 /* Modal.swift */, 9EEDE02C246FCD770096C735 /* SpinningLogoEntity.swift */, 3E6785412472CBEC007B9DE4 /* Way.swift */, + C064E9AB246C151F0022B228 /* Label.swift */, ); path = Entities; sourceTree = ""; @@ -266,6 +235,7 @@ 9E11FF74245CD79100EED3BE /* Partikels */ = { isa = PBXGroup; children = ( + 3F79FFDF2486F7CD003F79C3 /* Explosion.sks */, 9E11FF77245CD81100EED3BE /* Fire.sks */, ); path = Partikels; @@ -282,8 +252,6 @@ 9EC86BA2245C89B200796EF3 /* Enums */ = { isa = PBXGroup; children = ( - 11738A3A24508F68004426F1 /* UnitType.swift */, - 9EC86BA5245C8AD000796EF3 /* ModalType.swift */, 3EBD242D245D9332003CECE7 /* Team.swift */, 3F745DEF246F48FC00CE7375 /* PlayerMoveType.swift */, ); @@ -312,9 +280,8 @@ isa = PBXGroup; children = ( 3E67853F24728368007B9DE4 /* CElements.swift */, - AB1D759F245DEC0500671525 /* MapFactory.swift */, - AB1D759B245DD18100671525 /* TwoPlayerDefaultTestMap.swift */, - AB21D7D4246C748A00B09CBA /* TwoPlayerMapGenerator.swift */, + AB21D7D4246C748A00B09CBA /* MapFactory.swift */, + ABC0C3722481509300387B8F /* MapUtils.swift */, ); path = Map; sourceTree = ""; @@ -405,6 +372,7 @@ 110360E0244B101B008610AF /* Assets.xcassets in Resources */, 110360E3244B101B008610AF /* LaunchScreen.storyboard in Resources */, C04783EE2468583F004961FB /* intro-music.mp3 in Resources */, + 3F79FFE02486F7CD003F79C3 /* Explosion.sks in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -423,14 +391,10 @@ buildActionMask = 2147483647; files = ( 9E78ACB8245CB75B00526FF7 /* TeamComponent.swift in Sources */, - 9EA3ABEF245C834B006BC61D /* ModalContentComponent.swift in Sources */, + 9E0E459724796262009817A6 /* GameCenterManager.swift in Sources */, 3FE19DB5246C7A22004827AB /* RoundCalculatorService.swift in Sources */, - 9EC86BA6245C8AD000796EF3 /* ModalType.swift in Sources */, 9EC239E1246878A900952F74 /* MultiplayerNetwork.swift in Sources */, - 9E78ACBE245CC9C000526FF7 /* AtkBoostSkillComponent.swift in Sources */, - 9E78ACC4245CCA3600526FF7 /* SpySkillComponent.swift in Sources */, 9EA3ABEB245C6DFA006BC61D /* BaseNode.swift in Sources */, - 9E04AFAF245E2B73002D5CFC /* AttackActionComponent.swift in Sources */, 3E6785422472CBEC007B9DE4 /* Way.swift in Sources */, 110360D9244B101A008610AF /* GameScene.swift in Sources */, C04783F024685995004961FB /* SettingsScene.swift in Sources */, @@ -441,37 +405,29 @@ 9E78ACBA245CBDAF00526FF7 /* HUD.swift in Sources */, 9EC2FBA72476B1EC00ABF11F /* PlayerInfoComponent.swift in Sources */, 9EEDE02D246FCD770096C735 /* SpinningLogoEntity.swift in Sources */, - 11738A3B24508F68004426F1 /* UnitType.swift in Sources */, 9E174C86245DD91500209FF0 /* ButtonComponent.swift in Sources */, - AE151589245F18EF001D363E /* MatchmakingHelper.swift in Sources */, 11036113244B3E30008610AF /* MenuScene.swift in Sources */, C099579C246C5E5C0016AA22 /* DataService.swift in Sources */, - AB21D7D5246C748A00B09CBA /* TwoPlayerMapGenerator.swift in Sources */, + AB21D7D5246C748A00B09CBA /* MapFactory.swift in Sources */, 9EA3ABE9245C6DAA006BC61D /* DefaultBaseComponent.swift in Sources */, 9E174C8A245E1A0A00209FF0 /* Background.swift in Sources */, - 8BB6FF402472B8F000162BBD /* SkillButtonNode.swift in Sources */, - 9EA3ABED245C8143006BC61D /* ModalBackgroundComponent.swift in Sources */, + 8BB6FF402472B8F000162BBD /* SingeClickButtonNode.swift in Sources */, C064E9A8246C0EA50022B228 /* LabelNode.swift in Sources */, - 3EBD242C245D8044003CECE7 /* GameCenterHelper.swift in Sources */, 3F745DF0246F48FC00CE7375 /* PlayerMoveType.swift in Sources */, - AEBF3B01246EB187004F7CD5 /* CancelBtnComponent.swift in Sources */, - AB1D75A0245DEC0500671525 /* MapFactory.swift in Sources */, - AB1D759D245DD18100671525 /* TwoPlayerDefaultTestMap.swift in Sources */, - 9EBFD7552462CF5A00E1E219 /* SliderComponent.swift in Sources */, + 3EAD889524801B6A0048A10A /* RoundTimer.swift in Sources */, 3E67854024728368007B9DE4 /* CElements.swift in Sources */, ABA03DA0244BD54F00A66916 /* Base.swift in Sources */, C064E9AC246C151F0022B228 /* Label.swift in Sources */, + ABC0C3732481509300387B8F /* MapUtils.swift in Sources */, 9E174C82245DD81D00209FF0 /* ButtonNode.swift in Sources */, 9EC7E48B2461FBF700396BCD /* SliderNode.swift in Sources */, 9EEDE02F246FCD800096C735 /* SpinningLogoComponent.swift in Sources */, 9E174C84245DD8CE00209FF0 /* Button.swift in Sources */, - AEBF3AFF246EB146004F7CD5 /* CancelBtnNode.swift in Sources */, 110360DB244B101A008610AF /* GameViewController.swift in Sources */, 3E6785442472CC27007B9DE4 /* DefaultWayComponent.swift in Sources */, - 2086465C2461B66200817C23 /* TimerComponent.swift in Sources */, + C05BB9C4247D890C00411249 /* SliderComponent.swift in Sources */, 110360D3244B101A008610AF /* AppDelegate.swift in Sources */, 9EC86B9F245C88A300796EF3 /* Modal.swift in Sources */, - 9E78ACC2245CC9EE00526FF7 /* DefBoostSkillComponent.swift in Sources */, C05FAED62468559D0006AF2E /* SoundManager.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base-1.png b/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base-1.png deleted file mode 100644 index b9ffa3f..0000000 Binary files a/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base-1.png and /dev/null differ diff --git a/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base-2.png b/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base-2.png deleted file mode 100644 index b9ffa3f..0000000 Binary files a/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base-2.png and /dev/null differ diff --git a/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base.png b/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base.png deleted file mode 100644 index b9ffa3f..0000000 Binary files a/GoldWars/GoldWars/Assets.xcassets/Base.imageset/base.png and /dev/null differ diff --git a/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base-1.png b/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base-1.png new file mode 100644 index 0000000..efa12ed Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base-1.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base-2.png b/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base-2.png new file mode 100644 index 0000000..efa12ed Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base-2.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base.png b/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base.png new file mode 100644 index 0000000..efa12ed Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Base.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/Base.imageset/Contents.json b/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Contents.json similarity index 73% rename from GoldWars/GoldWars/Assets.xcassets/Base.imageset/Contents.json rename to GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Contents.json index 721f4c4..a4fdd66 100644 --- a/GoldWars/GoldWars/Assets.xcassets/Base.imageset/Contents.json +++ b/GoldWars/GoldWars/Assets.xcassets/BaseTexture.imageset/Contents.json @@ -1,17 +1,17 @@ { "images" : [ { - "filename" : "base.png", + "filename" : "Base.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "base-1.png", + "filename" : "Base-1.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "base-2.png", + "filename" : "Base-2.png", "idiom" : "universal", "scale" : "3x" } diff --git a/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2-1.png b/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2-1.png new file mode 100644 index 0000000..0dc17d6 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2-1.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2-2.png b/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2-2.png new file mode 100644 index 0000000..0dc17d6 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2-2.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2.png b/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2.png new file mode 100644 index 0000000..0dc17d6 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Base_2.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Contents.json b/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Contents.json new file mode 100644 index 0000000..f49b770 --- /dev/null +++ b/GoldWars/GoldWars/Assets.xcassets/BaseTexture_2.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Base_2.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Base_2-1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Base_2-2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/Contents.json b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/Contents.json index a9bd99c..44dc98f 100644 --- a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/Contents.json +++ b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/Contents.json @@ -1,17 +1,17 @@ { "images" : [ { - "filename" : "PopUpBackground.png", + "filename" : "ModalBackground.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "PopUpBackground-1.png", + "filename" : "ModalBackground-1.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "PopUpBackground-2.png", + "filename" : "ModalBackground-2.png", "idiom" : "universal", "scale" : "3x" } diff --git a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground-1.png b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground-1.png new file mode 100644 index 0000000..f3e5344 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground-1.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground-2.png b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground-2.png new file mode 100644 index 0000000..f3e5344 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground-2.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground.png b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground.png new file mode 100644 index 0000000..f3e5344 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/ModalBackground.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground-1.png b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground-1.png deleted file mode 100644 index 5236731..0000000 Binary files a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground-1.png and /dev/null differ diff --git a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground-2.png b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground-2.png deleted file mode 100644 index 5236731..0000000 Binary files a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground-2.png and /dev/null differ diff --git a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground.png b/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground.png deleted file mode 100644 index 5236731..0000000 Binary files a/GoldWars/GoldWars/Assets.xcassets/ModalBackground.imageset/PopUpBackground.png and /dev/null differ diff --git a/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/Contents.json b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/Contents.json index 231694f..5bbf0b1 100644 --- a/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/Contents.json +++ b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/Contents.json @@ -1,15 +1,17 @@ { "images" : [ { - "filename" : "SkyBackground.jpg", + "filename" : "SkyBackground.png", "idiom" : "universal", "scale" : "1x" }, { + "filename" : "SkyBackground-1.png", "idiom" : "universal", "scale" : "2x" }, { + "filename" : "SkyBackground-2.png", "idiom" : "universal", "scale" : "3x" } diff --git a/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground-1.png b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground-1.png new file mode 100644 index 0000000..a764543 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground-1.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground-2.png b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground-2.png new file mode 100644 index 0000000..a764543 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground-2.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground.jpg b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground.jpg deleted file mode 100644 index 8b499d5..0000000 Binary files a/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground.jpg and /dev/null differ diff --git a/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground.png b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground.png new file mode 100644 index 0000000..a764543 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/SkyBackground.imageset/SkyBackground.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/UITexture.spriteatlas/red_cross.imageset/Contents.json b/GoldWars/GoldWars/Assets.xcassets/UITexture.spriteatlas/red_cross.imageset/Contents.json new file mode 100644 index 0000000..d3320ef --- /dev/null +++ b/GoldWars/GoldWars/Assets.xcassets/UITexture.spriteatlas/red_cross.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "red_cross.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/GoldWars/GoldWars/Assets.xcassets/UITexture.spriteatlas/red_cross.imageset/red_cross.png b/GoldWars/GoldWars/Assets.xcassets/UITexture.spriteatlas/red_cross.imageset/red_cross.png new file mode 100644 index 0000000..fadb286 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/UITexture.spriteatlas/red_cross.imageset/red_cross.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/Contents.json b/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/Contents.json new file mode 100644 index 0000000..2044f76 --- /dev/null +++ b/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "roundInfo_texture.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "roundInfo_texture-1.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "roundInfo_texture-2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture-1.png b/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture-1.png new file mode 100644 index 0000000..2668882 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture-1.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture-2.png b/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture-2.png new file mode 100644 index 0000000..2668882 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture-2.png differ diff --git a/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture.png b/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture.png new file mode 100644 index 0000000..2668882 Binary files /dev/null and b/GoldWars/GoldWars/Assets.xcassets/roundInfo_texture.imageset/roundInfo_texture.png differ diff --git a/GoldWars/GoldWars/Components/ButtonComponent.swift b/GoldWars/GoldWars/Components/ButtonComponent.swift index 2c2d82a..0597f40 100644 --- a/GoldWars/GoldWars/Components/ButtonComponent.swift +++ b/GoldWars/GoldWars/Components/ButtonComponent.swift @@ -12,8 +12,8 @@ class ButtonComponent: GKComponent { var buttonNode: ButtonNode - init(iconName: String, text: String, position: CGPoint, isEnabled:Bool, onButtonPress: @escaping () -> ()) { - buttonNode = ButtonNode(iconName: iconName, + init(textureName: String, text: String, position: CGPoint, isEnabled:Bool, onButtonPress: @escaping () -> ()) { + buttonNode = ButtonNode(textureName: textureName, text: text, isEnabled: isEnabled, position: position, diff --git a/GoldWars/GoldWars/Components/ButtonNode.swift b/GoldWars/GoldWars/Components/ButtonNode.swift index 2ebd012..b98164a 100644 --- a/GoldWars/GoldWars/Components/ButtonNode.swift +++ b/GoldWars/GoldWars/Components/ButtonNode.swift @@ -22,12 +22,12 @@ class ButtonNode: SKSpriteNode { } } - let onButtonPress: () -> () + var onButtonPress: () -> () - init(iconName: String, text: String, isEnabled: Bool, position: CGPoint, onButtonPress: @escaping () -> ()) { + init(textureName: String, text: String, isEnabled: Bool, position: CGPoint, onButtonPress: @escaping () -> ()) { self.onButtonPress = onButtonPress self.isEnabled = isEnabled - let texture = SKTexture(imageNamed: "yellow_button04") + let texture = SKTexture(imageNamed: textureName) super.init(texture: texture, color: SKColor.white, size: texture.size()) self.position = position @@ -38,16 +38,7 @@ class ButtonNode: SKSpriteNode { label.verticalAlignmentMode = .center label.text = text label.name = "label" - - if iconName.isEmpty { - label.position = CGPoint(x: 0, y: 0) - } else { - label.position = CGPoint(x: size.width * 0.25, y: 0) - let icon = SKSpriteNode(imageNamed: iconName) - icon.position = CGPoint(x: -size.width * 0.25, y: 0) - icon.zPosition = 1 - self.addChild(icon) - } + self.addChild(label) isUserInteractionEnabled = true } diff --git a/GoldWars/GoldWars/Components/DefaultBaseComponent.swift b/GoldWars/GoldWars/Components/DefaultBaseComponent.swift index 2510ad8..9d7df44 100644 --- a/GoldWars/GoldWars/Components/DefaultBaseComponent.swift +++ b/GoldWars/GoldWars/Components/DefaultBaseComponent.swift @@ -12,21 +12,21 @@ import GameKit class DefaultBaseComponent: GKComponent { var spriteNode: BaseNode - var labelNode : SKLabelNode? + var labelNode : SKLabelNode init(texture: SKTexture, position: CGPoint) { - spriteNode = BaseNode(texture: texture, size: CGSize(width: 80, height: 80)) + spriteNode = BaseNode(texture: texture, size: CGSize(width: 100, height: 100)) spriteNode.position = position spriteNode.zPosition = 2 - super.init() labelNode = SKLabelNode(text: "") - labelNode?.fontColor = SKColor.black - labelNode?.horizontalAlignmentMode = .left - labelNode?.verticalAlignmentMode = .center - labelNode?.fontName = "AvenirNext-Bold" - labelNode?.fontSize = 15 - labelNode?.position = CGPoint(x: position.x + 30 , y: position.y - 50 ) - labelNode?.zPosition = spriteNode.zPosition - 1 + labelNode.fontColor = SKColor.black + labelNode.horizontalAlignmentMode = .left + labelNode.verticalAlignmentMode = .center + labelNode.fontName = "AvenirNext-Bold" + labelNode.fontSize = 15 + labelNode.position = CGPoint(x: position.x + 30 , y: position.y - 50 ) + labelNode.zPosition = spriteNode.zPosition - 1 + super.init() } required init?(coder aDecoder: NSCoder) { diff --git a/GoldWars/GoldWars/Components/LabelComponent.swift b/GoldWars/GoldWars/Components/LabelComponent.swift new file mode 100644 index 0000000..aa57816 --- /dev/null +++ b/GoldWars/GoldWars/Components/LabelComponent.swift @@ -0,0 +1,32 @@ +// +// LabelComponent.swift +// GoldWars +// +// Created by Tim Herbst on 13.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import GameplayKit + +class LabelComponent: GKComponent { + var labelNode: LabelNode + + init(fontnamed: String?, name: String, text: String, fontSize: CGFloat, fontColor: UIColor, position: CGPoint, horizontalAlignmentMode: SKLabelHorizontalAlignmentMode, vertikalAligmentMode: SKLabelVerticalAlignmentMode, isAnimationEnabled: Bool, isAnimationInfinite: Bool) { + labelNode = LabelNode(fontNamed: fontnamed) + labelNode.name = name + labelNode.text = text + labelNode.fontSize = fontSize + labelNode.fontColor = fontColor + labelNode.horizontalAlignmentMode = horizontalAlignmentMode + labelNode.verticalAlignmentMode = vertikalAligmentMode + labelNode.position = position + if isAnimationEnabled { + labelNode.sequentiallyBouncingZoom(delay: 0.3, infinite: isAnimationInfinite) + } + super.init() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/GoldWars/GoldWars/Components/LabelNode.swift b/GoldWars/GoldWars/Components/LabelNode.swift new file mode 100644 index 0000000..669a0b5 --- /dev/null +++ b/GoldWars/GoldWars/Components/LabelNode.swift @@ -0,0 +1,152 @@ +// +// LabelNode.swift +// GoldWars +// +// Created by Tim Herbst on 13.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import SpriteKit + +class LabelNode: SKNode { + let colt = SKLabelNode() + var labels = [SKLabelNode]() + var text = "" { + didSet { + refreshLabels() + } + } + var fontName = "HelveticaNeue-UltraLight" { + didSet { + _ = labels.compactMap({ $0.fontName = fontName }) + refreshLabels() + } + } + var fontSize = CGFloat(30.0) { + didSet { + _ = labels.compactMap({ $0.fontSize = fontSize }) + refreshLabels() + } + } + var fontColor = UIColor.init(white: 1.0, alpha: 1.0) { + didSet { + _ = labels.compactMap({ $0.fontColor = fontColor }) + refreshLabels() + } + } + var horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.init(rawValue: 0) { // left + didSet { + _ = labels.compactMap({ $0.horizontalAlignmentMode = horizontalAlignmentMode! }) + refreshLabels() + } + } + var verticalAlignmentMode = SKLabelVerticalAlignmentMode.init(rawValue: 0) { // center + didSet { + _ = labels.compactMap({ $0.verticalAlignmentMode = verticalAlignmentMode! }) + refreshLabels() + } + } + var lineSpacingFactor: CGFloat = -1.3 { + didSet { + refreshLabels() + } + } + override init() { + super.init() + } + convenience init(text: String) { + self.init() + self.text = text + } + convenience init(fontNamed fontName: String?) { + self.init(text: "") + if let f = fontName { + self.fontName = f + } + } + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func refreshLabels() { + _ = labels.compactMap({ $0.removeFromParent() }) + labels.removeAll() + if text.count > 0 { + var newX: CGFloat = 0.0 + var gapX: CGFloat = 0.0 + let ghostSpace = SKLabelNode(text: ".") + ghostSpace.fontName = fontName + ghostSpace.fontSize = fontSize + let ghostSpaceWidth = ghostSpace.frame.size.width + var fullNodeWidth:CGFloat = 0.0 + for char in text { + if String(char) != " " { + let charLabelNode = SKLabelNode(text: String(char)) + charLabelNode.fontName = fontName + charLabelNode.fontSize = fontSize + fullNodeWidth += charLabelNode.frame.size.width + lineSpacingFactor + } else { + fullNodeWidth += ghostSpaceWidth + lineSpacingFactor + } + } + switch horizontalAlignmentMode { + case .left? : gapX = 0.0 + case .center? : gapX = fullNodeWidth/2 + case .right? : gapX = fullNodeWidth + default: break + } + var index: Int = 0 + for char in text { + if String(char) != " " { + let charLabelNode = SKLabelNode(text: String(char)) + charLabelNode.fontName = fontName + charLabelNode.fontSize = fontSize + charLabelNode.fontColor = fontColor + charLabelNode.horizontalAlignmentMode = .left + charLabelNode.verticalAlignmentMode = verticalAlignmentMode! + charLabelNode.position.x = newX - gapX + charLabelNode.alpha = 1 + self.addChild(charLabelNode) + labels.append(charLabelNode) + newX += charLabelNode.frame.size.width + lineSpacingFactor + } else { + ghostSpace.horizontalAlignmentMode = .left + ghostSpace.verticalAlignmentMode = verticalAlignmentMode! + ghostSpace.position.x = newX - gapX + labels.append(ghostSpace) + newX += ghostSpaceWidth + lineSpacingFactor + } + index += 1 + } + } + } + + func sequentiallyBouncingZoom(delay:TimeInterval, infinite:Bool = false) { + if labels.count > 0 && self.action(forKey: "sequentiallyBouncingZoom") == nil { + let main = SKAction.run { [weak self] in + guard let strongSelf = self else { return } + for i in 0.. SKAction { + return SKAction.sequence([SKAction.wait(forDuration: delay), action]) + } + class func afterDelay(_ delay: TimeInterval, runBlock block: @escaping () -> Void) -> SKAction { + return SKAction.afterDelay(delay, performAction: SKAction.run(block)) + } +} diff --git a/GoldWars/GoldWars/Components/PlayerInfoComponent.swift b/GoldWars/GoldWars/Components/PlayerInfoComponent.swift index d48b6e9..6b57cda 100644 --- a/GoldWars/GoldWars/Components/PlayerInfoComponent.swift +++ b/GoldWars/GoldWars/Components/PlayerInfoComponent.swift @@ -10,52 +10,3 @@ import Foundation import GameplayKit import GameKit - -class PlayerInfoComponent: GKComponent { - - var hostLabel:SKLabelNode - var hostUnitsLabel:SKLabelNode - - var peerLabel:SKLabelNode - var peerUnitsLabel:SKLabelNode - var host: GKPlayer? - var peer: GKPlayer? - - init(size: CGSize) { - if MatchmakingHelper.sharedInstance.isServer { - host = GKLocalPlayer.local - peer = MatchmakingHelper.sharedInstance.mpMatch?.players[0] - } else { - host = MatchmakingHelper.sharedInstance.mpMatch?.players[0] - peer = GKLocalPlayer.local - } - hostLabel = SKLabelNode(text: host?.displayName) - hostUnitsLabel = SKLabelNode(text: "500" ) - peerLabel = SKLabelNode(text: peer?.displayName) - peerUnitsLabel = SKLabelNode(text: "500") - super.init() - hostLabel.position = CGPoint(x: size.width * 0.02, y: size.height * 0.95) - hostLabel.horizontalAlignmentMode = .left - peerLabel.position = CGPoint(x: size.width * 0.98, y: size.height * 0.95) - peerLabel.horizontalAlignmentMode = .right - hostUnitsLabel.position = CGPoint(x: size.width * 0.05, y: size.height * 0.9) - peerUnitsLabel.position = CGPoint(x: size.width * 0.95, y: size.height * 0.9) - setColor(labelNodes: [hostLabel,hostUnitsLabel,peerLabel,peerUnitsLabel]) - } - - func update(){ - hostUnitsLabel.text = "\(EntityManager.sharedInstance.getUnitSum(by: host!))" - peerUnitsLabel.text = "\(EntityManager.sharedInstance.getUnitSum(by: peer!))" - } - - func setColor(labelNodes: [SKLabelNode]) -> Void { - for label in labelNodes { - label.fontColor = SKColor.black - } - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} diff --git a/GoldWars/GoldWars/Components/SingeClickButtonNode.swift b/GoldWars/GoldWars/Components/SingeClickButtonNode.swift new file mode 100644 index 0000000..8b10a71 --- /dev/null +++ b/GoldWars/GoldWars/Components/SingeClickButtonNode.swift @@ -0,0 +1,18 @@ +// +// SkillButtonNode.swift +// GoldWars +// +// Created by Simon Kellner on 18.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import SpriteKit + +class SingeClickButtonNode: ButtonNode { + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + self.isEnabled = false + } + +} diff --git a/GoldWars/GoldWars/Components/SkillComponent.swift b/GoldWars/GoldWars/Components/SkillComponent.swift new file mode 100644 index 0000000..001aa2a --- /dev/null +++ b/GoldWars/GoldWars/Components/SkillComponent.swift @@ -0,0 +1,25 @@ +// +// SkillComponent.swift +// GoldWars +// +// Created by Marcel Schwarz on 24.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import Foundation +import GameKit +import GameplayKit + +class SkillComponent: GKComponent { + var skillButtonNode: SingeClickButtonNode + + init(textureName: String, text: String, position: CGPoint, isEnabled: Bool, onButtonPress: @escaping () -> ()) { + skillButtonNode = SingeClickButtonNode(textureName: textureName, text: text, isEnabled: isEnabled, position: position, onButtonPress: onButtonPress) + super.init() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + diff --git a/GoldWars/GoldWars/Components/SliderComponent.swift b/GoldWars/GoldWars/Components/SliderComponent.swift index 9682f10..e681e70 100644 --- a/GoldWars/GoldWars/Components/SliderComponent.swift +++ b/GoldWars/GoldWars/Components/SliderComponent.swift @@ -2,23 +2,24 @@ // SliderComponent.swift // GoldWars // -// Created by Niko Jochim on 05.05.20. +// Created by Marcel Schwarz on 24.05.20. // Copyright © 2020 SP2. All rights reserved. // import GameplayKit + class SliderComponent: GKComponent { - var sliderNode: SliderNode + var sliderNode: SliderNode - init(width: CGFloat, position: CGPoint) { - sliderNode = SliderNode(width: width, position: position) - sliderNode.zPosition = 4 - super.init() - } + init(width: CGFloat, position: CGPoint) { + sliderNode = SliderNode(width: width, position: position) + sliderNode.zPosition = 5 + super.init() + } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } } diff --git a/GoldWars/GoldWars/Components/SpySkillComponent.swift b/GoldWars/GoldWars/Components/SpySkillComponent.swift deleted file mode 100644 index b193de5..0000000 --- a/GoldWars/GoldWars/Components/SpySkillComponent.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// SpySkillComponent.swift -// GoldWars -// -// Created by Niko Jochim on 01.05.20. -// Copyright © 2020 SP2. All rights reserved. -// - -import GameplayKit - -class SpySkillComponent: GKComponent{ - - let shapeNode: SKShapeNode - let labelNode: SKLabelNode - - init(text: String, texture: SKTexture?, anchorPoint: CGPoint) { - self.labelNode = SKLabelNode(text: text) - self.shapeNode = SKShapeNode(circleOfRadius: 30) - self.shapeNode.position = anchorPoint - self.labelNode.position = CGPoint(x: anchorPoint.x, y: anchorPoint.y - 15) - if texture != nil { - shapeNode.fillTexture = texture - }else { - shapeNode.fillColor = SKColor.gray - } - super.init() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - diff --git a/GoldWars/GoldWars/Components/TimerComponent.swift b/GoldWars/GoldWars/Components/TimerComponent.swift index 3d2579c..e69de29 100644 --- a/GoldWars/GoldWars/Components/TimerComponent.swift +++ b/GoldWars/GoldWars/Components/TimerComponent.swift @@ -1,74 +0,0 @@ -// -// TimerComponent.swift -// GoldWars -// -// Created by Daniel Steckert on 05.05.20. -// Copyright © 2020 SP2. All rights reserved. -// - -import GameplayKit - -class TimerComponent: GKComponent { - - let labelNode :SKLabelNode - var endTime :Date! - var duration :Double - var isRunning = false - - init(text: String, anchorPoint: CGPoint, duration: TimeInterval) { - self.labelNode = SKLabelNode(text: text) - self.labelNode.fontColor = UIColor.black - self.labelNode.fontSize = CGFloat(45) - self.labelNode.position = CGPoint(x: anchorPoint.x, y: anchorPoint.y - 15) - self.duration = duration + 1 - super.init() - startWithDuration(duration: self.duration) - } - - func startWithDuration(duration: TimeInterval){ - isRunning = true - endTime = Date().addingTimeInterval(duration) - RoundCalculatorService.sharedInstance.isCalculating = false - } - - func timeLeft() -> Int { - if isRunning { - let remainingSeconds = Int(endTime.timeIntervalSince(Date())) - if(remainingSeconds == 0) { - isRunning = false - } - return remainingSeconds - } - - // if(remainingSeconds < 0){ - // startWithDuration(duration: duration) - // } - return 0 - } - - func isFinished() -> Bool { - return timeLeft() == 0 - } - - func update() { - self.labelNode.text = String(timeLeft()) - - if(isFinished()){ - self.labelNode.text = "Synching" - if !MultiplayerNetwork.sharedInstance.isSending { - MultiplayerNetwork.sharedInstance.sendPlayerMoves(playerMoves: DataService.sharedInstance.localPlayerMoves) - } - if !RoundCalculatorService.sharedInstance.isCalculating - && DataService.sharedInstance.didReceiveAllData() - && MatchmakingHelper.sharedInstance.isServer { - RoundCalculatorService.sharedInstance.calculateRound() - } - } - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - diff --git a/GoldWars/GoldWars/DataService.swift b/GoldWars/GoldWars/DataService.swift index d94a992..506478d 100644 --- a/GoldWars/GoldWars/DataService.swift +++ b/GoldWars/GoldWars/DataService.swift @@ -6,14 +6,22 @@ // Copyright © 2020 SP2. All rights reserved. // -struct PlayerMove: Codable{ +struct PlayerMove: Codable { let fromBase: Int let toBase: Int var unitCount: Int } -struct Host: Codable { - let playerName: String +struct LocalRoundData: Codable { + var localPlayerMoves: [PlayerMove] + var hasAttackBoost: Bool + var hasDefenceBoost: Bool + + init() { + localPlayerMoves = [] + hasAttackBoost = false + hasDefenceBoost = false + } } class SnapshotModel: Codable { @@ -29,7 +37,7 @@ class BaseEntityModel: Codable { var unitCount: Int var ownership: String? - init(baseId: Int, unitCount: Int, ownership: String?) { + init(baseId: Int, unitCount: Int, ownership: String?, hasAttackBoost: Bool, hasDefenceBoost: Bool) { self.baseId = baseId self.unitCount = unitCount self.ownership = ownership @@ -38,41 +46,39 @@ class BaseEntityModel: Codable { class DataService { static let sharedInstance = DataService() - var localPlayerMoves: [PlayerMove] = [] - var remotePlayerMoves: [String: [PlayerMove]] = [:] + var localRoundData: LocalRoundData = LocalRoundData() + var remotePlayerMoves: [String: LocalRoundData] = [:] var snapshotModel: SnapshotModel? - var gameHost: Host? - var mapModel: MapGenerationModel? + var hostingPlayer = GameCenterManager.sharedInstance.hostingPlayer + var mapModel: MapGenerationModel? + var entityManager = EntityManager.gameEMInstance + func addMove(playerMove: PlayerMove) { - var equalMove = localPlayerMoves.filter { (ele) -> Bool in + var equalMove = localRoundData.localPlayerMoves.filter { (ele) -> Bool in ele.fromBase == playerMove.fromBase && ele.toBase == playerMove.toBase } if equalMove.count == 1 { equalMove[0].unitCount = Int(equalMove[0].unitCount) + Int(playerMove.unitCount) } else { - self.localPlayerMoves.append(playerMove) + self.localRoundData.localPlayerMoves.append(playerMove) } } - func addRemotePlayerMoves(playerName: String, playerMoves: [PlayerMove]) { - self.remotePlayerMoves[playerName] = playerMoves + func addRemotePlayerMoves(playerName: String, localRoundData: LocalRoundData) { + self.remotePlayerMoves[playerName] = localRoundData } func didReceiveAllData() -> Bool { - return remotePlayerMoves.count == MatchmakingHelper.sharedInstance.mpMatch?.players.count + return remotePlayerMoves.count == GameCenterManager.sharedInstance.myMatch?.players.count } - func setGameHost(host: Host) { - self.gameHost = host - } - func setSnapshotModel(snapshotModel: SnapshotModel) { self.snapshotModel = snapshotModel } func setMapModel(model: MapGenerationModel) { self.mapModel = model - MapFactory(scene: EntityManager.sharedInstance.scene, entityManager: EntityManager.sharedInstance).loadMap(fromModel: DataService.sharedInstance.mapModel!) + MapFactory(scene: entityManager.scene, entityManager: entityManager).load(fromModel: DataService.sharedInstance.mapModel!) } } diff --git a/GoldWars/GoldWars/Entities/Base.swift b/GoldWars/GoldWars/Entities/Base.swift index 41078fa..e01ba62 100644 --- a/GoldWars/GoldWars/Entities/Base.swift +++ b/GoldWars/GoldWars/Entities/Base.swift @@ -13,7 +13,8 @@ import GameKit class Base: GKEntity{ static var BASE_ID_COUNT: Int = 0 var unitCount: Int - var unitType: UnitType + var hasAttackBoost = false + var hasDefenseBoost = false var adjacencyList: Array var changeOwnership: Bool var ownershipPlayer: GKPlayer? @@ -22,7 +23,6 @@ class Base: GKEntity{ init(position: CGPoint, player: GKPlayer! = nil, team: Team! = nil) { self.unitCount = 0 - self.unitType = .General self.adjacencyList = [Base]() self.changeOwnership = false self.ownershipPlayer = player @@ -32,28 +32,29 @@ class Base: GKEntity{ super.init() let spritePos = position - addComponent(DefaultBaseComponent(texture: SKTexture(imageNamed: "Base"), position: spritePos)) + addComponent(DefaultBaseComponent(texture: SKTexture(imageNamed: "BaseTexture"), position: spritePos)) if(team != nil && player != nil){ addComponent(TeamComponent(team: team!, player: player!, position: spritePos)) self.unitCount = 500 } if ownershipPlayer == GKLocalPlayer.local { - self.component(ofType: DefaultBaseComponent.self)?.labelNode?.text = "\(unitCount)" + self.component(ofType: DefaultBaseComponent.self)?.labelNode.text = "\(unitCount)" } - - } func doPlayerMoveTypeToBase(base: Base, playerMoveType: PlayerMoveType, units: Int) -> [GKEntity]{ - base.changeOwnership = true + if base.ownershipPlayer != GKLocalPlayer.local { + base.changeOwnership = true + } base.ownershipPlayer = self.ownershipPlayer self.unitCount -= units base.unitCount += units - self.component(ofType: DefaultBaseComponent.self)?.labelNode?.text = "\(self.unitCount)" - base.component(ofType: DefaultBaseComponent.self)?.labelNode?.text = "\(base.unitCount)" + self.component(ofType: DefaultBaseComponent.self)?.labelNode.text = "\(self.unitCount)" + base.component(ofType: DefaultBaseComponent.self)?.labelNode.text = "\(base.unitCount)" DataService.sharedInstance.addMove(playerMove: PlayerMove(fromBase: self.baseID, toBase: base.baseID, - unitCount: units * playerMoveType.rawValue)) + unitCount: units * playerMoveType.rawValue) + ) return [self, base] } diff --git a/GoldWars/GoldWars/Entities/Button.swift b/GoldWars/GoldWars/Entities/Button.swift index 8ac174d..cbc4b34 100644 --- a/GoldWars/GoldWars/Entities/Button.swift +++ b/GoldWars/GoldWars/Entities/Button.swift @@ -13,10 +13,10 @@ class Button: GKEntity{ let name: String var isEnabled = true - init(name: String, iconName: String, text: String, position: CGPoint, onButtonPress: @escaping () -> ()) { + init(name: String, textureName: String, text: String, position: CGPoint, onButtonPress: @escaping () -> ()) { self.name = name super.init() - self.addComponent(ButtonComponent(iconName: iconName, text: text, position: position, isEnabled: isEnabled, onButtonPress: onButtonPress)) + self.addComponent(ButtonComponent(textureName: textureName, text: text, position: position, isEnabled: isEnabled, onButtonPress: onButtonPress)) } required init?(coder: NSCoder) { diff --git a/GoldWars/GoldWars/Entities/EntityManager.swift b/GoldWars/GoldWars/Entities/EntityManager.swift index a1c69d3..6987fb9 100644 --- a/GoldWars/GoldWars/Entities/EntityManager.swift +++ b/GoldWars/GoldWars/Entities/EntityManager.swift @@ -12,7 +12,9 @@ import GameKit class EntityManager { - static let sharedInstance = EntityManager() + static let gameEMInstance = EntityManager() + static let menuEMInstance = EntityManager() + static let settingsEMInstance = EntityManager() var entities = Set() var scene: SKScene @@ -30,37 +32,40 @@ class EntityManager { func add(_ entity: GKEntity) { entities.insert(entity) - if let spriteNode = entity.component(ofType: DefaultBaseComponent.self)?.spriteNode { - scene.addChild(spriteNode) + + if let modalEntitiy = entity as? Modal { + scene.addChild(modalEntitiy.background) + scene.addChild(modalEntitiy.closeButton) + scene.addChild(modalEntitiy.header) + scene.addChild(modalEntitiy.body) + scene.addChild(modalEntitiy.footer) + scene.addChild(modalEntitiy.overlay) + isModal = true } - if let label = entity.component(ofType: DefaultBaseComponent.self)?.labelNode { - scene.addChild(label) + + if let hudEntitiy = entity as? HUD { + scene.addChild(hudEntitiy.hostLabel) + scene.addChild(hudEntitiy.hostUnitsLabel) + scene.addChild(hudEntitiy.peerLabel) + scene.addChild(hudEntitiy.peerUnitsLabel) + scene.addChild(hudEntitiy.defSkill) + scene.addChild(hudEntitiy.atkSkill) + scene.addChild(hudEntitiy.spySkill) + scene.addChild(hudEntitiy.roundTimerLabel) + scene.addChild(hudEntitiy.finishButton) + scene.addChild(hudEntitiy.backgroundRoundCounter) + scene.addChild(hudEntitiy.currentRoundLabel) + scene.addChild(hudEntitiy.roundsLabel) + scene.addChild(hudEntitiy.roundLabel) + } + + if let spriteNode = entity.component(ofType: DefaultBaseComponent.self) { + scene.addChild(spriteNode.labelNode) + scene.addChild(spriteNode.spriteNode) } if let fire = entity.component(ofType: TeamComponent.self)?.fire{ scene.addChild(fire) } - if let spriteNode = entity.component(ofType: ModalBackgroundComponent.self)?.spriteNode { - scene.addChild(spriteNode) - } - if let modal = entity.component(ofType: ModalContentComponent.self) { - scene.addChild(modal.header) - scene.addChild(modal.body) - scene.addChild(modal.footer) - isModal = true - } - if let skillButtonNode = entity.component(ofType: AtkBoostSkillComponent.self)?.skillButtonNode { - scene.addChild(skillButtonNode) - } - if let skillButtonNode = entity.component(ofType: DefBoostSkillComponent.self)?.skillButtonNode { - scene.addChild(skillButtonNode) - } - if let skill = entity.component(ofType: SpySkillComponent.self) { - scene.addChild(skill.shapeNode) - scene.addChild(skill.labelNode) - } - if let timer = entity.component(ofType: TimerComponent.self) { - scene.addChild(timer.labelNode) - } if let buttonNode = entity.component(ofType: ButtonComponent.self)?.buttonNode { scene.addChild(buttonNode) } @@ -76,36 +81,18 @@ class EntityManager { if let labelNode = entity.component(ofType: LabelComponent.self)?.labelNode { scene.addChild(labelNode) } - if let cancelBtnNode = entity.component(ofType: CancelBtnComponent.self)?.cancelBtnNode { - scene.addChild(cancelBtnNode) - } if let node = entity.component(ofType: SpinningLogoComponent.self)?.node { scene.addChild(node) } if let wayNode = entity.component(ofType: DefaultWayComponent.self)?.shapeNode { scene.addChild(wayNode) } - if let playerInfos = entity.component(ofType: PlayerInfoComponent.self) { - scene.addChild(playerInfos.hostLabel) - scene.addChild(playerInfos.hostUnitsLabel) - scene.addChild(playerInfos.peerLabel) - scene.addChild(playerInfos.peerUnitsLabel) - } } func remove(_ entity: GKEntity) { if let spriteNode = entity.component(ofType: DefaultBaseComponent.self)?.spriteNode { spriteNode.removeFromParent() } - if let spriteNode = entity.component(ofType: ModalBackgroundComponent.self)?.spriteNode { - spriteNode.removeFromParent() - } - if let modal = entity.component(ofType: ModalContentComponent.self) { - modal.header.removeFromParent() - modal.body.removeFromParent() - modal.footer.removeFromParent() - isModal = false - } if let sliderNode = entity.component(ofType: SliderComponent.self)?.sliderNode { sliderNode.sliderKnob.removeFromParent() sliderNode.sliderLine.removeFromParent() @@ -113,9 +100,6 @@ class EntityManager { if let modalButton = entity.component(ofType: ButtonComponent.self) { modalButton.buttonNode.removeFromParent() } - if let cancelBtnNode = entity.component(ofType: CancelBtnComponent.self)?.cancelBtnNode { - cancelBtnNode.removeFromParent() - } entities.remove(entity) } @@ -138,7 +122,7 @@ class EntityManager { scene.addChild(fire) } } - base.changeOwnership = false + GameCenterManager.sharedInstance.addAchievementProgress(identifier: "de.hft.stuttgart.ip2.goldwars.capture.fifty.bases", increasePercentComplete: 2) } } } @@ -150,19 +134,36 @@ class EntityManager { let snapBase = self.getSnapshotBaseById(baseId: base.baseID, snapshotModel: snapshotModel) var getOwnerBySnapBase: GKPlayer? = nil base.unitCount = snapBase.unitCount + base.changeOwnership = false if snapBase.ownership != nil { - getOwnerBySnapBase = MatchmakingHelper.sharedInstance.getGKPlayerByUsername(displayName: snapBase.ownership!) + getOwnerBySnapBase = GameCenterManager.sharedInstance.getGKPlayerByUsername(displayName: snapBase.ownership!) } else { entity.removeComponent(ofType: TeamComponent.self) + base.ownershipPlayer = nil } if getOwnerBySnapBase != nil { - if getOwnerBySnapBase == GKLocalPlayer.local { - base.component(ofType: DefaultBaseComponent.self)?.labelNode?.text = "\(base.unitCount)" - }else { - base.component(ofType: DefaultBaseComponent.self)?.labelNode?.text = "" + if base.ownershipPlayer != getOwnerBySnapBase { + //TODO: Outsource following with a AnimationManager + let explosion = SKEmitterNode(fileNamed: "Explosion")! + scene.addChild(explosion) + explosion.zPosition = 2 + explosion.position = base.position + explosion.name = "explosion" + explosion.particleColorSequence = nil + explosion.particleColorBlendFactor = 1.0 + let wait = SKAction.wait(forDuration: 1) + let removeParticle = SKAction.removeFromParent() + let sequence = SKAction.sequence([wait, removeParticle]) + explosion.run(sequence) + } + + + if getOwnerBySnapBase == GKLocalPlayer.local { + base.component(ofType: DefaultBaseComponent.self)?.labelNode.text = "\(base.unitCount)" + } else { + base.component(ofType: DefaultBaseComponent.self)?.labelNode.text = "" } - base.changeOwnership = true base.ownershipPlayer = getOwnerBySnapBase if (entity.component(ofType: TeamComponent.self) != nil) { entity.component(ofType: TeamComponent.self)!.change(to: getTeamByPlayer(playerName: snapBase.ownership!), to: getOwnerBySnapBase!) @@ -180,7 +181,7 @@ class EntityManager { } } - getHUD()?.component(ofType: PlayerInfoComponent.self)?.update() + getHUD()!.updateUnitSum() } @@ -216,6 +217,14 @@ class EntityManager { return entities.filter{$0 is Base && ($0 as! Base).component(ofType: TeamComponent.self)?.team == team } as! Set } + func getOpponentBases(for team: Team) -> Set { + if(team == .team1){ + return getBasesByTeam(for: .team2) + }else { + return getBasesByTeam(for: .team1) + } + } + func getBasesByPlayer(for player: GKPlayer) -> Set { return entities.filter{$0 is Base && ($0 as! Base).component(ofType: TeamComponent.self)?.player == player } as! Set } @@ -237,6 +246,10 @@ class EntityManager { return entities.filter { $0 is Base && ($0 as! Base).component(ofType: TeamComponent.self)?.player.displayName == playerName }[0].component(ofType: TeamComponent.self)!.team } + func getTeam() -> Team { + return entities.filter { $0 is Base && ($0 as! Base).component(ofType: TeamComponent.self)?.player.displayName == GKLocalPlayer.local.displayName }[0].component(ofType: TeamComponent.self)!.team + } + func getBasebyID(id: Int) -> Base?{ for entity in entities { if entity is Base && (entity as! Base).baseID == id { @@ -258,8 +271,8 @@ class EntityManager { return entities.filter{$0 is Button && ($0 as! Button).name == buttonName }[0] as! Button } - func getHUD() -> GKEntity? { - return entities.filter{$0 is HUD}[0] + func getHUD() -> HUD? { + return entities.filter{$0 is HUD}[0] as? HUD } func getSnapshotModel() -> SnapshotModel { @@ -268,15 +281,20 @@ class EntityManager { for entity in bases { let base = entity as! Base - snapBase.append(BaseEntityModel(baseId: base.baseID, unitCount: base.unitCount, ownership: base.ownershipPlayer?.displayName)) + snapBase.append( + BaseEntityModel( + baseId: base.baseID, + unitCount: base.unitCount, + ownership: base.ownershipPlayer?.displayName, + hasAttackBoost: base.hasAttackBoost, + hasDefenceBoost: base.hasDefenseBoost + ) + ) } return SnapshotModel(baseEntites: snapBase) } - func getTimer() -> TimerComponent { - return entities.filter{$0 is HUD}[0].component(ofType: TimerComponent.self)! - } func getUnitSum(by player: GKPlayer) -> Int{ let bases = getBasesByPlayer(for: player) @@ -286,4 +304,44 @@ class EntityManager { } return sum } + + func removeModal() { + entities.forEach({entity in + if let modal = entity as? Modal { + modal.background.removeFromParent() + modal.closeButton.removeFromParent() + modal.header.removeFromParent() + modal.body.removeFromParent() + modal.footer.removeFromParent() + modal.overlay.removeFromParent() + + if let slider = modal.component(ofType: SliderComponent.self) { + slider.sliderNode.removeFromParent() + slider.sliderNode.sliderKnob.removeFromParent() + slider.sliderNode.sliderLine.removeFromParent() + } + + if let button = modal.component(ofType: ButtonComponent.self) { + button.buttonNode.removeFromParent() + } + self.remove(modal) + + for child in scene.children { + if(child.name != "fire"){ + child.alpha = 1 + } + } + + isModal = false + } + }) + } + + func getTimer() -> RoundTimer? { + return getHUD()?.roundTimer + } + + func updateTime(time: String) { + getHUD()?.roundTimerLabel.text = time + } } diff --git a/GoldWars/GoldWars/Entities/HUD.swift b/GoldWars/GoldWars/Entities/HUD.swift index e2da8bf..ed34eb6 100644 --- a/GoldWars/GoldWars/Entities/HUD.swift +++ b/GoldWars/GoldWars/Entities/HUD.swift @@ -7,30 +7,177 @@ // import GameplayKit +import GameKit class HUD: GKEntity { + var entityManager = EntityManager.gameEMInstance + var hostLabel:SKLabelNode + var hostUnitsLabel:SKLabelNode + + var peerLabel:SKLabelNode + var peerUnitsLabel:SKLabelNode + var host: GKPlayer? + var peer: GKPlayer? + + var spySkill: SingeClickButtonNode + var defSkill: SingeClickButtonNode + var atkSkill: SingeClickButtonNode + + var roundTimerLabel: SKLabelNode + let roundTimer: RoundTimer + + var backgroundRoundCounter: SKSpriteNode + var currentRoundLabel: SKLabelNode + var roundsLabel: SKLabelNode + var roundLabel: SKLabelNode + + var finishButton: ButtonNode + init(size: CGSize) { + host = GameCenterManager.sharedInstance.hostingPlayer + peer = GameCenterManager.sharedInstance.peerPlayer + hostLabel = SKLabelNode(text: host?.displayName) + hostUnitsLabel = SKLabelNode(text: "500" ) + peerLabel = SKLabelNode(text: peer?.displayName) + peerUnitsLabel = SKLabelNode(text: "500") + + roundTimerLabel = SKLabelNode(text: "") + roundTimerLabel.fontColor = UIColor.black + roundTimerLabel.fontSize = CGFloat(45) + roundTimerLabel.position = CGPoint(x: size.width * 0.5, y: size.height * 0.9) + roundTimerLabel.horizontalAlignmentMode = .center + + self.roundTimer = RoundTimer() + + spySkill = SingeClickButtonNode( + textureName: "yellow_circle", + text: "Spy", + isEnabled: true, + position: CGPoint(x: EntityManager.gameEMInstance.scene.size.width * 0.75, y: EntityManager.gameEMInstance.scene.size.height * 0.1), + onButtonPress: { + EntityManager.gameEMInstance.getOpponentBases(for: EntityManager.gameEMInstance.getTeam()).forEach({base in base.component(ofType: DefaultBaseComponent.self)?.labelNode.text = "\(base.unitCount)"}) + GameCenterManager.sharedInstance.addAchievementProgress(identifier: "de.hft.stuttgart.ip2.goldwars.skill.first.time", increasePercentComplete: 100) + GameCenterManager.sharedInstance.addAchievementProgress(identifier: "de.hft.stuttgart.ip2.goldwars.skill.spy.ten", increasePercentComplete: 10) + } + ) + defSkill = SingeClickButtonNode( + textureName: "yellow_circle", + text: "Def", + isEnabled: true, + position: CGPoint(x: EntityManager.gameEMInstance.scene.size.width * 0.85, y: EntityManager.gameEMInstance.scene.size.height * 0.1), + onButtonPress: { + DataService.sharedInstance.localRoundData.hasDefenceBoost = true + GameCenterManager.sharedInstance.addAchievementProgress(identifier: "de.hft.stuttgart.ip2.goldwars.skill.first.time", increasePercentComplete: 100) + GameCenterManager.sharedInstance.addAchievementProgress(identifier: "de.hft.stuttgart.ip2.goldwars.skill.def.ten", increasePercentComplete: 10) + } + ) + atkSkill = SingeClickButtonNode( + textureName: "yellow_circle", + text: "Atk", + isEnabled: true, + position: CGPoint(x: EntityManager.gameEMInstance.scene.size.width * 0.95, y: EntityManager.gameEMInstance.scene.size.height * 0.1), + onButtonPress: { + DataService.sharedInstance.localRoundData.hasAttackBoost = true + GameCenterManager.sharedInstance.addAchievementProgress(identifier: "de.hft.stuttgart.ip2.goldwars.skill.first.time", increasePercentComplete: 100) + GameCenterManager.sharedInstance.addAchievementProgress(identifier: "de.hft.stuttgart.ip2.goldwars.skill.atk.ten", increasePercentComplete: 10) + } + ) + + finishButton = SingeClickButtonNode( + textureName: "yellow_button04", + text: "Done", + isEnabled: true, + position: CGPoint( + x: EntityManager.gameEMInstance.scene.size.width * 0.15, + y: EntityManager.gameEMInstance.scene.size.height * 0.06), + onButtonPress: { } + ) + finishButton.size = CGSize(width: 80, height: 40) + finishButton.zPosition = 2 + + backgroundRoundCounter = SKSpriteNode(texture: SKTexture(imageNamed: "roundInfo_texture")) + currentRoundLabel = SKLabelNode(fontNamed: "Courier-Bold") + roundsLabel = SKLabelNode(fontNamed: "Courier-Bold") + roundLabel = SKLabelNode(fontNamed: "Courier-Bold") super.init() - addComponent(SpySkillComponent(text: "Spy", - texture: nil, - anchorPoint: CGPoint(x: size.width * 0.75, y: size.height * 0.1))) + initRoundInfo(size: size) + finishButton.onButtonPress = { [unowned self] in + self.finishRound() + } - addComponent(AtkBoostSkillComponent(iconName: "", text: "Atk", position: CGPoint(x: size.width * 0.85, y: size.height * 0.1), isEnabled: true)) - - - addComponent(DefBoostSkillComponent(iconName: "", text: "Def", position: CGPoint(x: size.width * 0.95, y: size.height * 0.1), isEnabled: true)) - - addComponent(TimerComponent(text: "", - anchorPoint: CGPoint(x: size.width * 0.5, y: size.height * 0.9), duration: 30)) - - addComponent(PlayerInfoComponent(size: size)) + hostLabel.position = CGPoint(x: size.width * 0.02, y: size.height * 0.95) + hostLabel.horizontalAlignmentMode = .left + peerLabel.position = CGPoint(x: size.width * 0.98, y: size.height * 0.95) + peerLabel.horizontalAlignmentMode = .right + hostUnitsLabel.position = CGPoint(x: size.width * 0.05, y: size.height * 0.9) + peerUnitsLabel.position = CGPoint(x: size.width * 0.95, y: size.height * 0.9) + setColor(labelNodes: [hostLabel,hostUnitsLabel,peerLabel,peerUnitsLabel]) + roundTimer.initTimer() + startWithDuration() + } + + func updateUnitSum(){ + hostUnitsLabel.text = "\(entityManager.getUnitSum(by: host!))" + peerUnitsLabel.text = "\(entityManager.getUnitSum(by: peer!))" + } + + func setColor(labelNodes: [SKLabelNode]) -> Void { + for label in labelNodes { + label.fontColor = SKColor.black + } } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + func startWithDuration(){ + roundTimer.startTimer() + finishButton.isEnabled = true + self.roundTimer.roundEnded = "Syncing" + RoundCalculatorService.sharedInstance.isCalculating = false + } + + func finishRound() -> () { + self.roundTimer.timeLeft = 1; + self.roundTimer.roundEnded = "Waiting for other player..." + } + + func initRoundInfo(size: CGSize) -> () { + backgroundRoundCounter.zPosition = 2 + backgroundRoundCounter.position = CGPoint(x: Double(size.width) * 0.06, y: Double(size.height) * 0.08) + + currentRoundLabel.text = "\(RoundCalculatorService.sharedInstance.currentRound)" + currentRoundLabel.fontSize = 50 + currentRoundLabel.fontColor = SKColor.black + currentRoundLabel.verticalAlignmentMode = .center + currentRoundLabel.position = CGPoint(x: backgroundRoundCounter.position.x, y: backgroundRoundCounter.position.y - 5) + currentRoundLabel.zPosition = backgroundRoundCounter.zPosition + 1 + + roundsLabel.zPosition = backgroundRoundCounter.zPosition + 1 + roundsLabel.text = "of \(RoundCalculatorService.sharedInstance.MAX_ROUNDS)" + roundsLabel.fontColor = SKColor.black + roundsLabel.verticalAlignmentMode = .center + roundsLabel.fontSize = 12 + roundsLabel.position = CGPoint(x: currentRoundLabel.position.x, y: currentRoundLabel.position.y - 25) + + roundLabel.zPosition = backgroundRoundCounter.zPosition + 1 + roundLabel.text = "Round" + roundLabel.fontColor = SKColor.black + roundLabel.verticalAlignmentMode = .center + roundLabel.fontSize = 12 + roundLabel.position = CGPoint(x: currentRoundLabel.position.x, y: currentRoundLabel.position.y + 25) + } + + func setCurrentRound(round: Int) -> Void { + currentRoundLabel.text = "\(round)" + let newRoundAction = SKAction.sequence([ + SKAction.scale(by: 2, duration: 1), + SKAction.scale(by: 0.5, duration: 1), + ]) + currentRoundLabel.run(newRoundAction) + } } diff --git a/GoldWars/GoldWars/Entities/Label.swift b/GoldWars/GoldWars/Entities/Label.swift new file mode 100644 index 0000000..2cac987 --- /dev/null +++ b/GoldWars/GoldWars/Entities/Label.swift @@ -0,0 +1,21 @@ +// +// Label.swift +// GoldWars +// +// Created by Tim Herbst on 13.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import GameplayKit + +class Label: GKEntity { + + init(fontnamed: String, name: String, text: String, fontSize: CGFloat, fontColor: UIColor, position: CGPoint, horizontalAlignmentMode: SKLabelHorizontalAlignmentMode, vertikalAligmentMode: SKLabelVerticalAlignmentMode, isAnimationEnabled: Bool, isAnimationInfinite: Bool) { + super.init() + self.addComponent(LabelComponent(fontnamed: fontnamed, name: name, text: text, fontSize: fontSize, fontColor: fontColor, position: position, horizontalAlignmentMode: horizontalAlignmentMode, vertikalAligmentMode: vertikalAligmentMode, isAnimationEnabled: isAnimationEnabled, isAnimationInfinite: isAnimationInfinite)) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/GoldWars/GoldWars/Entities/Modal.swift b/GoldWars/GoldWars/Entities/Modal.swift index 489aed4..9e9a0d4 100644 --- a/GoldWars/GoldWars/Entities/Modal.swift +++ b/GoldWars/GoldWars/Entities/Modal.swift @@ -8,31 +8,88 @@ import GameplayKit +enum ModalType: String{ + case BaseDetails + case BaseAttack + case BaseMoveOwnUnits +} + class Modal: GKEntity{ - var unitCount:Int + var entityManager = EntityManager.gameEMInstance + var unitCount: Int + var background: SKSpriteNode + var closeButton: ButtonNode + var header: SKLabelNode + var body: SKLabelNode + var footer: SKLabelNode + var overlay: SKSpriteNode init(modaltype: ModalType, base: Base, anchorPoint: CGPoint, gameScene: GameScene, currentDraggedBase: Base?, touchLocation: CGPoint, collisionBase: Base?) { unitCount = base.unitCount + + let texture = SKTexture(imageNamed:"ModalBackground") + background = SKSpriteNode(texture: texture, size: texture.size()) + background.setScale(2.4) + background.position = anchorPoint + background.zPosition = 4 + + closeButton = ButtonNode(textureName: "red_cross", text: "", isEnabled: true, position: CGPoint(x: anchorPoint.x + 195, y: anchorPoint.y + 178), onButtonPress: { + EntityManager.gameEMInstance.removeModal() + }) + closeButton.size = CGSize(width: 26, height: 26) + closeButton.zPosition = 5 + + overlay = SKSpriteNode(color: UIColor.init(red: 0, green: 0, blue: 0, alpha: 0.7), size: gameScene.size) + overlay.anchorPoint = gameScene.anchorPoint + overlay.zPosition = 3 + + switch modaltype { + case .BaseDetails: + header = SKLabelNode(text: "Information") + body = SKLabelNode(text: "Diese Basis enthält \(base.unitCount) Einheiten") + footer = SKLabelNode() + case .BaseAttack: + header = SKLabelNode(text: "Angriff") + body = SKLabelNode(text: "Schicke \(unitCount / 2)\nEinheiten") + footer = SKLabelNode() + case .BaseMoveOwnUnits: + header = SKLabelNode(text: "Formation") + body = SKLabelNode(text: "Sende \(unitCount / 2)\nEinheiten") + footer = SKLabelNode() + } + + self.header.position = CGPoint(x: anchorPoint.x, y: anchorPoint.y + 90) + self.header.fontName = "HelveticaNeue-Bold" + self.header.fontSize = 40 + self.header.zPosition = 5 + + self.body.position = CGPoint(x: anchorPoint.x, y: anchorPoint.y - 20) + self.body.numberOfLines = 2 + self.body.preferredMaxLayoutWidth = 390 + self.body.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.center + self.body.fontName = "HelveticaNeue-Bold" + self.body.fontSize = 40 + self.body.zPosition = 5 + + self.footer.position = CGPoint(x: anchorPoint.x, y: anchorPoint.y - 40) + self.footer.fontName = "HelveticaNeue-Bold" + self.footer.fontSize = 40 + self.footer.zPosition = 5 + super.init() + switch modaltype{ case .BaseDetails: - addComponent(ModalBackgroundComponent(anchorPoint: anchorPoint)) - addComponent(ModalContentComponent(header: "Basis Information", body: "Diese Basis enthält \(base.unitCount) Einheiten", footer: "", anchorPoint: anchorPoint)) - addComponent(ButtonComponent(iconName: "", text: "Zurück", position: CGPoint(x: anchorPoint.x , y: anchorPoint.y - 120), isEnabled: true, onButtonPress: { - self.removeModalEntities(gameScene: gameScene) + addComponent(ButtonComponent(textureName: "yellow_button04", text: "Zurück", position: CGPoint(x: anchorPoint.x , y: anchorPoint.y - 105), isEnabled: true, onButtonPress: { + EntityManager.gameEMInstance.removeModal() })) - case .BaseAttack: - addComponent(ModalBackgroundComponent(anchorPoint: anchorPoint)) + case .BaseAttack, .BaseMoveOwnUnits: + let text = (modaltype == .BaseAttack) ? "Angriff" : "Senden" addComponent(SliderComponent(width: 300, position: CGPoint(x: anchorPoint.x , y: anchorPoint.y - 50))) - addComponent(ModalContentComponent(header: "Angriff", body: "Schicke \(unitCount / 2) Einheiten", - footer: "", anchorPoint: anchorPoint)) - addComponent(ButtonComponent(iconName: "", text: "Senden", position: CGPoint(x: anchorPoint.x , y: anchorPoint.y - 120), isEnabled: true, onButtonPress: { + addComponent(ButtonComponent(textureName: "yellow_button04", text: text, position: CGPoint(x: anchorPoint.x , y: anchorPoint.y - 105), isEnabled: true, onButtonPress: { self.sendUnits(currentDraggedBase: currentDraggedBase, touchLocation: touchLocation, gameScene: gameScene, collisionBase: collisionBase) - self.removeModalEntities(gameScene: gameScene) - })) - addComponent(CancelBtnComponent(iconName: "", text: "", position: CGPoint(x: anchorPoint.x + 160, y: anchorPoint.y + 140), isEnabled: true, onButtonPress: { - self.removeModalEntities(gameScene: gameScene) + EntityManager.gameEMInstance.removeModal() })) } } @@ -42,14 +99,9 @@ class Modal: GKEntity{ } func removeModalEntities(gameScene: SKScene){ - for entity in EntityManager.sharedInstance.entities { - if EntityManager.sharedInstance.isModal && entity.isMember(of: Modal.self) { - EntityManager.sharedInstance.remove(entity) - } - for child in gameScene.children { - if(child.name != "fire"){ - child.alpha = 1 - } + for entity in entityManager.entities { + if entityManager.isModal && entity.isMember(of: Modal.self) { + entityManager.remove(entity) } } } @@ -57,7 +109,8 @@ class Modal: GKEntity{ func sendUnits(currentDraggedBase: Base?, touchLocation: CGPoint, gameScene: GameScene, collisionBase: Base?){ for base in currentDraggedBase!.adjacencyList { if base == collisionBase { - EntityManager.sharedInstance.update((currentDraggedBase?.doPlayerMoveTypeToBase(base: base, playerMoveType: PlayerMoveType.AtkMove, units: Int(GameScene.sendUnits)))!) + RoundCalculatorService.sharedInstance.increaseMoveCounter(ownBase: currentDraggedBase?.ownershipPlayer == base.ownershipPlayer) + entityManager.update((currentDraggedBase?.doPlayerMoveTypeToBase(base: base, playerMoveType: PlayerMoveType.AtkMove, units: Int(GameScene.sendUnits)))!) GameScene.sendUnits = 0 } } diff --git a/GoldWars/GoldWars/Enums/ModalType.swift b/GoldWars/GoldWars/Enums/ModalType.swift deleted file mode 100644 index 40bcedf..0000000 --- a/GoldWars/GoldWars/Enums/ModalType.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// ModalType.swift -// GoldWars -// -// Created by Niko Jochim on 01.05.20. -// Copyright © 2020 SP2. All rights reserved. -// - -enum ModalType: String{ - case BaseDetails - case BaseAttack -} diff --git a/GoldWars/GoldWars/GameCenterHelper.swift b/GoldWars/GoldWars/GameCenterHelper.swift deleted file mode 100644 index abf9578..0000000 --- a/GoldWars/GoldWars/GameCenterHelper.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// GameCenterHelper.swift -// GoldWars -// -// Created by Jakob Haag on 02.05.20. -// Copyright © 2020 SP2. All rights reserved. -// - -import GameKit - -final class GameCenterHelper: NSObject { - typealias CompletionBlock = (Error?) -> Void - - static let helper = GameCenterHelper() - - var viewController: UIViewController? - - static var isAuthenticated: Bool { - return GKLocalPlayer.local.isAuthenticated - } - - override init() { - super.init() - - GKLocalPlayer.local.authenticateHandler = { gcAuthVC, error in - NotificationCenter.default - .post(name: .authenticationChanged, object: GKLocalPlayer.local.isAuthenticated) - - if GKLocalPlayer.local.isAuthenticated { - print("Authenticated to Game Center!") - } else if let vc = gcAuthVC { - self.viewController?.present(vc, animated: true) - } - else { - print("Error authentication to GameCenter: " + - "\(error?.localizedDescription ?? "none")") - } - } - } -} - -extension Notification.Name { - static let presentGame = Notification.Name(rawValue: "presentGame") - static let authenticationChanged = Notification.Name(rawValue: "authenticationChanged") -} diff --git a/GoldWars/GoldWars/GameCenterManager.swift b/GoldWars/GoldWars/GameCenterManager.swift new file mode 100644 index 0000000..d10654b --- /dev/null +++ b/GoldWars/GoldWars/GameCenterManager.swift @@ -0,0 +1,265 @@ +// +// GameCenter.swift +// GoldWars +// +// Created by Niko Jochim on 23.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import Foundation +import GameKit +import os + +struct RandomNumber: Codable { + let number: Int + init() { + number = Int.random(in: 0...999999) + } +} + +struct State: Codable { + // 0 PlayerInit fertig + // 1 RemotePlayerInit fertig + // 2 Peer hat Map erhalten + // 3 Host hat Spiel gestartet + // 4 Peer hat verloren + // 5 Peer hat gewonnen + let state: Int +} + +final class GameCenterManager: NSObject, GKMatchmakerViewControllerDelegate, GKGameCenterControllerDelegate ,GKMatchDelegate,GKLocalPlayerListener{ + + static let sharedInstance = GameCenterManager() + + let LOG = OSLog.init(subsystem: "GameCenterManager", category: "GameCenterManager") + + var viewController: UIViewController? + let localPlayer: GKLocalPlayer = GKLocalPlayer.local + var myMatch: GKMatch? + var isMatchStarted = false + var isServer = false + var hostingPlayer: GKPlayer? + var peerPlayer: GKPlayer? + var menusc: MenuScene? + var entityManager = EntityManager.gameEMInstance + var localPlayerRandomNumber: RandomNumber? + var initIsFinish = false + var gameScene: GameScene? + static var isAuthenticated: Bool { + return GKLocalPlayer.local.isAuthenticated + } + + override init() { + super.init() + localPlayer.register(self) + authUser(); + localPlayerRandomNumber = RandomNumber() + } + + func authUser() -> Void { + GKLocalPlayer.local.authenticateHandler = { gcAuthVC, error in + NotificationCenter.default + .post(name: .authenticationChanged, object: GKLocalPlayer.local.isAuthenticated) + if let vc = gcAuthVC { + self.viewController?.present(vc, animated: true) + } + } + } + + func presentMatchmaker() { + let request = GKMatchRequest() + request.minPlayers = 2 + request.maxPlayers = 2 + request.defaultNumberOfPlayers = 2 + request.inviteMessage = "Willst du GoldWars spielen?" + let matchmakerVC = GKMatchmakerViewController.init(matchRequest: request) + matchmakerVC!.matchmakerDelegate = self + viewController?.present(matchmakerVC!, animated: true, completion: nil) + } + + func presentGameCenter() { + let gameCenterController: GKGameCenterViewController = GKGameCenterViewController.init() + gameCenterController.gameCenterDelegate = self + gameCenterController.viewState = .achievements + viewController?.present(gameCenterController, animated: true, completion: nil) + } + + func addAchievementProgress(identifier: String, increasePercentComplete: Double) { + GKAchievement.loadAchievements { (achievements: [GKAchievement]?, err: Error?) in + var achievementExists: Bool = false + achievements?.forEach({ (achievement: GKAchievement) in + print(achievement.identifier) + if achievement.identifier == identifier { + achievementExists = true + achievement.percentComplete += increasePercentComplete + achievement.showsCompletionBanner = true + GKAchievement.report([achievement]) { (error) in + print(error?.localizedDescription ?? "") + } + } + }) + if !achievementExists { + let newAchievement: GKAchievement = GKAchievement.init(identifier: identifier) + newAchievement.showsCompletionBanner = true + newAchievement.percentComplete = increasePercentComplete + GKAchievement.report([newAchievement]) { (error) in + print(error?.localizedDescription ?? "") + } + } + } + } + + func match(_ match: GKMatch, didReceive data: Data, fromRemotePlayer player: GKPlayer) { + if myMatch != match { return } + let jsonDecoder = JSONDecoder() + if let randomNumberFromPeer = try? jsonDecoder.decode(RandomNumber.self, from: data) { + os_log("Random Number des anderen Spielers erhalten", log: LOG, type: .info) + if randomNumberFromPeer.number <= localPlayerRandomNumber!.number { + isServer = true + self.hostingPlayer = GKLocalPlayer.local + self.peerPlayer = player + os_log("Dieser Spieler wurde zum HostingPlayer gewählt", log: LOG, type: .info) + } else { + isServer = false + self.hostingPlayer = player + self.peerPlayer = GKLocalPlayer.local + os_log("Dieser Spieler wurde zum PeerPlayer gewählt", log: LOG, type: .info) + } + os_log("Setzen von Peer und Host abgeschlossen", log: LOG, type: .info) + sendStateToPeers(state: State(state: 0)) + os_log("State 0 wurde an anderen Spieler gesendet", log: LOG, type: .info) + } + if let state = try? jsonDecoder.decode(State.self, from: data) { + switch state.state { + case 0: + os_log("State 0 erhalten", log: LOG, type: .info) + sendStateToPeers(state: State(state: 1)) + case 1: + os_log("State 1 erhalten", log: LOG, type: .info) + + if isServer { + os_log("Peer hat Player initialisiert", log: LOG, type: .info) + initAndSendMap() + }else { + os_log("Host hat Player initialisiert", log: LOG, type: .info) + } + case 2: + os_log("State 2 erhalten", log: LOG, type: .info) + sendStateToPeers(state: State(state: 3)) + initIsFinish = true + os_log("Spiel startet", log: LOG, type: .info) + case 3: + os_log("State 3 erhalten", log: LOG, type: .info) + initIsFinish = true + os_log("Spiel startet", log: LOG, type: .info) + case 4: + os_log("State 4 erhalten, Peer hat verloren", log: LOG, type: .info) + // TODO: Trigger Loser Scene + case 5: + os_log("State 5 erhalten, Peer hat gewonnen", log: LOG, type: .info) + // TODO: Trigger Winner Scene + default: + break + } + } + if let roundData = try? jsonDecoder.decode(LocalRoundData.self, from: data) { + DataService.sharedInstance.addRemotePlayerMoves(playerName: player.displayName, localRoundData: roundData) + } + if let snapshotModel = try? jsonDecoder.decode(SnapshotModel.self, from: data) { + DataService.sharedInstance.snapshotModel = snapshotModel + RoundCalculatorService.sharedInstance.currentRound += 1 + entityManager.getHUD()?.setCurrentRound(round: RoundCalculatorService.sharedInstance.currentRound) + entityManager.updateSnapshotModel(snapshotModel: snapshotModel) + entityManager.getHUD()?.startWithDuration() + } + if let mapModel = try? jsonDecoder.decode(MapGenerationModel.self, from: data) { + os_log("Peer hat Map erhalten", log: LOG, type: .info) + let scene = GameScene(size: self.menusc!.size) + EntityManager.gameEMInstance.setScene(scene: scene) + DataService.sharedInstance.setMapModel(model: mapModel) + os_log("Map model wurde gesetzt", log: LOG, type: .info) + GameCenterManager.sharedInstance.isMatchStarted = true + self.gameScene = scene + sendStateToPeers(state: State(state: 2)) + os_log("State 2 wurde an Host gesendet", log: LOG, type: .info) + initIsFinish = true + os_log("Peer startet Spiel", log: LOG, type: .info) + } + MultiplayerNetwork.sharedInstance.isSending = false + } + + func initAndSendMap() -> Void { + self.gameScene = GameScene(size: self.menusc!.size) + let mapModel = MapFactory(scene: self.gameScene!, entityManager: entityManager).load() + os_log("Map wurde erstellt", log: LOG, type: .info) + MultiplayerNetwork.sharedInstance.sendMapModelToPlayers(mapModel: mapModel) + os_log("Map wurde an Peer gesendet", log: LOG, type: .info) + DataService.sharedInstance.setSnapshotModel(snapshotModel: entityManager.getSnapshotModel()) + os_log("SnapshotModel wurde erstellt", log: LOG, type: .info) + } + + func getGKPlayerByUsername(displayName: String) -> GKPlayer? { + let nilGK : GKPlayer? = nil + + if GKLocalPlayer.local.displayName == displayName { + return GKLocalPlayer.local + } + + for player in myMatch!.players { + if player.displayName == displayName { + return player + } + } + return nilGK + } + func sendStateToPeers(state: State){ + let encoder = JSONEncoder() + let encoded = (try? encoder.encode(state))! + MultiplayerNetwork.sharedInstance.sendData(data: encoded) + } + + func sendRandomNumberToAllPeers(in match: GKMatch){ + let encoder = JSONEncoder() + let encoded = (try? encoder.encode(localPlayerRandomNumber))! + MultiplayerNetwork.sharedInstance.sendData(data: encoded) + } + + func player(_ player: GKPlayer, didAccept invite: GKInvite) { + os_log("Einladung angenommen", log: LOG, type: .info) + let matchmakerVC = GKMatchmakerViewController.init(invite: invite) + matchmakerVC!.matchmakerDelegate = self + viewController?.present(matchmakerVC!, animated: true, completion: nil) + } + func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) { + viewController.dismiss(animated: true, completion: nil) + } + + func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) { + viewController.dismiss(animated: true, completion: nil) + } + + func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) { + viewController.dismiss(animated: true, completion: nil) + myMatch = match + if !isMatchStarted && match.expectedPlayerCount == 0 { + myMatch?.delegate = self + sendRandomNumberToAllPeers(in: self.myMatch!) + os_log("Random Number wurde an den anderen Spieler gesendet", log: LOG, type: .info) + } + } + + func gameCenterViewControllerDidFinish(_ gameCenterViewController: GKGameCenterViewController) { + gameCenterViewController.dismiss(animated: true, completion: nil) + } + + func disconnect() { + if myMatch != nil { + myMatch?.disconnect() + } + } +} + +extension Notification.Name { + static let presentGame = Notification.Name(rawValue: "presentGame") + static let authenticationChanged = Notification.Name(rawValue: "authenticationChanged") +} diff --git a/GoldWars/GoldWars/GameViewController.swift b/GoldWars/GoldWars/GameViewController.swift index 05b2706..a3b45f5 100644 --- a/GoldWars/GoldWars/GameViewController.swift +++ b/GoldWars/GoldWars/GameViewController.swift @@ -14,24 +14,24 @@ class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - + if let view = self.view as! SKView? { let scene = MenuScene(size: self.view.bounds.size) + EntityManager.menuEMInstance.setScene(scene: scene) scene.scaleMode = .aspectFill view.presentScene(scene) //TODO: create dev profile or remove on delivery view.showsFPS = true view.showsNodeCount = true - - GameCenterHelper.helper.viewController = self - MatchmakingHelper.sharedInstance.viewController = self + } + GameCenterManager.sharedInstance.viewController = self + + } - } - override var shouldAutorotate: Bool { return true } - + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { if UIDevice.current.userInterfaceIdiom == .phone { return .allButUpsideDown @@ -39,7 +39,7 @@ class GameViewController: UIViewController { return .all } } - + override var prefersStatusBarHidden: Bool { return true } diff --git a/GoldWars/GoldWars/Map/CElements.swift b/GoldWars/GoldWars/Map/CElements.swift index 22fc4dc..1e158be 100644 --- a/GoldWars/GoldWars/Map/CElements.swift +++ b/GoldWars/GoldWars/Map/CElements.swift @@ -529,16 +529,12 @@ class CElement7: CenterElementProtocol { } func connectInnerBases() { - self.leftBase.adjacencyList.append(self.rightBase) self.leftBase.adjacencyList.append(self.topBase) self.leftBase.adjacencyList.append(self.bottomBase) - self.rightBase.adjacencyList.append(self.leftBase) self.rightBase.adjacencyList.append(self.topBase) self.rightBase.adjacencyList.append(self.bottomBase) self.topBase.adjacencyList.append(self.leftBase) self.topBase.adjacencyList.append(self.rightBase) - self.topBase.adjacencyList.append(self.bottomBase) - self.bottomBase.adjacencyList.append(self.topBase) self.bottomBase.adjacencyList.append(self.rightBase) self.bottomBase.adjacencyList.append(self.leftBase) } @@ -1116,16 +1112,12 @@ class CElement15: CenterElementProtocol { } func connectInnerBases() { - self.leftBase.adjacencyList.append(self.rightBase) self.leftBase.adjacencyList.append(self.topBase) self.leftBase.adjacencyList.append(self.bottomBase) - self.rightBase.adjacencyList.append(self.leftBase) self.rightBase.adjacencyList.append(self.topBase) self.rightBase.adjacencyList.append(self.bottomBase) self.topBase.adjacencyList.append(self.leftBase) self.topBase.adjacencyList.append(self.rightBase) - self.topBase.adjacencyList.append(self.bottomBase) - self.bottomBase.adjacencyList.append(self.topBase) self.bottomBase.adjacencyList.append(self.rightBase) self.bottomBase.adjacencyList.append(self.leftBase) } @@ -1209,16 +1201,12 @@ class CElement16: CenterElementProtocol { } func connectInnerBases() { - self.leftBase.adjacencyList.append(self.rightBase) self.leftBase.adjacencyList.append(self.topBase) self.leftBase.adjacencyList.append(self.bottomBase) - self.rightBase.adjacencyList.append(self.leftBase) self.rightBase.adjacencyList.append(self.topBase) self.rightBase.adjacencyList.append(self.bottomBase) self.topBase.adjacencyList.append(self.leftBase) self.topBase.adjacencyList.append(self.rightBase) - self.topBase.adjacencyList.append(self.bottomBase) - self.bottomBase.adjacencyList.append(self.topBase) self.bottomBase.adjacencyList.append(self.rightBase) self.bottomBase.adjacencyList.append(self.leftBase) } @@ -1302,16 +1290,12 @@ class CElement17: CenterElementProtocol { } func connectInnerBases() { - self.leftBase.adjacencyList.append(self.rightBase) self.leftBase.adjacencyList.append(self.topBase) self.leftBase.adjacencyList.append(self.bottomBase) - self.rightBase.adjacencyList.append(self.leftBase) self.rightBase.adjacencyList.append(self.topBase) self.rightBase.adjacencyList.append(self.bottomBase) self.topBase.adjacencyList.append(self.leftBase) self.topBase.adjacencyList.append(self.rightBase) - self.topBase.adjacencyList.append(self.bottomBase) - self.bottomBase.adjacencyList.append(self.topBase) self.bottomBase.adjacencyList.append(self.rightBase) self.bottomBase.adjacencyList.append(self.leftBase) } diff --git a/GoldWars/GoldWars/Map/MapFactory.swift b/GoldWars/GoldWars/Map/MapFactory.swift index fd7dc3c..9b8da1c 100644 --- a/GoldWars/GoldWars/Map/MapFactory.swift +++ b/GoldWars/GoldWars/Map/MapFactory.swift @@ -1,88 +1,247 @@ // -// MapFactory.swift +// TwoPlayerMapGenerator.swift // GoldWars // -// Created by Marcel Schwarz on 02.05.20. +// Created by Marcel Schwarz on 13.05.20. // Copyright © 2020 SP2. All rights reserved. // import Foundation import SpriteKit +import GameKit import os -protocol MapProtocol { - var size: CGSize! {get set} - var entityManager: EntityManager! {get set} - - init(scene: SKScene, entityManager: EntityManager) - - func load(withModel mapModel: MapGenerationModel) -} - -protocol CenterElementProtocol { - - var bases: [Base] {get set} - var ways: [Way] {get set} - var id: Int { get } - - init(frame: CGRect) - - func getAllBases() -> [Base] - func getInternalWays() -> [Way] - func getTopConnection() -> Base? - func getRightConnection() -> Base? - func getBottomConnection() -> Base? - func getLeftConnection() -> Base? -} - class MapFactory { + let LOG = OSLog.init(subsystem: "MapGenerator", category: "MapFactory") - var twoPlayerMapGenerator: TwoPlayerMapGenerator + var size: CGSize! + var entityManager: EntityManager! - init(scene: SKScene, entityManager: EntityManager) { - self.twoPlayerMapGenerator = TwoPlayerMapGenerator(scene: scene, entityManager: entityManager) + required init(scene: SKScene, entityManager: EntityManager) { + self.size = scene.size + self.entityManager = entityManager } - func loadMap() -> MapGenerationModel{ - let mapModel = TwoPlayerMapGenerator.getNewMapModel() - loadMap(fromModel: mapModel) + func load() -> MapGenerationModel { + let mapModel = MapGenerationModel.new() + load(fromModel: mapModel) return mapModel } - func loadMap(fromModel model: MapGenerationModel) { - os_log("Loading two player map", log: LOG, type: .info) - twoPlayerMapGenerator.load(withModel: model) - } -} - -class CenterElementProvider { - static let LOG = OSLog.init(subsystem: "MapGenerator", category: "CenterElementProvider") - - static let centerElements: [CenterElementProtocol.Type] = [ - CElement0.self, - CElement1.self, - CElement2.self, - CElement3.self, - CElement4.self, - CElement5.self, - CElement6.self, - CElement7.self, - CElement8.self, - CElement9.self, - CElement10.self, - CElement11.self, - CElement12.self, - CElement13.self, - CElement14.self, - CElement15.self, - CElement16.self, - CElement17.self - ] - - static func get(inFrame frame: CGRect, withId id: Int) -> CenterElementProtocol { - os_log("Getting new predifined center element from provider", log: LOG, type: .info) + func load(fromModel mapModel: MapGenerationModel) { + os_log("Loading from TwoPlayerMapFactory", log: LOG, type: .info) - return centerElements[id].init(frame: frame) + // Generate bases structure + os_log("Get player one base", log: LOG, type: .info) + let basePlayerOne = Base( + position: CGPoint(x: self.size.width * 0.07, y: self.size.height / 2), + player: (GameCenterManager.sharedInstance.isServer) ? GKLocalPlayer.local : GameCenterManager.sharedInstance.myMatch?.players[0], + team: .team1 + ) + + os_log("Get player one's startbases", log: LOG, type: .info) + var p1StartBases = [String: Base]() + var ways = [Way]() + + if (mapModel.numBasesP1 == 1) { + p1StartBases["mid"] = Base(position: CGPoint(x: self.size.width * 0.2, y: self.size.height * 0.5)) + ways.append(Way(fromBase: basePlayerOne, toBase: p1StartBases["mid"]!)) + } else if (mapModel.numBasesP1 == 2) { + p1StartBases["top"] = Base(position: CGPoint(x: self.size.width * 0.2, y: self.size.height * 0.333)) + p1StartBases["bot"] = Base(position: CGPoint(x: self.size.width * 0.2, y: self.size.height * 0.666)) + ways.append(Way(fromBase: basePlayerOne, toBase: p1StartBases["top"]!)) + ways.append(Way(fromBase: basePlayerOne, toBase: p1StartBases["bot"]!)) + } else { + p1StartBases["top"] = Base(position: CGPoint(x: self.size.width * 0.2, y: self.size.height * 0.25)) + p1StartBases["mid"] = Base(position: CGPoint(x: self.size.width * 0.2, y: self.size.height * 0.5)) + p1StartBases["bot"] = Base(position: CGPoint(x: self.size.width * 0.2, y: self.size.height * 0.75)) + ways.append(Way(fromBase: basePlayerOne, toBase: p1StartBases["top"]!)) + ways.append(Way(fromBase: basePlayerOne, toBase: p1StartBases["mid"]!)) + ways.append(Way(fromBase: basePlayerOne, toBase: p1StartBases["bot"]!)) + } + + os_log("Generate Map center", log: LOG, type: .info) + let gridCellWidth = self.size.width * 0.2 + let gridCellHeight = self.size.height * 0.4 + let cellInsetX = CGFloat(self.size.width * 0.05) + let cellInsetY = CGFloat(self.size.height * 0.07) + + let gridTopLeft = CGRect( + x: self.size.width * 0.3, + y: self.size.height * 0.1, + width: gridCellWidth, + height: gridCellHeight + ).insetBy(dx: cellInsetX, dy: cellInsetY) + + let gridTopRight = CGRect( + x: self.size.width * 0.5, + y: self.size.height * 0.1, + width: gridCellWidth, + height: gridCellHeight + ).insetBy(dx: cellInsetX, dy: cellInsetY) + + let gridBottomLeft = CGRect( + x: self.size.width * 0.3, + y: self.size.height * 0.5, + width: gridCellWidth, + height: gridCellHeight + ).insetBy(dx: cellInsetX, dy: cellInsetY) + + let gridBottomRight = CGRect( + x: self.size.width * 0.5, + y: self.size.height * 0.5, + width: gridCellWidth, + height: gridCellHeight + ).insetBy(dx: cellInsetX, dy: cellInsetY) + + let topLeft = CenterElementProvider.get(inFrame: gridTopLeft, withId: mapModel.topLeftId) + let topRight = CenterElementProvider.get(inFrame: gridTopRight, withId: mapModel.topRightId) + let bottomLeft = CenterElementProvider.get(inFrame: gridBottomLeft, withId: mapModel.bottomLeftId) + let bottomRight = CenterElementProvider.get(inFrame: gridBottomRight, withId: mapModel.bottomRightId) + + ways.append(contentsOf: topLeft.getInternalWays()) + ways.append(contentsOf: topRight.getInternalWays()) + ways.append(contentsOf: bottomLeft.getInternalWays()) + ways.append(contentsOf: bottomRight.getInternalWays()) + + os_log("Get player two base", log: LOG, type: .info) + let basePlayerTwo = Base( + position: CGPoint(x: self.size.width * 0.93, y: self.size.height / 2), + player: (!GameCenterManager.sharedInstance.isServer) ? GKLocalPlayer.local : GameCenterManager.sharedInstance.myMatch?.players[0], + team: .team2 + ) + + os_log("Get player two's startbases", log: LOG, type: .info) + var p2StartBases = [String: Base]() + + if (mapModel.numBasesP2 == 1) { + p2StartBases["mid"] = Base(position: CGPoint(x: self.size.width * 0.8, y: self.size.height * 0.5)) + ways.append(Way(fromBase: basePlayerTwo, toBase: p2StartBases["mid"]!)) + } else if (mapModel.numBasesP2 == 2) { + p2StartBases["top"] = Base(position: CGPoint(x: self.size.width * 0.8, y: self.size.height * 0.333)) + p2StartBases["bot"] = Base(position: CGPoint(x: self.size.width * 0.8, y: self.size.height * 0.666)) + ways.append(Way(fromBase: basePlayerTwo, toBase: p2StartBases["top"]!)) + ways.append(Way(fromBase: basePlayerTwo, toBase: p2StartBases["bot"]!)) + } else { + p2StartBases["top"] = Base(position: CGPoint(x: self.size.width * 0.8, y: self.size.height * 0.25)) + p2StartBases["mid"] = Base(position: CGPoint(x: self.size.width * 0.8, y: self.size.height * 0.5)) + p2StartBases["bot"] = Base(position: CGPoint(x: self.size.width * 0.8, y: self.size.height * 0.75)) + ways.append(Way(fromBase: basePlayerTwo, toBase: p2StartBases["top"]!)) + ways.append(Way(fromBase: basePlayerTwo, toBase: p2StartBases["mid"]!)) + ways.append(Way(fromBase: basePlayerTwo, toBase: p2StartBases["bot"]!)) + } + + // Create adjacency mapping + os_log("Connecting base p1 and start bases", log: LOG, type: .info) + basePlayerOne.adjacencyList.append(contentsOf: p1StartBases.values) + p1StartBases.values.forEach({base in base.adjacencyList.append(basePlayerOne)}) + + if (p1StartBases["top"] != nil && topLeft.getLeftConnection() != nil) { + os_log("Connecting p1 startbase top with topLeft segment", log: LOG, type: .info) + p1StartBases["top"]!.adjacencyList.append(topLeft.getLeftConnection()!) + topLeft.getLeftConnection()!.adjacencyList.append(p1StartBases["top"]!) + ways.append(Way(fromBase: p1StartBases["top"]!, toBase: topLeft.getLeftConnection()!)) + } + + if (p1StartBases["mid"] != nil) { + if (topLeft.getLeftConnection() != nil) { + os_log("Connecting p1 startbase mid with topLeft segment", log: LOG, type: .info) + p1StartBases["mid"]!.adjacencyList.append(topLeft.getLeftConnection()!) + topLeft.getLeftConnection()!.adjacencyList.append(p1StartBases["mid"]!) + ways.append(Way(fromBase: p1StartBases["mid"]!, toBase: topLeft.getLeftConnection()!)) + } + + if (bottomLeft.getLeftConnection() != nil) { + os_log("Connecting p1 startbase mid with bottomLeft segment", log: LOG, type: .info) + p1StartBases["mid"]!.adjacencyList.append(bottomLeft.getLeftConnection()!) + bottomLeft.getLeftConnection()!.adjacencyList.append(p1StartBases["mid"]!) + ways.append(Way(fromBase: p1StartBases["mid"]!, toBase: bottomLeft.getLeftConnection()!)) + } + } + + if (p1StartBases["bot"] != nil && bottomLeft.getLeftConnection() != nil) { + os_log("Connecting p1 startbase bot with bottomLeft segment", log: LOG, type: .info) + p1StartBases["bot"]!.adjacencyList.append(bottomLeft.getLeftConnection()!) + bottomLeft.getLeftConnection()!.adjacencyList.append(p1StartBases["bot"]!) + ways.append(Way(fromBase: p1StartBases["bot"]!, toBase: bottomLeft.getLeftConnection()!)) + } + + if (topLeft.getRightConnection() != nil && topRight.getLeftConnection() != nil) { + os_log("Connecting topLeft with topRight segment horizontally", log: LOG, type: .info) + topLeft.getRightConnection()!.adjacencyList.append(topRight.getLeftConnection()!) + topRight.getLeftConnection()!.adjacencyList.append(topLeft.getRightConnection()!) + ways.append(Way(fromBase: topLeft.getRightConnection()!, toBase: topRight.getLeftConnection()!)) + } + + if (bottomLeft.getRightConnection() != nil && bottomRight.getLeftConnection() != nil) { + os_log("Connecting bottomLeft with bottomRight segment horizontally", log: LOG, type: .info) + bottomLeft.getRightConnection()!.adjacencyList.append(bottomRight.getLeftConnection()!) + bottomRight.getLeftConnection()!.adjacencyList.append(bottomLeft.getRightConnection()!) + ways.append(Way(fromBase: bottomLeft.getRightConnection()!, toBase: bottomRight.getLeftConnection()!)) + } + + if (topLeft.getBottomConnection() != nil && bottomLeft.getTopConnection() != nil) { + os_log("Connecting topLeft with bottomLeft segment vertically", log: LOG, type: .info) + topLeft.getBottomConnection()!.adjacencyList.append(bottomLeft.getTopConnection()!) + bottomLeft.getTopConnection()!.adjacencyList.append(topLeft.getBottomConnection()!) + ways.append(Way(fromBase: topLeft.getBottomConnection()!, toBase: bottomLeft.getTopConnection()!)) + } + + if (topRight.getBottomConnection() != nil && bottomRight.getTopConnection() != nil) { + os_log("Connecting topRight with bottomRight segment vertically", log: LOG, type: .info) + topRight.getBottomConnection()!.adjacencyList.append(bottomRight.getTopConnection()!) + bottomRight.getTopConnection()!.adjacencyList.append(topRight.getBottomConnection()!) + ways.append(Way(fromBase: topRight.getBottomConnection()!, toBase: bottomRight.getTopConnection()!)) + } + + os_log("Connecting base p2 and start bases", log: LOG, type: .info) + basePlayerTwo.adjacencyList.append(contentsOf: p2StartBases.values) + p2StartBases.values.forEach({base in base.adjacencyList.append(basePlayerTwo)}) + + if (p2StartBases["top"] != nil && topRight.getRightConnection() != nil) { + os_log("Connecting p2 startbase top with topRight segment", log: LOG, type: .info) + p2StartBases["top"]!.adjacencyList.append(topRight.getRightConnection()!) + topRight.getRightConnection()!.adjacencyList.append(p2StartBases["top"]!) + ways.append(Way(fromBase: p2StartBases["top"]!, toBase: topRight.getRightConnection()!)) + } + + if (p2StartBases["mid"] != nil) { + if (topRight.getRightConnection() != nil) { + os_log("Connecting p2 startbase mid with topRight segment", log: LOG, type: .info) + p2StartBases["mid"]!.adjacencyList.append(topRight.getRightConnection()!) + topRight.getRightConnection()!.adjacencyList.append(p2StartBases["mid"]!) + ways.append(Way(fromBase: topRight.getRightConnection()!, toBase: p2StartBases["mid"]!)) + } + + if (bottomRight.getRightConnection() != nil) { + os_log("Connecting p2 startbase mid with bottomRight segment", log: LOG, type: .info) + p2StartBases["mid"]!.adjacencyList.append(bottomRight.getRightConnection()!) + bottomRight.getRightConnection()!.adjacencyList.append(p2StartBases["mid"]!) + ways.append(Way(fromBase: p2StartBases["mid"]!, toBase: bottomRight.getRightConnection()!)) + } + } + + if (p2StartBases["bot"] != nil && bottomRight.getRightConnection() != nil) { + os_log("Connecting p2 startbase bot with bottomRight segment", log: LOG, type: .info) + p2StartBases["bot"]!.adjacencyList.append(bottomRight.getRightConnection()!) + bottomRight.getRightConnection()!.adjacencyList.append(p2StartBases["bot"]!) + ways.append(Way(fromBase: p2StartBases["bot"]!, toBase: bottomRight.getRightConnection()!)) + } + + + // Add all bases to the scene + entityManager.add(basePlayerOne) + p1StartBases.forEach({(key, base) in entityManager.add(base)}) + + topLeft.getAllBases().forEach({base in entityManager.add(base)}) + topRight.getAllBases().forEach({base in entityManager.add(base)}) + bottomLeft.getAllBases().forEach({base in entityManager.add(base)}) + bottomRight.getAllBases().forEach({base in entityManager.add(base)}) + + entityManager.add(basePlayerTwo) + p2StartBases.forEach({(key, base) in entityManager.add(base)}) + + ways.forEach({way in entityManager.add(way)}) } } diff --git a/GoldWars/GoldWars/Map/MapUtils.swift b/GoldWars/GoldWars/Map/MapUtils.swift new file mode 100644 index 0000000..732c93a --- /dev/null +++ b/GoldWars/GoldWars/Map/MapUtils.swift @@ -0,0 +1,81 @@ +// +// MapUtils.swift +// GoldWars +// +// Created by Marcel Schwarz on 29.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import GameKit +import os + +protocol CenterElementProtocol { + + var bases: [Base] {get set} + var ways: [Way] {get set} + var id: Int { get } + + init(frame: CGRect) + + func getAllBases() -> [Base] + func getInternalWays() -> [Way] + func getTopConnection() -> Base? + func getRightConnection() -> Base? + func getBottomConnection() -> Base? + func getLeftConnection() -> Base? +} + +struct MapGenerationModel: Codable { + + let numBasesP1: Int + let numBasesP2: Int + let topLeftId: Int + let topRightId: Int + let bottomLeftId: Int + let bottomRightId: Int + + static func new() -> MapGenerationModel { + let noOfCElements = CenterElementProvider.centerElements.count - 1 + + return MapGenerationModel( + numBasesP1: Int.random(in: 1...3), + numBasesP2: Int.random(in: 1...3), + topLeftId: Int.random(in: 0...noOfCElements), + topRightId: Int.random(in: 0...noOfCElements), + bottomLeftId: Int.random(in: 0...noOfCElements), + bottomRightId: Int.random(in: 0...noOfCElements) + ) + } + +} + +class CenterElementProvider { + static let LOG = OSLog.init(subsystem: "MapGenerator", category: "CenterElementProvider") + + static let centerElements: [CenterElementProtocol.Type] = [ + CElement0.self, + CElement1.self, + CElement2.self, + CElement3.self, + CElement4.self, + CElement5.self, + CElement6.self, + CElement7.self, + CElement8.self, + CElement9.self, + CElement10.self, + CElement11.self, + CElement12.self, + CElement13.self, + CElement14.self, + CElement15.self, + CElement16.self, + CElement17.self + ] + + static func get(inFrame frame: CGRect, withId id: Int) -> CenterElementProtocol { + os_log("Getting new predifined center element from provider", log: LOG, type: .info) + + return centerElements[id].init(frame: frame) + } +} diff --git a/GoldWars/GoldWars/MultiplayerNetwork.swift b/GoldWars/GoldWars/MultiplayerNetwork.swift index 5cf2937..aaac30d 100644 --- a/GoldWars/GoldWars/MultiplayerNetwork.swift +++ b/GoldWars/GoldWars/MultiplayerNetwork.swift @@ -11,48 +11,42 @@ import Foundation import GameKit class MultiplayerNetwork{ - static let sharedInstance = MultiplayerNetwork() + static let sharedInstance = MultiplayerNetwork() var isSending = false func sendData(data: Data) { - let mmHelper = MatchmakingHelper.sharedInstance - if let multiplayerMatch = mmHelper.mpMatch { + let mmHelper = GameCenterManager.sharedInstance + if let multiplayerMatch = mmHelper.myMatch { do { try multiplayerMatch.sendData(toAllPlayers: data, with: .reliable) } catch { - //TODO: Add logging } } } func sendDataToHost(data: Data) { - let mmHelper = MatchmakingHelper.sharedInstance - let hostGKPlayer = MatchmakingHelper.sharedInstance.mpMatch?.players.filter{ $0.displayName == DataService.sharedInstance.gameHost!.playerName}[0] - if let multiplayerMatch = mmHelper.mpMatch{ + if let multiplayerMatch = GameCenterManager.sharedInstance.myMatch{ do { - try multiplayerMatch.send(data, to: [hostGKPlayer!], dataMode: .reliable) + try multiplayerMatch.send(data, to: [GameCenterManager.sharedInstance.hostingPlayer!], dataMode: .reliable) } catch { //TODO: Add logging } } } - - func sendPlayerMoves(playerMoves: [PlayerMove]) { - if MatchmakingHelper.sharedInstance.isServer == false { + + func sendPlayerMoves(localRoundData: LocalRoundData) { + if GameCenterManager.sharedInstance.isServer == false { + print("I am client") self.isSending = true let encoder = JSONEncoder() - let encoded = (try? encoder.encode(playerMoves))! + let encoded = (try? encoder.encode(localRoundData))! sendDataToHost(data: encoded) - DataService.sharedInstance.localPlayerMoves.removeAll() + DataService.sharedInstance.localRoundData.localPlayerMoves.removeAll() + DataService.sharedInstance.localRoundData.hasAttackBoost = false + DataService.sharedInstance.localRoundData.hasDefenceBoost = false } - } - - func sendHostIdentifier() { - let encoder = JSONEncoder() - let encoded = (try? encoder.encode(DataService.sharedInstance.gameHost))! - sendData(data: encoded) } func sendSnapshotModelToPlayers() { @@ -66,5 +60,5 @@ class MultiplayerNetwork{ let encoded = (try? encoder.encode(mapModel))! sendData(data: encoded) } - + } diff --git a/GoldWars/GoldWars/Partikels/Explosion.sks b/GoldWars/GoldWars/Partikels/Explosion.sks new file mode 100644 index 0000000..179dbe7 Binary files /dev/null and b/GoldWars/GoldWars/Partikels/Explosion.sks differ diff --git a/GoldWars/GoldWars/RoundCalculatorService.swift b/GoldWars/GoldWars/RoundCalculatorService.swift index b9186c6..95f0c72 100644 --- a/GoldWars/GoldWars/RoundCalculatorService.swift +++ b/GoldWars/GoldWars/RoundCalculatorService.swift @@ -10,34 +10,31 @@ import GameKit import os class RoundCalculatorService { + var entityManager = EntityManager.gameEMInstance static let sharedInstance = RoundCalculatorService() static let LOG = OSLog.init(subsystem: "Round Calculator", category: "RoundCalculatorService") var allPlayerMoves: [String: [PlayerMove]] = [:] - var baseSpecificMoves: [Int: [String: [PlayerMove]]] = [:] + // TODO: Better data structure + var boosts: [String: (Bool, Bool)] = [:] // First bool is atk boost, second is def boost + let ATK_BOOST_MULTIPLICATOR = 1.1 + let DEF_BOOST_MULTIPLICATOR = 1.1 + let MAX_ROUNDS = 20 + var currentRound = 1 var isCalculating = false + var numberOfAttacks = 0 + var numberOfOwnUnitMoves = 0 func calculateRound() { os_log("Started calculating Round", log: RoundCalculatorService.LOG, type: .info) isCalculating = true let currentSnapshotModel = DataService.sharedInstance.snapshotModel - for playerMove in DataService.sharedInstance.remotePlayerMoves { - addPlayerMove(playerName: playerMove.key, playerMoves: playerMove.value) - } - addPlayerMove(playerName: GKLocalPlayer.local.displayName, playerMoves: DataService.sharedInstance.localPlayerMoves) - - for playerMove in allPlayerMoves { - for move in playerMove.value { - mapPlayerMoveToAttackedBase(playerName: playerMove.key, playerMove: move) - } - } + var baseSpecificMoves = collectBaseSpecificMoves() // TODO: Refactor to a less complex way - for (key, value) in baseSpecificMoves { - let baseId = key - var playerMovesByBase = value + for (baseId, playerMovesByBase) in baseSpecificMoves { let targetBase = currentSnapshotModel?.baseEntites.filter { $0.baseId == baseId }[0] let possiblyOwnershipMoves = playerMovesByBase.filter { $0.key == targetBase?.ownership} @@ -52,10 +49,10 @@ class RoundCalculatorService { } } } - playerMovesByBase.removeValue(forKey: playerName) + baseSpecificMoves[baseId]!.removeValue(forKey: playerName) } - - for (_, playerMoves) in playerMovesByBase { + + for playerMoves in baseSpecificMoves[baseId]!.values { for playerMove in playerMoves { for base in currentSnapshotModel!.baseEntites { if base.baseId == playerMove.fromBase { @@ -64,21 +61,42 @@ class RoundCalculatorService { } } } - + } + + for (baseId, playerMovesByBase) in baseSpecificMoves { var combinePotentionalForces: [String: PlayerMove] = [:] for playerMoves in playerMovesByBase { - combinePotentionalForces[playerMoves.key] = PlayerMove(fromBase: playerMoves.value[0].fromBase, toBase: playerMoves.value[0].toBase, unitCount: 0) + combinePotentionalForces[playerMoves.key] = PlayerMove( + fromBase: playerMoves.value[0].fromBase, + toBase: playerMoves.value[0].toBase, + unitCount: 0 + ) for move in playerMoves.value { combinePotentionalForces[playerMoves.key]!.unitCount += move.unitCount } } - if(combinePotentionalForces.count > 0) { + + if combinePotentionalForces.count > 0 { let sortedPotentionalCombinedForces = combinePotentionalForces.sorted { $0.1.unitCount > $1.1.unitCount } var playerMoveWithMaxUnits = sortedPotentionalCombinedForces[0] + if playerMovesByBase.count >= 2 { - let playerMoveWithSecMaxUnits = sortedPotentionalCombinedForces[1] + var playerMoveWithSecMaxUnits = sortedPotentionalCombinedForces[1] + if boosts[playerMoveWithMaxUnits.key]!.0 { + playerMoveWithMaxUnits.value.unitCount = Int(Double(playerMoveWithMaxUnits.value.unitCount) * ATK_BOOST_MULTIPLICATOR) + } + if boosts[playerMoveWithSecMaxUnits.key]!.0 { + playerMoveWithSecMaxUnits.value.unitCount = Int(Double(playerMoveWithSecMaxUnits.value.unitCount) * ATK_BOOST_MULTIPLICATOR) + } + + if playerMoveWithMaxUnits.value.unitCount < playerMoveWithSecMaxUnits.value.unitCount { + let temp = playerMoveWithMaxUnits + playerMoveWithMaxUnits = playerMoveWithSecMaxUnits + playerMoveWithSecMaxUnits = temp + } + playerMoveWithMaxUnits.value.unitCount -= playerMoveWithSecMaxUnits.value.unitCount } @@ -86,17 +104,17 @@ class RoundCalculatorService { if base.baseId == playerMoveWithMaxUnits.value.toBase { if base.ownership == nil { base.unitCount += playerMoveWithMaxUnits.value.unitCount - if playerMoveWithMaxUnits.value.unitCount == 0 { - base.ownership = nil - } else { - base.ownership = playerMoveWithMaxUnits.key - } + base.ownership = playerMoveWithMaxUnits.value.unitCount == 0 ? nil : playerMoveWithMaxUnits.key } else { + if boosts[base.ownership!]!.1 { + base.unitCount = Int(Double(base.unitCount) * DEF_BOOST_MULTIPLICATOR) + } if base.unitCount < playerMoveWithMaxUnits.value.unitCount { base.unitCount = playerMoveWithMaxUnits.value.unitCount - base.unitCount base.ownership = playerMoveWithMaxUnits.key } else if (base.unitCount == playerMoveWithMaxUnits.value.unitCount) { base.ownership = nil + base.unitCount = 0 } else { base.unitCount -= playerMoveWithMaxUnits.value.unitCount } @@ -106,34 +124,131 @@ class RoundCalculatorService { } baseSpecificMoves.removeValue(forKey: baseId) } + var player1BaseCount = 0; + var player2BaseCount = 0; + let player1 = GameCenterManager.sharedInstance.hostingPlayer?.displayName + let player2 = GameCenterManager.sharedInstance.peerPlayer?.displayName + for baseEntry in currentSnapshotModel!.baseEntites { + if baseEntry.ownership == player1 { + player1BaseCount += 1 + } else if baseEntry.ownership == player2 { + player2BaseCount += 1 + } + } + currentSnapshotModel?.baseEntites = currentSnapshotModel!.baseEntites.map { (BaseEntityModel) -> BaseEntityModel in + if BaseEntityModel.ownership == player1 { + BaseEntityModel.unitCount += player1BaseCount + } else if BaseEntityModel.ownership == player2 { + BaseEntityModel.unitCount += player2BaseCount + } + return BaseEntityModel + } allPlayerMoves.removeAll() - DataService.sharedInstance.localPlayerMoves.removeAll() + DataService.sharedInstance.localRoundData.localPlayerMoves.removeAll() + DataService.sharedInstance.localRoundData.hasAttackBoost = false + DataService.sharedInstance.localRoundData.hasDefenceBoost = false + + if isGameOver() { + let winner: String? + if MAX_ROUNDS == currentRound { + os_log("Game is over by rounds", log: RoundCalculatorService.LOG, type: .info) + winner = determineWinner(by: "rounds") + } else { + os_log("Game is over by capture", log: RoundCalculatorService.LOG, type: .info) + winner = determineWinner(by: "capture") + } + winner == GameCenterManager.sharedInstance.hostingPlayer?.displayName ? GameCenterManager.sharedInstance.sendStateToPeers(state: State(state: 4)) : GameCenterManager.sharedInstance.sendStateToPeers(state: State(state: 5)) + //TODO: Trigger Winner/Loser-Scene for Server + return + } + currentRound += 1 + entityManager.getHUD()?.setCurrentRound(round: currentRound) + MultiplayerNetwork.sharedInstance.sendSnapshotModelToPlayers() DataService.sharedInstance.snapshotModel = currentSnapshotModel - EntityManager.sharedInstance.updateSnapshotModel(snapshotModel: currentSnapshotModel!) - sleep(1) - EntityManager.sharedInstance.getTimer().startWithDuration(duration: 31) + entityManager.updateSnapshotModel(snapshotModel: currentSnapshotModel!) + entityManager.getHUD()?.startWithDuration() os_log("Finished calculating Round", log: RoundCalculatorService.LOG, type: .info) } - func addPlayerMove(playerName: String, playerMoves: [PlayerMove]) { - self.allPlayerMoves[playerName] = playerMoves - } - - func mapPlayerMoveToAttackedBase(playerName: String, playerMove: PlayerMove) { - if self.baseSpecificMoves.keys.contains(playerMove.toBase) { - if (self.baseSpecificMoves[playerMove.toBase]?.keys.contains(playerName))!{ - self.baseSpecificMoves[playerMove.toBase]?[playerName]?.append(playerMove) - } else { - self.baseSpecificMoves[playerMove.toBase]?.merge([playerName: [playerMove]]){(current, _) in current} - } - } else { - self.baseSpecificMoves[playerMove.toBase] = [playerName: [playerMove]] + func collectBaseSpecificMoves() -> [Int: [String: [PlayerMove]]] { + for playerMove in DataService.sharedInstance.remotePlayerMoves { + allPlayerMoves[playerMove.key] = playerMove.value.localPlayerMoves } + + boosts[GameCenterManager.sharedInstance.hostingPlayer!.displayName] = ( + DataService.sharedInstance.localRoundData.hasAttackBoost, + DataService.sharedInstance.localRoundData.hasDefenceBoost + ) + boosts[GameCenterManager.sharedInstance.peerPlayer!.displayName] = ( + DataService.sharedInstance.remotePlayerMoves[GameCenterManager.sharedInstance.peerPlayer!.displayName]?.hasAttackBoost ?? false, + DataService.sharedInstance.remotePlayerMoves[GameCenterManager.sharedInstance.peerPlayer!.displayName]?.hasDefenceBoost ?? false + ) + + allPlayerMoves[GKLocalPlayer.local.displayName] = DataService.sharedInstance.localRoundData.localPlayerMoves + + var baseSpecificMoves: [Int: [String: [PlayerMove]]] = [:] + + for playerMove in allPlayerMoves { + for move in playerMove.value { + if baseSpecificMoves.keys.contains(move.toBase) { + if (baseSpecificMoves[move.toBase]?.keys.contains(playerMove.key))! { + baseSpecificMoves[move.toBase]?[playerMove.key]?.append(move) + } else { + baseSpecificMoves[move.toBase]?.merge([playerMove.key: [move]]){(current, _) in current} + } + } else { + baseSpecificMoves[move.toBase] = [playerMove.key: [move]] + } + } + } + DataService.sharedInstance.remotePlayerMoves.removeAll() + return baseSpecificMoves } func resolvePlayerMove(playerMove: PlayerMove, unitCount: Int, ownership: String?, resolveType: String) { //TODO: outsource playermoves } + func resetNumberOfAttacksAndFormats() { + self.numberOfAttacks = 0; + self.numberOfOwnUnitMoves = 0; + } + + func increaseMoveCounter(ownBase: Bool!) { + if ownBase { + self.numberOfOwnUnitMoves += 1 + } else { + self.numberOfAttacks += 1 + } + } + + func isGameOver() -> Bool { + let remoteplayerBasesCount = entityManager.getBasesByPlayer(for: GameCenterManager.sharedInstance.peerPlayer!).count + let localplayerBasesCount = entityManager.getBasesByPlayer(for: GameCenterManager.sharedInstance.hostingPlayer!).count + let onePlayerLoseAllBases = remoteplayerBasesCount == 0 || localplayerBasesCount == 0 + let reachMaxRounds = MAX_ROUNDS == currentRound + return onePlayerLoseAllBases || reachMaxRounds + } + + func determineWinner(by criteria: String) -> String { + var winner: String? + switch criteria { + case "rounds": + let peerPlayerBasesCount = entityManager.getBasesByPlayer(for: GameCenterManager.sharedInstance.peerPlayer!).count + let hostingPlayerBasesCount = entityManager.getBasesByPlayer(for: GameCenterManager.sharedInstance.hostingPlayer!).count + if peerPlayerBasesCount == hostingPlayerBasesCount { + let hostingPlayerUnitCount = entityManager.getUnitSum(by: GameCenterManager.sharedInstance.hostingPlayer!) + let peerPlayerUnitCount = entityManager.getUnitSum(by: GameCenterManager.sharedInstance.peerPlayer!) + winner = hostingPlayerUnitCount > peerPlayerUnitCount ? GameCenterManager.sharedInstance.hostingPlayer?.displayName : GameCenterManager.sharedInstance.peerPlayer?.displayName + } else { + winner = hostingPlayerBasesCount > peerPlayerBasesCount ? GameCenterManager.sharedInstance.hostingPlayer?.displayName : GameCenterManager.sharedInstance.peerPlayer?.displayName + } + case "capture": + winner = entityManager.getBasesByPlayer(for: GameCenterManager.sharedInstance.hostingPlayer!).count == 0 ? GameCenterManager.sharedInstance.peerPlayer?.displayName : GameCenterManager.sharedInstance.hostingPlayer?.displayName + default: + break + } + return winner! + } } diff --git a/GoldWars/GoldWars/RoundTimer.swift b/GoldWars/GoldWars/RoundTimer.swift new file mode 100644 index 0000000..8f27a60 --- /dev/null +++ b/GoldWars/GoldWars/RoundTimer.swift @@ -0,0 +1,55 @@ +// +// RoundTimer.swift +// GoldWars +// +// Created by Jakob Haag on 28.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import Foundation + +class RoundTimer: Timer { + + var timer: Timer? + var timeLeft: Int = 0 + var calculate = false + var roundEnded = "Syncing" + + func initTimer() { + timer = Timer.scheduledTimer( + timeInterval: 1.0, + target: self, + selector: #selector(onTimerFires), + userInfo: nil, + repeats: true + ) + } + + func startTimer() { + timeLeft = 30 + } + + @objc func onTimerFires() + { + timeLeft -= 1 + + EntityManager.gameEMInstance.updateTime(time: (timeLeft > 0 ? String(timeLeft) : roundEnded)) + + if timeLeft == 0 { + RoundCalculatorService.sharedInstance.resetNumberOfAttacksAndFormats() + if !MultiplayerNetwork.sharedInstance.isSending { + MultiplayerNetwork.sharedInstance.sendPlayerMoves(localRoundData: DataService.sharedInstance.localRoundData) + } + calculate = true + } + if timeLeft <= 0 { + if calculate + && !RoundCalculatorService.sharedInstance.isCalculating + && DataService.sharedInstance.didReceiveAllData() + && GameCenterManager.sharedInstance.isServer { + RoundCalculatorService.sharedInstance.calculateRound() + calculate = false + } + } + } +} diff --git a/GoldWars/GoldWars/Scenes/GameScene.swift b/GoldWars/GoldWars/Scenes/GameScene.swift index 7618d1a..d8ad5bb 100644 --- a/GoldWars/GoldWars/Scenes/GameScene.swift +++ b/GoldWars/GoldWars/Scenes/GameScene.swift @@ -12,26 +12,20 @@ import GameKit class GameScene: SKScene{ + var entityManager = EntityManager.gameEMInstance + var isMoveTouch = false var currentDraggedBase : Base? static var sendUnits: CGFloat = 0 var collisionBase: Base? override func sceneDidLoad() { - EntityManager.sharedInstance.setScene(scene: self) - EntityManager.sharedInstance.add(HUD(size: self.size)) - EntityManager.sharedInstance.add(Background(size: self.size)) - initMap() - } - - func initMap() { - if (DataService.sharedInstance.gameHost?.playerName == GKLocalPlayer.local.displayName) { - let mapModel = MapFactory(scene: self, entityManager: EntityManager.sharedInstance).loadMap() - MultiplayerNetwork.sharedInstance.sendMapModelToPlayers(mapModel: mapModel) - DataService.sharedInstance.setSnapshotModel(snapshotModel: EntityManager.sharedInstance.getSnapshotModel()) - } + entityManager.setScene(scene: self) + entityManager.add(HUD(size: self.size)) + entityManager.add(Background(size: self.size)) if CommandLine.arguments.contains("--no-matchmaking") { - MapFactory(scene: self, entityManager: EntityManager.sharedInstance).loadMap() + _ = MapFactory(scene: self, entityManager: entityManager).load() + return } } @@ -42,22 +36,23 @@ class GameScene: SKScene{ let touchLocation = touch.location(in: self) - if isMoveTouch{ + if isMoveTouch { isMoveTouch = false - currentDraggedBase!.component(ofType: DefaultBaseComponent.self)?.spriteNode.position = currentDraggedBase!.position - currentDraggedBase!.component(ofType: TeamComponent.self)?.fire.position = currentDraggedBase!.position - currentDraggedBase!.component(ofType: DefaultBaseComponent.self)?.labelNode?.position = CGPoint(x: currentDraggedBase!.position.x + 30, y: currentDraggedBase!.position.y - 50) + moveFireAndBase(base: currentDraggedBase!, touchLocation: currentDraggedBase!.position) + addAttackDetails(touchLocation: touchLocation) + + entityManager.getBasesByPlayer(for: GKLocalPlayer.local).forEach({base in + moveFireAndBase(base: base, touchLocation: base.position) + }) } else { - for entity in EntityManager.sharedInstance.entities { + for entity in entityManager.entities { let spriteNode = entity.component(ofType: DefaultBaseComponent.self)?.spriteNode - //FIXME: this is confusing addBaseDetails(touchLocation: touchLocation, spriteNode: spriteNode, touches: touches, event: event, entity: entity) } } - } override func touchesMoved(_ touches: Set, with event: UIEvent?) { @@ -72,33 +67,24 @@ class GameScene: SKScene{ } } checkSlider() - - let bases = EntityManager.sharedInstance.getBasesByPlayer(for: GKLocalPlayer.local) - + let bases = entityManager.getBasesByPlayer(for: GKLocalPlayer.local) checkBases(bases: bases, touchLocation: touchLocation) } override func update(_ currentTime: TimeInterval) { - EntityManager.sharedInstance.getBackground()?.update(deltaTime: currentTime) - EntityManager.sharedInstance.getHUD()?.component(ofType: TimerComponent.self)?.update() + entityManager.getBackground()?.update(deltaTime: currentTime) } func addBaseDetails(touchLocation: CGPoint, spriteNode: SKNode?, touches: Set, event: UIEvent?, entity: GKEntity){ - if atPoint(touchLocation) == spriteNode && !EntityManager.sharedInstance.isModal { + if atPoint(touchLocation) == spriteNode && !entityManager.isModal { spriteNode?.touchesBegan(touches, with: event) if let baseEntity = entity as? Base { if baseEntity.ownershipPlayer == GKLocalPlayer.local { - for child in self.children { - if(child.name != "fire"){ - child.alpha = 0.3 - } - } - EntityManager.sharedInstance.add(Modal(modaltype: .BaseDetails, - base: entity as! Base, - anchorPoint: CGPoint(x: self.size.width / 2 , y: self.size.height / 2), - gameScene: self, - currentDraggedBase: currentDraggedBase, touchLocation: touchLocation, collisionBase: collisionBase)) - + entityManager.add(Modal(modaltype: .BaseDetails, + base: entity as! Base, + anchorPoint: CGPoint(x: self.size.width / 2 , y: self.size.height / 2), + gameScene: self, + currentDraggedBase: currentDraggedBase, touchLocation: touchLocation, collisionBase: collisionBase)) } } } @@ -110,10 +96,18 @@ class GameScene: SKScene{ collisionBase = base // TODO: change interaction based on collision instead of touchlocation if currentDraggedBase!.unitCount > 1 { - EntityManager.sharedInstance.add(Modal(modaltype: .BaseAttack, - base: currentDraggedBase!, - anchorPoint: CGPoint(x: self.size.width / 2 , y: self.size.height / 2), - gameScene: self, currentDraggedBase: currentDraggedBase, touchLocation: touchLocation, collisionBase: collisionBase)) + if !checkIfMoveIsAble() { + return + } + let modaltype = setModalType() + entityManager.add(Modal(modaltype: modaltype, + base: currentDraggedBase!, + anchorPoint: CGPoint(x: self.size.width / 2 , y: self.size.height / 2), + gameScene: self, + currentDraggedBase: currentDraggedBase, + touchLocation: touchLocation, + collisionBase: collisionBase) + ) GameScene.sendUnits = CGFloat(currentDraggedBase!.unitCount / 2) } } @@ -121,8 +115,8 @@ class GameScene: SKScene{ } func checkSlider(){ - for e in EntityManager.sharedInstance.entities{ - if let body = e.component(ofType: ModalContentComponent.self)?.body{ + for e in entityManager.entities{ + if let modal = e as? Modal { GameScene.sendUnits = ((e.component(ofType: SliderComponent.self)?.sliderNode.getValue ?? 0) * CGFloat((e as! Modal).unitCount)).rounded(.up) //TODO: refactor this quick and dirty fix @@ -131,20 +125,22 @@ class GameScene: SKScene{ } else if Int(GameScene.sendUnits) == currentDraggedBase?.unitCount { GameScene.sendUnits -= 1 } - body.text = "Schicke \(GameScene.sendUnits) Einheiten " + modal.body.text = "Schicke \(GameScene.sendUnits) Einheiten " } } } func checkBases(bases: Set, touchLocation: CGPoint){ for base in bases { - if atPoint(touchLocation) == base.component(ofType: DefaultBaseComponent.self)?.spriteNode{ - if !isMoveTouch { - currentDraggedBase = base + if atPoint(touchLocation) == base.component(ofType: DefaultBaseComponent.self)?.spriteNode { + if !base.changeOwnership { + if !isMoveTouch { + currentDraggedBase = base + } + isMoveTouch = true + moveFireAndBase(base: base, touchLocation: touchLocation) + showNearestBases(base: base) } - isMoveTouch = true - moveFireAndBase(base: base, touchLocation: touchLocation) - showNearestBases(base: base) } } } @@ -152,7 +148,7 @@ class GameScene: SKScene{ func moveFireAndBase(base: Base, touchLocation: CGPoint){ base.component(ofType: DefaultBaseComponent.self)?.spriteNode.position = touchLocation base.component(ofType: TeamComponent.self)?.fire.position = touchLocation - base.component(ofType: DefaultBaseComponent.self)?.labelNode?.position = CGPoint(x:touchLocation.x + 30, y: touchLocation.y - 50) + base.component(ofType: DefaultBaseComponent.self)?.labelNode.position = CGPoint(x:touchLocation.x + 30, y: touchLocation.y - 50) } func showNearestBases(base: Base){ @@ -164,4 +160,24 @@ class GameScene: SKScene{ ])) } } + + func checkIfMoveIsAble() -> Bool{ + if isAttackMove() { + return RoundCalculatorService.sharedInstance.numberOfAttacks < 2 + } else { + return RoundCalculatorService.sharedInstance.numberOfOwnUnitMoves < 5 + } + } + + func setModalType() -> ModalType { + if isAttackMove() { + return .BaseAttack + } else { + return .BaseMoveOwnUnits + } + } + + func isAttackMove() -> Bool { + return collisionBase?.ownershipPlayer != currentDraggedBase?.ownershipPlayer + } } diff --git a/GoldWars/GoldWars/Scenes/MenuScene.swift b/GoldWars/GoldWars/Scenes/MenuScene.swift index 764a1da..82469a3 100644 --- a/GoldWars/GoldWars/Scenes/MenuScene.swift +++ b/GoldWars/GoldWars/Scenes/MenuScene.swift @@ -9,13 +9,16 @@ import SpriteKit import SceneKit class MenuScene: SKScene { - + + var entityManager = EntityManager.menuEMInstance + override func sceneDidLoad() { - EntityManager.sharedInstance.setScene(scene: self) + GameCenterManager.sharedInstance.menusc = self + entityManager.setScene(scene: self) let midX = self.size.width / 2 let midY = self.size.height / 2 - EntityManager.sharedInstance.add(Button(name: "startGameButton", - iconName: "", + entityManager.add(Button(name: "startGameButton", + textureName: "yellow_button04", text: "Start Game", position: CGPoint(x: midX, y: midY), onButtonPress: { @@ -23,18 +26,35 @@ class MenuScene: SKScene { self.loadScene(scene: GameScene(size: self.size)) SoundManager.sharedInstance.stopMenuMusic() } else { - MatchmakingHelper.sharedInstance.presentMatchmaker(scene: self) + + if GameCenterManager.isAuthenticated { + GameCenterManager.sharedInstance.presentMatchmaker() + }else { + GameCenterManager.sharedInstance.authUser() + } } })) - EntityManager.sharedInstance.add(Button(name: "settingsButton", - iconName: "", + entityManager.add(Button(name: "settingsButton", + textureName: "yellow_button04", text: "Settings", position: CGPoint(x: midX, y: midY - 80 ), onButtonPress: { - self.loadScene(scene: SettingsScene(size: self.size)) + let scene = SettingsScene(size: self.size) + self.loadScene(scene: scene) })) - EntityManager.sharedInstance.add(Background(size: self.size)) - EntityManager.sharedInstance.add(SpinningLogoEntity(position: CGPoint(x: midX, y: midY + 200))) + entityManager.add(Button(name: "gameCenterButton", + textureName: "yellow_button04", + text: "GameCenter", + position: CGPoint(x: midX, y: midY - 160), + onButtonPress: { + if GameCenterManager.isAuthenticated { + GameCenterManager.sharedInstance.presentGameCenter() + }else { + GameCenterManager.sharedInstance.authUser() + } + })) + entityManager.add(Background(size: self.size)) + entityManager.add(SpinningLogoEntity(position: CGPoint(x: midX, y: midY + 200))) if SoundManager.sharedInstance.isMusicPlaying == false && SoundManager.sharedInstance.isMusicEnabled == true { SoundManager.sharedInstance.startMenuMusic() @@ -43,11 +63,19 @@ class MenuScene: SKScene { func loadScene(scene: SKScene) { let transition = SKTransition.flipVertical(withDuration: 0.5) + entityManager.entities.removeAll() self.view?.presentScene(scene, transition: transition) } override func update(_ currentTime: TimeInterval) { - EntityManager.sharedInstance.getBackground()!.update(deltaTime: currentTime) - EntityManager.sharedInstance.getButtonByName(buttonName: "startGameButton").component(ofType: ButtonComponent.self)?.buttonNode.isEnabled = GameCenterHelper.isAuthenticated + if entityManager.entities.count != 0 { + entityManager.getBackground()!.update(deltaTime: currentTime) + entityManager.getButtonByName(buttonName: "startGameButton").component(ofType: ButtonComponent.self)?.buttonNode.isEnabled = GameCenterManager.isAuthenticated + } + + if GameCenterManager.sharedInstance.initIsFinish { + self.loadScene(scene: GameCenterManager.sharedInstance.gameScene!) + } + } } diff --git a/GoldWars/GoldWars/SettingsScene.swift b/GoldWars/GoldWars/SettingsScene.swift index a9cd9e0..2e0760d 100644 --- a/GoldWars/GoldWars/SettingsScene.swift +++ b/GoldWars/GoldWars/SettingsScene.swift @@ -10,20 +10,22 @@ import SpriteKit class SettingsScene: SKScene { + var entityManager = EntityManager.settingsEMInstance + override func sceneDidLoad() { - EntityManager.sharedInstance.setScene(scene: self) + entityManager.setScene(scene: self) let positionX = self.size.width * 0.1 let positionY = self.size.height * 0.05 - - EntityManager.sharedInstance.add(Button(name: "backToMenuScene", - iconName: "", + entityManager.add(Button(name: "backToMenuScene", + textureName: "yellow_button04", text: "Back", position: CGPoint(x: positionX, y: positionY), onButtonPress: { - self.loadScene(scene: MenuScene(size: self.size)) + let scene = MenuScene(size: self.size) + self.loadScene(scene: scene) })) - EntityManager.sharedInstance.add(Button(name: "StopMenuMusic", - iconName: "", + entityManager.add(Button(name: "StopMenuMusic", + textureName: "yellow_button04", text: "ON/OFF", position: CGPoint(x: self.size.width * 0.6, y: self.size.height / 2), onButtonPress: { @@ -35,8 +37,8 @@ class SettingsScene: SKScene { SoundManager.sharedInstance.startMenuMusic() } })) - EntityManager.sharedInstance.add(Button(name: "StopMovingBackground", - iconName: "", + entityManager.add(Button(name: "StopMovingBackground", + textureName: "yellow_button04", text: "MOVE/STOP", position: CGPoint(x: self.size.width * 0.6, y: self.size.height / 2 - 100), onButtonPress: { @@ -46,7 +48,7 @@ class SettingsScene: SKScene { BackgroundComponent.isMovingBackgroundEnabled = true } })) - EntityManager.sharedInstance.add(Label(fontnamed: "Courier-Bold", + entityManager.add(Label(fontnamed: "Courier-Bold", name: "SettingsLabel", text: "Settings", fontSize: 200.0, @@ -57,7 +59,7 @@ class SettingsScene: SKScene { isAnimationEnabled: true, isAnimationInfinite: true) ) - EntityManager.sharedInstance.add(Label(fontnamed: "Courier-Bold", + entityManager.add(Label(fontnamed: "Courier-Bold", name: "LabelMusic", text: "Music", fontSize: 50.0, fontColor: .black, @@ -67,7 +69,7 @@ class SettingsScene: SKScene { isAnimationEnabled: true, isAnimationInfinite: false) ) - EntityManager.sharedInstance.add(Label(fontnamed: "Courier-Bold", + entityManager.add(Label(fontnamed: "Courier-Bold", name: "LabelBackground", text: "Background", fontSize: 50.0, @@ -78,16 +80,19 @@ class SettingsScene: SKScene { isAnimationEnabled: true, isAnimationInfinite: false) ) - EntityManager.sharedInstance.add(Background(size: self.size)) + entityManager.add(Background(size: self.size)) } func loadScene(scene: SKScene) { let transition = SKTransition.flipVertical(withDuration: 0.5) + entityManager.entities.removeAll() self.view?.presentScene(scene, transition: transition) } override func update(_ currentTime: TimeInterval) { - EntityManager.sharedInstance.getBackground()!.update(deltaTime: currentTime) + if entityManager.entities.count != 0 { + entityManager.getBackground()!.update(deltaTime: currentTime) + } } }