Merge branch '39-spielendkriterium' into 'development'

Resolve "Spielendkriterium"

Closes #39

See merge request marcel.schwarz/software-projekt-2!105
This commit is contained in:
Aldin Duraki 2020-06-02 20:34:02 +00:00
commit 69927d35fa
9 changed files with 140 additions and 13 deletions

View File

@ -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
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -53,6 +53,10 @@ class EntityManager {
scene.addChild(hudEntitiy.spySkill) scene.addChild(hudEntitiy.spySkill)
scene.addChild(hudEntitiy.roundTimerLabel) scene.addChild(hudEntitiy.roundTimerLabel)
scene.addChild(hudEntitiy.finishButton) 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) { if let spriteNode = entity.component(ofType: DefaultBaseComponent.self) {

View File

@ -27,6 +27,11 @@ class HUD: GKEntity {
var roundTimerLabel: SKLabelNode var roundTimerLabel: SKLabelNode
let roundTimer: RoundTimer let roundTimer: RoundTimer
var backgroundRoundCounter: SKSpriteNode
var currentRoundLabel: SKLabelNode
var roundsLabel: SKLabelNode
var roundLabel: SKLabelNode
var finishButton: ButtonNode var finishButton: ButtonNode
init(size: CGSize) { init(size: CGSize) {
@ -84,13 +89,19 @@ class HUD: GKEntity {
text: "Done", text: "Done",
isEnabled: true, isEnabled: true,
position: CGPoint( position: CGPoint(
x: EntityManager.gameEMInstance.scene.size.width * 0.1, x: EntityManager.gameEMInstance.scene.size.width * 0.15,
y: EntityManager.gameEMInstance.scene.size.height * 0.1), y: EntityManager.gameEMInstance.scene.size.height * 0.06),
onButtonPress: { } onButtonPress: { }
) )
finishButton.size = CGSize(width: 80, height: 40) finishButton.size = CGSize(width: 80, height: 40)
finishButton.zPosition = 2 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() super.init()
initRoundInfo(size: size)
finishButton.onButtonPress = { [unowned self] in finishButton.onButtonPress = { [unowned self] in
self.finishRound() self.finishRound()
@ -134,4 +145,39 @@ class HUD: GKEntity {
self.roundTimer.timeLeft = 1; self.roundTimer.timeLeft = 1;
self.roundTimer.roundEnded = "Waiting for other player..." 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)
}
} }

View File

@ -22,6 +22,8 @@ struct State: Codable {
// 1 RemotePlayerInit fertig // 1 RemotePlayerInit fertig
// 2 Peer hat Map erhalten // 2 Peer hat Map erhalten
// 3 Host hat Spiel gestartet // 3 Host hat Spiel gestartet
// 4 Peer hat verloren
// 5 Peer hat gewonnen
let state: Int let state: Int
} }
@ -92,7 +94,7 @@ final class GameCenterManager: NSObject, GKMatchmakerViewControllerDelegate, GKG
achievement.percentComplete += increasePercentComplete achievement.percentComplete += increasePercentComplete
achievement.showsCompletionBanner = true achievement.showsCompletionBanner = true
GKAchievement.report([achievement]) { (error) in GKAchievement.report([achievement]) { (error) in
print(error?.localizedDescription ?? "") print(error?.localizedDescription ?? "")
} }
} }
}) })
@ -101,7 +103,7 @@ final class GameCenterManager: NSObject, GKMatchmakerViewControllerDelegate, GKG
newAchievement.showsCompletionBanner = true newAchievement.showsCompletionBanner = true
newAchievement.percentComplete = increasePercentComplete newAchievement.percentComplete = increasePercentComplete
GKAchievement.report([newAchievement]) { (error) in GKAchievement.report([newAchievement]) { (error) in
print(error?.localizedDescription ?? "") print(error?.localizedDescription ?? "")
} }
} }
} }
@ -140,7 +142,7 @@ final class GameCenterManager: NSObject, GKMatchmakerViewControllerDelegate, GKG
initAndSendMap() initAndSendMap()
}else { }else {
os_log("Host hat Player initialisiert", log: LOG, type: .info) os_log("Host hat Player initialisiert", log: LOG, type: .info)
} }
case 2: case 2:
os_log("State 2 erhalten", log: LOG, type: .info) os_log("State 2 erhalten", log: LOG, type: .info)
sendStateToPeers(state: State(state: 3)) sendStateToPeers(state: State(state: 3))
@ -150,6 +152,12 @@ final class GameCenterManager: NSObject, GKMatchmakerViewControllerDelegate, GKG
os_log("State 3 erhalten", log: LOG, type: .info) os_log("State 3 erhalten", log: LOG, type: .info)
initIsFinish = true initIsFinish = true
os_log("Spiel startet", log: LOG, type: .info) 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: default:
break break
} }
@ -159,6 +167,8 @@ final class GameCenterManager: NSObject, GKMatchmakerViewControllerDelegate, GKG
} }
if let snapshotModel = try? jsonDecoder.decode(SnapshotModel.self, from: data) { if let snapshotModel = try? jsonDecoder.decode(SnapshotModel.self, from: data) {
DataService.sharedInstance.snapshotModel = snapshotModel DataService.sharedInstance.snapshotModel = snapshotModel
RoundCalculatorService.sharedInstance.currentRound += 1
entityManager.getHUD()?.setCurrentRound(round: RoundCalculatorService.sharedInstance.currentRound)
entityManager.updateSnapshotModel(snapshotModel: snapshotModel) entityManager.updateSnapshotModel(snapshotModel: snapshotModel)
entityManager.getHUD()?.startWithDuration() entityManager.getHUD()?.startWithDuration()
} }

View File

@ -10,20 +10,19 @@ import GameKit
import os import os
class RoundCalculatorService { class RoundCalculatorService {
var entityManager = EntityManager.gameEMInstance
static let sharedInstance = RoundCalculatorService() static let sharedInstance = RoundCalculatorService()
static let LOG = OSLog.init(subsystem: "Round Calculator", category: "RoundCalculatorService") static let LOG = OSLog.init(subsystem: "Round Calculator", category: "RoundCalculatorService")
let ATK_BOOST_MULTIPLICATOR = 1.1
let DEF_BOOST_MULTIPLICATOR = 1.1
var allPlayerMoves: [String: [PlayerMove]] = [:] var allPlayerMoves: [String: [PlayerMove]] = [:]
// TODO: Better data structure // TODO: Better data structure
var boosts: [String: (Bool, Bool)] = [:] // First bool is atk boost, second is def boost var boosts: [String: (Bool, Bool)] = [:] // First bool is atk boost, second is def boost
var entityManager = EntityManager.gameEMInstance let ATK_BOOST_MULTIPLICATOR = 1.1
let DEF_BOOST_MULTIPLICATOR = 1.1
let MAX_ROUNDS = 20
var currentRound = 1
var isCalculating = false var isCalculating = false
var numberOfAttacks = 0 var numberOfAttacks = 0
var numberOfOwnUnitMoves = 0 var numberOfOwnUnitMoves = 0
@ -148,6 +147,23 @@ class RoundCalculatorService {
DataService.sharedInstance.localRoundData.localPlayerMoves.removeAll() DataService.sharedInstance.localRoundData.localPlayerMoves.removeAll()
DataService.sharedInstance.localRoundData.hasAttackBoost = false DataService.sharedInstance.localRoundData.hasAttackBoost = false
DataService.sharedInstance.localRoundData.hasDefenceBoost = 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() MultiplayerNetwork.sharedInstance.sendSnapshotModelToPlayers()
DataService.sharedInstance.snapshotModel = currentSnapshotModel DataService.sharedInstance.snapshotModel = currentSnapshotModel
entityManager.updateSnapshotModel(snapshotModel: currentSnapshotModel!) entityManager.updateSnapshotModel(snapshotModel: currentSnapshotModel!)
@ -168,7 +184,7 @@ class RoundCalculatorService {
DataService.sharedInstance.remotePlayerMoves[GameCenterManager.sharedInstance.peerPlayer!.displayName]?.hasAttackBoost ?? false, DataService.sharedInstance.remotePlayerMoves[GameCenterManager.sharedInstance.peerPlayer!.displayName]?.hasAttackBoost ?? false,
DataService.sharedInstance.remotePlayerMoves[GameCenterManager.sharedInstance.peerPlayer!.displayName]?.hasDefenceBoost ?? false DataService.sharedInstance.remotePlayerMoves[GameCenterManager.sharedInstance.peerPlayer!.displayName]?.hasDefenceBoost ?? false
) )
allPlayerMoves[GKLocalPlayer.local.displayName] = DataService.sharedInstance.localRoundData.localPlayerMoves allPlayerMoves[GKLocalPlayer.local.displayName] = DataService.sharedInstance.localRoundData.localPlayerMoves
var baseSpecificMoves: [Int: [String: [PlayerMove]]] = [:] var baseSpecificMoves: [Int: [String: [PlayerMove]]] = [:]
@ -206,4 +222,33 @@ class RoundCalculatorService {
self.numberOfAttacks += 1 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!
}
} }

View File

@ -13,7 +13,6 @@ class SettingsScene: SKScene {
var entityManager = EntityManager.settingsEMInstance var entityManager = EntityManager.settingsEMInstance
override func sceneDidLoad() { override func sceneDidLoad() {
entityManager.setScene(scene: self) entityManager.setScene(scene: self)
let positionX = self.size.width * 0.1 let positionX = self.size.width * 0.1
let positionY = self.size.height * 0.05 let positionY = self.size.height * 0.05