diff --git a/GoldWars/GoldWars.xcodeproj/project.pbxproj b/GoldWars/GoldWars.xcodeproj/project.pbxproj index ebaec53..ba4f9b5 100644 --- a/GoldWars/GoldWars.xcodeproj/project.pbxproj +++ b/GoldWars/GoldWars.xcodeproj/project.pbxproj @@ -46,6 +46,12 @@ AB1D75A0245DEC0500671525 /* MapFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB1D759F245DEC0500671525 /* MapFactory.swift */; }; ABA03DA0244BD54F00A66916 /* Base.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABA03D9F244BD54F00A66916 /* Base.swift */; }; AE151589245F18EF001D363E /* MatchmakingHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE151588245F18EF001D363E /* MatchmakingHelper.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 */; }; + 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 */; }; + C064E9AC246C151F0022B228 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = C064E9AB246C151F0022B228 /* Label.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -103,6 +109,12 @@ AB1D759F245DEC0500671525 /* 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + C064E9AB246C151F0022B228 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -146,6 +158,7 @@ 110360D1244B101A008610AF /* GoldWars */ = { isa = PBXGroup; children = ( + C04783ED2468583F004961FB /* intro-music.mp3 */, 9ECD3699245C91F7008DEEBD /* GoldWars.entitlements */, 9E11FF74245CD79100EED3BE /* Partikels */, 116060F5245C5709004E5A36 /* Entities */, @@ -155,11 +168,16 @@ 9EC86BA4245C8A1E00796EF3 /* Scenes */, 9EC86BA3245C89F400796EF3 /* Storyboards */, 110360D2244B101A008610AF /* AppDelegate.swift */, + C05FAED52468559D0006AF2E /* SoundManager.swift */, 110360DA244B101A008610AF /* GameViewController.swift */, 110360DF244B101B008610AF /* Assets.xcassets */, 110360E4244B101B008610AF /* Info.plist */, AE151588245F18EF001D363E /* MatchmakingHelper.swift */, 3EBD242B245D8044003CECE7 /* GameCenterHelper.swift */, + C04783EF24685995004961FB /* SettingsScene.swift */, + C064E9A7246C0EA50022B228 /* LabelNode.swift */, + C064E9A9246C114C0022B228 /* LabelComponent.swift */, + C064E9AB246C151F0022B228 /* Label.swift */, ); path = GoldWars; sourceTree = ""; @@ -347,6 +365,7 @@ 9E11FF79245CD81100EED3BE /* Fire.sks in Resources */, 110360E0244B101B008610AF /* Assets.xcassets in Resources */, 110360E3244B101B008610AF /* LaunchScreen.storyboard in Resources */, + C04783EE2468583F004961FB /* intro-music.mp3 in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -372,7 +391,9 @@ 9EA3ABEB245C6DFA006BC61D /* BaseNode.swift in Sources */, 9E04AFAF245E2B73002D5CFC /* AttackActionComponent.swift in Sources */, 110360D9244B101A008610AF /* GameScene.swift in Sources */, + C04783F024685995004961FB /* SettingsScene.swift in Sources */, 116060F7245C57D2004E5A36 /* EntityManager.swift in Sources */, + C064E9AA246C114C0022B228 /* LabelComponent.swift in Sources */, 3EBD242E245D9332003CECE7 /* Team.swift in Sources */, 9E174C88245DF1FF00209FF0 /* BackgroundComponent.swift in Sources */, 9E78ACBA245CBDAF00526FF7 /* HUD.swift in Sources */, @@ -383,12 +404,14 @@ 9EA3ABE9245C6DAA006BC61D /* DefaultBaseComponent.swift in Sources */, 9E174C8A245E1A0A00209FF0 /* Background.swift in Sources */, 9EA3ABED245C8143006BC61D /* ModalBackgroundComponent.swift in Sources */, + C064E9A8246C0EA50022B228 /* LabelNode.swift in Sources */, 3EBD242C245D8044003CECE7 /* GameCenterHelper.swift in Sources */, AB1D759C245DD18100671525 /* MapProtocol.swift in Sources */, AB1D75A0245DEC0500671525 /* MapFactory.swift in Sources */, AB1D759D245DD18100671525 /* TwoPlayerDefaultTestMap.swift in Sources */, 9EBFD7552462CF5A00E1E219 /* SliderComponent.swift in Sources */, ABA03DA0244BD54F00A66916 /* Base.swift in Sources */, + C064E9AC246C151F0022B228 /* Label.swift in Sources */, 9E174C82245DD81D00209FF0 /* ButtonNode.swift in Sources */, 9EC7E48B2461FBF700396BCD /* SliderNode.swift in Sources */, 9E174C84245DD8CE00209FF0 /* Button.swift in Sources */, @@ -397,6 +420,7 @@ 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/Components/BackgroundComponent.swift b/GoldWars/GoldWars/Components/BackgroundComponent.swift index 7239741..f74d5dd 100644 --- a/GoldWars/GoldWars/Components/BackgroundComponent.swift +++ b/GoldWars/GoldWars/Components/BackgroundComponent.swift @@ -12,6 +12,7 @@ class BackgroundComponent: GKComponent{ var nodes = [SKSpriteNode]() let size: CGSize + static var isMovingBackgroundEnabled = true init(size: CGSize) { self.size = size @@ -27,10 +28,12 @@ class BackgroundComponent: GKComponent{ } func update(){ - for node in nodes{ - node.position.x -= 2 - if node.position.x < -(size.width) { - node.position.x += (size.width) * 3 + if BackgroundComponent.isMovingBackgroundEnabled { + for node in nodes{ + node.position.x -= 2 + if node.position.x < -(size.width) { + node.position.x += (size.width) * 3 + } } } } diff --git a/GoldWars/GoldWars/Entities/EntityManager.swift b/GoldWars/GoldWars/Entities/EntityManager.swift index 6c92437..c2d8239 100644 --- a/GoldWars/GoldWars/Entities/EntityManager.swift +++ b/GoldWars/GoldWars/Entities/EntityManager.swift @@ -65,6 +65,9 @@ class EntityManager { scene.addChild(sliderNode.sliderKnob) scene.addChild(sliderNode.sliderLine) } + if let labelNode = entity.component(ofType: LabelComponent.self)?.labelNode { + scene.addChild(labelNode) + } } func remove(_ entity: GKEntity) { diff --git a/GoldWars/GoldWars/Label.swift b/GoldWars/GoldWars/Label.swift new file mode 100644 index 0000000..2cac987 --- /dev/null +++ b/GoldWars/GoldWars/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/LabelComponent.swift b/GoldWars/GoldWars/LabelComponent.swift new file mode 100644 index 0000000..aa57816 --- /dev/null +++ b/GoldWars/GoldWars/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/LabelNode.swift b/GoldWars/GoldWars/LabelNode.swift new file mode 100644 index 0000000..669a0b5 --- /dev/null +++ b/GoldWars/GoldWars/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/Scenes/MenuScene.swift b/GoldWars/GoldWars/Scenes/MenuScene.swift index edf6bb9..bca03d2 100644 --- a/GoldWars/GoldWars/Scenes/MenuScene.swift +++ b/GoldWars/GoldWars/Scenes/MenuScene.swift @@ -23,6 +23,7 @@ class MenuScene: SKScene { onButtonPress: { if CommandLine.arguments.contains("--no-matchmaking") { self.loadScene(scene: GameScene(size: self.size)) + SoundManager.sharedInstance.stopMenuMusic() } else { MatchmakingHelper.sharedInstance.presentMatchmaker(scene: self) } @@ -32,9 +33,13 @@ class MenuScene: SKScene { text: "Settings", position: CGPoint(x: midX, y: midY - 80 ), onButtonPress: { - //TODO: create Settings Scene - })) + self.loadScene(scene: SettingsScene(size: self.size)) + })) entityManager.add(Background(size: self.size)) + + if SoundManager.sharedInstance.isMusicPlaying == false && SoundManager.sharedInstance.isMusicEnabled == true { + SoundManager.sharedInstance.startMenuMusic() + } } func loadScene(scene: SKScene) { diff --git a/GoldWars/GoldWars/SettingsScene.swift b/GoldWars/GoldWars/SettingsScene.swift new file mode 100644 index 0000000..8eb22f5 --- /dev/null +++ b/GoldWars/GoldWars/SettingsScene.swift @@ -0,0 +1,94 @@ +// +// SettingsScene.swift +// GoldWars +// +// Created by Tim Herbst on 10.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import SpriteKit + +class SettingsScene: SKScene { + var entityManager: EntityManager! + + override func sceneDidLoad() { + entityManager = EntityManager(scene: self) + let positionX = self.size.width * 0.1 + let positionY = self.size.height * 0.05 + + entityManager.add(Button(name: "backToMenuScene", + iconName: "", + text: "Back", + position: CGPoint(x: positionX, y: positionY), + onButtonPress: { + self.loadScene(scene: MenuScene(size: self.size)) + })) + entityManager.add(Button(name: "StopMenuMusic", + iconName: "", + text: "ON/OFF", + position: CGPoint(x: self.size.width * 0.6, y: self.size.height / 2), + onButtonPress: { + if SoundManager.sharedInstance.isMusicPlaying { + SoundManager.sharedInstance.stopMenuMusic() + SoundManager.sharedInstance.isMusicEnabled = false + } else { + SoundManager.sharedInstance.isMusicEnabled = true + SoundManager.sharedInstance.startMenuMusic() + } + })) + entityManager.add(Button(name: "StopMovingBackground", + iconName: "", + text: "MOVE/STOP", + position: CGPoint(x: self.size.width * 0.6, y: self.size.height / 2 - 100), + onButtonPress: { + if BackgroundComponent.isMovingBackgroundEnabled { + BackgroundComponent.isMovingBackgroundEnabled = false + } else { + BackgroundComponent.isMovingBackgroundEnabled = true + } + })) + entityManager.add(Label(fontnamed: "Courier-Bold", + name: "SettingsLabel", + text: "Settings", + fontSize: 200.0, + fontColor: .black, + position: CGPoint(x: self.size.width * 0.5, y: self.size.height * 0.7), + horizontalAlignmentMode: .center, + vertikalAligmentMode: .baseline, + isAnimationEnabled: true, + isAnimationInfinite: true) + ) + entityManager.add(Label(fontnamed: "Courier-Bold", + name: "LabelMusic", + text: "Music", fontSize: 50.0, + fontColor: .black, + position: CGPoint(x: self.size.width * 0.5, y: self.size.height / 2 - 15), + horizontalAlignmentMode: .right, + vertikalAligmentMode: .baseline, + isAnimationEnabled: true, + isAnimationInfinite: false) + ) + entityManager.add(Label(fontnamed: "Courier-Bold", + name: "LabelBackground", + text: "Background", + fontSize: 50.0, + fontColor: .black, + position: CGPoint(x: self.size.width * 0.5, y: self.size.height / 2 - 115), + horizontalAlignmentMode: .right, + vertikalAligmentMode: .baseline, + isAnimationEnabled: true, + isAnimationInfinite: false) + ) + entityManager.add(Background(size: self.size)) + } + + func loadScene(scene: SKScene) { + let transition = SKTransition.flipVertical(withDuration: 0.5) + self.view?.presentScene(scene, transition: transition) + } + + override func update(_ currentTime: TimeInterval) { + entityManager.getBackground()!.update(deltaTime: currentTime) + } + +} diff --git a/GoldWars/GoldWars/SoundManager.swift b/GoldWars/GoldWars/SoundManager.swift new file mode 100644 index 0000000..4f8f34d --- /dev/null +++ b/GoldWars/GoldWars/SoundManager.swift @@ -0,0 +1,47 @@ +// +// SoundManager.swift +// GoldWars +// +// Created by Tim Herbst on 10.05.20. +// Copyright © 2020 SP2. All rights reserved. +// + +import SpriteKit +import AVFoundation + +class SoundManager { + public static var sharedInstance = SoundManager() + + var audioPlayer = AVAudioPlayer() + var backgroundMainMenuAudio: URL? + var isMusicPlaying = false + var isMusicEnabled = true + + func startMenuMusic() { + self.isMusicPlaying = true + backgroundMainMenuAudio = Bundle.main.url(forResource: "intro-music", withExtension: "mp3") + do { + audioPlayer = try AVAudioPlayer(contentsOf: backgroundMainMenuAudio!) + } catch { + print("Datei nicht gefunden!") + } + audioPlayer.numberOfLoops = -1 + audioPlayer.prepareToPlay() + if self.isMusicEnabled == true { + audioPlayer.play() + } + } + + func stopMenuMusic() { + audioPlayer.pause() + self.isMusicPlaying = false + } + + func setVolume(_ volume: Float) { + audioPlayer.volume = volume + } + + func getVolume() -> Float { + return audioPlayer.volume + } +} diff --git a/GoldWars/GoldWars/intro-music.mp3 b/GoldWars/GoldWars/intro-music.mp3 new file mode 100644 index 0000000..6aaa001 Binary files /dev/null and b/GoldWars/GoldWars/intro-music.mp3 differ