diff --git a/DouShouQiIOS/DouShouQiIOS.xcodeproj/project.pbxproj b/DouShouQiIOS/DouShouQiIOS.xcodeproj/project.pbxproj index ee595fb..d8d8760 100644 --- a/DouShouQiIOS/DouShouQiIOS.xcodeproj/project.pbxproj +++ b/DouShouQiIOS/DouShouQiIOS.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 7B236FB62C29B371008E9CA7 /* DSQ.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B6426F12C00B61500575E16 /* DSQ.xcframework */; }; 7B2597B82C203AFE0095F010 /* PlayerSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2597B72C203AFE0095F010 /* PlayerSelect.swift */; }; 7B2597BA2C203FCB0095F010 /* ImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B2597B92C203FCB0095F010 /* ImagePicker.swift */; }; 7B3B17642BF24B32002BC817 /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3B17632BF24B32002BC817 /* Player.swift */; }; @@ -20,7 +21,6 @@ 7B4508EA2BF206B10027E1EF /* DouShouQiIOSUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4508E92BF206B10027E1EF /* DouShouQiIOSUITestsLaunchTests.swift */; }; 7B4508F72BF2084B0027E1EF /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4508F62BF2084B0027E1EF /* PlayerView.swift */; }; 7B4508FA2BF214F50027E1EF /* PlayerListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B4508F92BF214F50027E1EF /* PlayerListView.swift */; }; - 7B6426F22C00B61500575E16 /* DSQ.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B6426F12C00B61500575E16 /* DSQ.xcframework */; }; 7B6426F72C00B81400575E16 /* GameScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6426F62C00B81400575E16 /* GameScene.swift */; }; 7B6426F92C00BDEA00575E16 /* SpriteKitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6426F82C00BDEA00575E16 /* SpriteKitView.swift */; }; 7B6426FB2C00BFF500575E16 /* SpriteMeeple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6426FA2C00BFF500575E16 /* SpriteMeeple.swift */; }; @@ -96,7 +96,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7B6426F22C00B61500575E16 /* DSQ.xcframework in Frameworks */, + 7B236FB62C29B371008E9CA7 /* DSQ.xcframework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/DouShouQiIOS/DouShouQiIOS/Class/GameScene.swift b/DouShouQiIOS/DouShouQiIOS/Class/GameScene.swift index 19d3bfb..f630146 100644 --- a/DouShouQiIOS/DouShouQiIOS/Class/GameScene.swift +++ b/DouShouQiIOS/DouShouQiIOS/Class/GameScene.swift @@ -46,7 +46,7 @@ class GameScene : SKScene{ ] ] - init(size s: CGSize, andVM gameVM : GameVM){ + override init(size s: CGSize){ //, andVM gameVM : GameVM //self.gameVm = gameVM super.init(size: s) @@ -57,13 +57,18 @@ class GameScene : SKScene{ self.anchorPoint = CGPoint(x: 0.5, y:0.5) } - private func displayBoard(_ board : DouShouQiModel.Board){ + func displayBoard(_ board : DouShouQiModel.Board){ + + //Nettoyage des fils + self.removeAllChildren() + self.addChild(imgBoard) + for row in 0.. todelete) + ///Players (-game -> todelete) // let player1 : Player // let player2 : Player // var pieces : [ Owner : [Animal : SpriteMeeple]] @@ -36,33 +36,43 @@ class GameVM : ObservableObject, Identifiable { @Published var displayMessage : String = "" //On donne directement la scene et la game à la vm - public init(withGame _game : Game?, andScene _gameScene : GameScene) { + public init(withGame _game : Game, andScene _gameScene : GameScene) { self.game = _game self.gameScene = _gameScene ///Abonnement aux événements - self.game?.addGameStartedListener(onGameStart) - self.game?.addPlayerNotifiedListener(onPlayerNotified) - self.game?.addMoveChosenCallbacksListener(onMoveChosen) - self.game?.addInvalidMoveCallbacksListener(onInvalidMove) - self.game?.addBoardChangedListener(onBoardChanged) - self.game?.addGameOverListener(onGameOver) + self.game.addGameStartedListener(onGameStart) + self.game.addPlayerNotifiedListener(onPlayerNotified) + self.game.addMoveChosenCallbacksListener(onMoveChosen) + self.game.addInvalidMoveCallbacksListener(onInvalidMove) + self.game.addBoardChangedListener(onBoardChanged) + self.game.addGameOverListener(onGameOver) //self.game?.addGameChangedListener({}) - //? cas persistance + + self.subscribesToMeeple() + + Task{ + try! await self.game.start() + } } func onGameStart(board : Board){ displayMessage = " ==>> 🎉 GAME STARTS! 🎉 <<== " + self.gameScene.displayBoard(board) + print("GAME STARTS") } func onPlayerNotified(board : Board, player : Player) async{ + print("PLAYER NOTIFIED") if player is HumanPlayer { displayMessage = "Player \(player.id == .player1 ? "🟡 1" : "🔴 2") - \(player.name), it's your turn!" + //try! await (player as! HumanPlayer).chooseMove(move) } else { do{ - _ = try await player.chooseMove(in: board, with: self.game!.rules) + _ = try await player.chooseMove(in: board, with: self.game.rules) } catch{ hasError = true @@ -84,12 +94,54 @@ class GameVM : ObservableObject, Identifiable { ///Mouvement invalide func onInvalidMove(board : Board, move : Move, player : Player, result : Bool){ + displayMessage = "⚠️⚠️⚠️⚠️ Invalid Move detected: \(move) by \(player.name) (\(player.id))" + if result { ///* invalidité terminante + if let piece = board.grid[move.rowDestination][move.columnDestination].piece{ + // Delete le meeple + let meeples = gameScene.pieces[player.id == .player1 ? .player2 : .player1] + let meeple = meeples?.first(where: { + $0.key == piece.animal + }) + meeple?.value.parent?.removeChildren(in: [meeple!.value]) + + } return } - displayMessage = "⚠️⚠️⚠️⚠️ Invalid Move detected: \(move) by \(player.name) (\(player.id))" + let piece = board.grid[move.rowOrigin][move.columnOrigin] + let meeples = gameScene.pieces[move.owner] + let meeple = meeples?.first(where: { + $0.key == piece.piece?.animal + }) + + meeple?.value.cellPosition = CGPoint(x: move.rowOrigin, y: move.columnOrigin); + + print("INVALID") } + func invalideMoveChosen(board: Board, move: Move, player: Player, result: Bool) { + if result { + if let piece = board.grid[move.rowDestination][move.columnDestination].piece{ + // Delete le meeple + let meeples = gameScene.pieces[player.id == .player1 ? .player2 : .player1] + let meeple = meeples?.first(where: { + $0.key == piece.animal + }) + meeple?.value.parent?.removeChildren(in: [meeple!.value]) + + } + return + } + let piece = board.grid[move.rowOrigin][move.columnOrigin] + let meeples = gameScene.pieces[move.owner] + let meeple = meeples?.first(where: { + $0.key == piece.piece?.animal + }) + + meeple?.value.cellPosition = CGPoint(x: move.rowOrigin, y: move.columnOrigin); + } + + func onBoardChanged(board : Board){ /// Bruit d'un placement de pion ? } @@ -100,27 +152,37 @@ class GameVM : ObservableObject, Identifiable { } - func readInt(withMessage message: String) -> Int { - var temp: Int? - while temp == nil { - print(message) - let result = readLine() - temp = Int(result ?? "") + ///Meeples + + func subscribesToMeeple(){ + for meeple in gameScene.pieces[.player1]!{ + meeple.value.observers.append(meepleMoved) + } + for meeple in gameScene.pieces[.player2]!{ + meeple.value.observers.append(meepleMoved) } - return temp! } - - func readMove(from player: HumanPlayer) -> Move? { - var originRow, originCol, destRow, destCol : Int? - - originRow = readInt(withMessage: "\(player.name) please enter the origin row in which your piece is)") - originCol = readInt(withMessage: "\(player.name) please enter the origin column in which your piece is)") - destRow = readInt(withMessage: "\(player.name) please enter the destination row in which you want to move your piece)") - destCol = readInt(withMessage: "\(player.name) please enter the destination column in which you want to move your piece)") - - //self.pieces[player.id][Animal.cat]? + + func meepleMoved(spriteMeeple: SpriteMeeple, startX: Int, startY: Int, endX: Int, endY: Int) async{ + let owner : Owner = game.board.grid[startX][startY].piece!.owner + let otherPlayer : Owner = self.game.rules.getNextPlayer() - return Move(of: player.id, fromRow: originRow!, andFromColumn: originCol!, toRow: destRow!, andToColumn: destCol!) + let move: Move = Move(of: owner, fromRow: startX, andFromColumn: startY, toRow: endX, andToColumn: endY) + if(otherPlayer != owner){ ///Mauvais Joueur pour ce jeton + print("invalide de la part de meepleMoved") + onInvalidMove(board: game.board, move: move, player: game.players[otherPlayer]!, result: false) + return + } + + if let player: HumanPlayer = game.players[owner] as? HumanPlayer{ + try! await player.chooseMove(move) + } +// else { ///IMPOSSIBLE DE CAST LE JOUEUR HUMAIN +// let player: HumanPlayer = game.players[.player1] as! HumanPlayer +// try! await player.chooseMove(move) +// } + + print("il a bougé") } } diff --git a/DouShouQiIOS/DouShouQiIOS/Class/SpriteMeeple.swift b/DouShouQiIOS/DouShouQiIOS/Class/SpriteMeeple.swift index 81b0444..899b034 100644 --- a/DouShouQiIOS/DouShouQiIOS/Class/SpriteMeeple.swift +++ b/DouShouQiIOS/DouShouQiIOS/Class/SpriteMeeple.swift @@ -9,7 +9,7 @@ import Foundation import SpriteKit import SwiftUI -class SpriteMeeple : SKNode{ +class SpriteMeeple : SKNode, ObservableObject{ let imageNode : SKSpriteNode let ellipseNode : SKShapeNode @@ -24,6 +24,11 @@ class SpriteMeeple : SKNode{ static let offset = CGPoint(x:-400, y:-300) static let direction = CGVector(dx:100, dy:100); + + //@Published var observers : [ any ObservableObject ] = [] + @Published var observers : [ (SpriteMeeple, Int, Int, Int, Int) async ->() ] = [] + + public init(imageName imgN : String,size meepleSize : CGSize,color meepleColor : Color){ imageNode = SKSpriteNode(imageNamed: imgN) imageNode.size = meepleSize; @@ -86,7 +91,14 @@ class SpriteMeeple : SKNode{ self.position.y = (calcy.rounded(.toNearestOrAwayFromZero))*100; } + ///Envoi au observers d'une notif + ///* Exectution des Observeurs + Task { + for observer in observers { + await observer(self, Int(cellPosition.x), Int(cellPosition.y), Int(position.x), Int(position.y)) + } + } } required init?(coder aDecoder: NSCoder) { diff --git a/DouShouQiIOS/DouShouQiIOS/View/GameView.swift b/DouShouQiIOS/DouShouQiIOS/View/GameView.swift index 969baf0..6073646 100644 --- a/DouShouQiIOS/DouShouQiIOS/View/GameView.swift +++ b/DouShouQiIOS/DouShouQiIOS/View/GameView.swift @@ -19,8 +19,6 @@ struct GameView: View { @State private var player1Pieces = 8 @State private var player2Pieces = 8 - // On donne les deux player à la vue ? - var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() let gridItems = Array(repeating: GridItem(.flexible()), count: 8) @@ -29,13 +27,18 @@ struct GameView: View { var gameVM : GameVM ///SK - var gs : GameScene + //var gs : GameScene - init (){ - self.gameVM = GameVM(andPlayer1: Player(withName: "Meruemu", andId: .player1)!, andPlayer2: Player(withName: "Kumogi", andId: .player2)!) + init (gameVM : GameVM){ + //self.gameVM = GameVM(andPlayer1: Player(withName: "Meruemu", andId: .player1)!, andPlayer2: Player(withName: "Kumogi", andId: .player2)!) + self.gameVM = gameVM + // self.gs = GameScene(size: CGSizeMake(940,740), andVM: gameVM) + //self.gs = GameScene(size: CGSizeMake(940,740)) + + - self.gs = GameScene(size: CGSizeMake(940,740), andVM: gameVM) + } var body: some View { @@ -44,7 +47,7 @@ struct GameView: View { VStack { VStack { Text(gameVM.displayMessage) - .font(.title) + .font(.title3) .padding(.top, 20) HStack { @@ -77,7 +80,7 @@ struct GameView: View { .padding(20) */ - SpriteView(scene: gs) + SpriteView(scene: gameVM.gameScene) .frame(width: 350, height: 275) .padding(10) .background(Color.primaryColor) @@ -122,6 +125,6 @@ struct GameView: View { struct GameView_Previews: PreviewProvider { static var previews: some View { - GameView() + GameView(gameVM: GameVM(withGame: try! Game(withRules: ClassicRules(), andPlayer1: Player(withName: "toto", andId: .player1)!, andPlayer2: Player(withName: "tata", andId: .player2)!), andScene: GameScene(size: CGSize(width: 120, height: 120)))) } } diff --git a/DouShouQiIOS/DouShouQiIOS/View/MainMenuView.swift b/DouShouQiIOS/DouShouQiIOS/View/MainMenuView.swift index 27d7569..b005511 100644 --- a/DouShouQiIOS/DouShouQiIOS/View/MainMenuView.swift +++ b/DouShouQiIOS/DouShouQiIOS/View/MainMenuView.swift @@ -6,10 +6,18 @@ // import SwiftUI +import DouShouQiModel + struct MainMenuView: View { @Environment(\.colorScheme) var colorScheme + var gamevm : GameVM = GameVM(withGame: try! Game(withRules: ClassicRules(), + andPlayer1: Player(withName: "Meruemu", andId: .player1)!, + andPlayer2: Player(withName: "Kumogi", andId: .player2)!), + andScene: GameScene(size: CGSize(width: 940, height: 740))) + + var body: some View { NavigationStack { @@ -27,7 +35,8 @@ struct MainMenuView: View { .bold() .padding() - NavButton("Jouer Seul", destinationView: {PlayerSelect(versus: false)}) + //NavButton("Jouer Seul", destinationView: {PlayerSelect(versus: false)}) + NavButton("Jouer Seul", destinationView: {GameView(gameVM: gamevm)}) .padding(.top, 10) NavButton("Jouer en Multi", destinationView: {PlayerSelect(versus: true)})