Merge branch 'dev_views_Game'

Conflicts:
	DouShouQi_App/DouShouQi_App.xcodeproj/project.pbxproj
	DouShouQi_App/DouShouQi_App/Views/Game/GameView.swift
	DouShouQi_App/DouShouQi_App/Views/Player/SelectPlayerView.swift
dev_vm_saveHistorique
Nathan VERDIER 10 months ago
commit 631ae89c11

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
6437FF132C25846F009D0EAF /* PlayingGameVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6437FF122C25846F009D0EAF /* PlayingGameVM.swift */; };
6437FF142C25870C009D0EAF /* DSQ.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EC62C5322C1C188F0048CD0B /* DSQ.xcframework */; };
6458345C2BF5F92300E18321 /* DouShouQi_AppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6458345B2BF5F92300E18321 /* DouShouQi_AppApp.swift */; };
6458345E2BF5F92300E18321 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6458345D2BF5F92300E18321 /* ContentView.swift */; };
645834602BF5F92500E18321 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6458345F2BF5F92500E18321 /* Assets.xcassets */; };
@ -30,6 +32,7 @@
649B59AE2BF64EAB002BAE38 /* AppImages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649B59AD2BF64EAB002BAE38 /* AppImages.swift */; };
649B59B22BF65392002BAE38 /* TextStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649B59B12BF65392002BAE38 /* TextStyles.swift */; };
649B59B42BF653E1002BAE38 /* ViewTitleTextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649B59B32BF653E1002BAE38 /* ViewTitleTextStyle.swift */; };
64D2D74E2C25D380009BD010 /* Animals.Symbols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D2D74D2C25D380009BD010 /* Animals.Symbols.swift */; };
64D992722C06281B002ACBC6 /* SystemIcons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D992712C06281B002ACBC6 /* SystemIcons.swift */; };
64FC4D692C09C78000D08B8B /* SelectPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64FC4D682C09C78000D08B8B /* SelectPlayerView.swift */; };
64FC4D6B2C09C7C900D08B8B /* SelectPlayerButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64FC4D6A2C09C7C900D08B8B /* SelectPlayerButtonView.swift */; };
@ -56,7 +59,6 @@
EC62C5252C0F68830048CD0B /* PlayerVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC62C5242C0F68830048CD0B /* PlayerVM.swift */; };
EC62C5292C1974000048CD0B /* PlayersVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC62C5282C1974000048CD0B /* PlayersVM.swift */; };
EC62C52D2C197ED10048CD0B /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC62C52C2C197ED10048CD0B /* Player.swift */; };
EC62C5332C1C188F0048CD0B /* DSQ.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EC62C5322C1C188F0048CD0B /* DSQ.xcframework */; };
EC62C5382C1C64EE0048CD0B /* CoreManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC62C5372C1C64EE0048CD0B /* CoreManager.swift */; };
EC62C53D2C1C69200048CD0B /* DouShouQi_App.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = EC62C53B2C1C69200048CD0B /* DouShouQi_App.xcdatamodeld */; };
EC62C53F2C1C6D1A0048CD0B /* CDPlayerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC62C53E2C1C6D1A0048CD0B /* CDPlayerExtension.swift */; };
@ -98,6 +100,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
6437FF122C25846F009D0EAF /* PlayingGameVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayingGameVM.swift; sourceTree = "<group>"; };
645834582BF5F92300E18321 /* DouShouQi_App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DouShouQi_App.app; sourceTree = BUILT_PRODUCTS_DIR; };
6458345B2BF5F92300E18321 /* DouShouQi_AppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DouShouQi_AppApp.swift; sourceTree = "<group>"; };
6458345D2BF5F92300E18321 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@ -125,6 +128,7 @@
649B59AD2BF64EAB002BAE38 /* AppImages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppImages.swift; sourceTree = "<group>"; };
649B59B12BF65392002BAE38 /* TextStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextStyles.swift; sourceTree = "<group>"; };
649B59B32BF653E1002BAE38 /* ViewTitleTextStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewTitleTextStyle.swift; sourceTree = "<group>"; };
64D2D74D2C25D380009BD010 /* Animals.Symbols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animals.Symbols.swift; sourceTree = "<group>"; };
64D992712C06281B002ACBC6 /* SystemIcons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemIcons.swift; sourceTree = "<group>"; };
64FC4D682C09C78000D08B8B /* SelectPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectPlayerView.swift; sourceTree = "<group>"; };
64FC4D6A2C09C7C900D08B8B /* SelectPlayerButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectPlayerButtonView.swift; sourceTree = "<group>"; };
@ -174,7 +178,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EC62C5332C1C188F0048CD0B /* DSQ.xcframework in Frameworks */,
6437FF142C25870C009D0EAF /* DSQ.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -322,6 +326,7 @@
children = (
646FA83D2C072340001466BA /* GameVM.swift */,
646FA8422C0730D6001466BA /* HistoricVM.swift */,
6437FF122C25846F009D0EAF /* PlayingGameVM.swift */,
);
path = Game;
sourceTree = "<group>";
@ -455,6 +460,7 @@
children = (
EC62C53E2C1C6D1A0048CD0B /* CDPlayerExtension.swift */,
ECF3FD302C2722C600F5E62B /* CDHistoriqueExtension.swift */,
64D2D74D2C25D380009BD010 /* Animals.Symbols.swift */,
);
path = Extensions;
sourceTree = "<group>";
@ -672,6 +678,7 @@
649B59B22BF65392002BAE38 /* TextStyles.swift in Sources */,
EC99D5C12C089F6B00731B62 /* GameResumeFrame.swift in Sources */,
EC05BFCB2C05F470000F7B19 /* GameScene.swift in Sources */,
64D2D74E2C25D380009BD010 /* Animals.Symbols.swift in Sources */,
6458345C2BF5F92300E18321 /* DouShouQi_AppApp.swift in Sources */,
ECB636512C046379007CD5E2 /* MusicPlayer.swift in Sources */,
ECB6364E2C04628E007CD5E2 /* SpriteMeeple.swift in Sources */,
@ -709,6 +716,7 @@
646F04BE2C0F54C0003C8600 /* SettingsVM.swift in Sources */,
EC62C52D2C197ED10048CD0B /* Player.swift in Sources */,
EC62C5292C1974000048CD0B /* PlayersVM.swift in Sources */,
6437FF132C25846F009D0EAF /* PlayingGameVM.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

@ -0,0 +1,34 @@
//
// Animals.Symbols.swift
// DouShouQi_App
//
// Created by Rémi REGNAULT on 21/06/2024.
//
import Foundation
import DouShouQiModel
extension Animal {
public var symbol: String {
switch self{
case .rat:
return "🐭"
case .cat:
return "🐱"
case .dog:
return "🐶"
case .wolf:
return "🐺"
case .leopard:
return "🐆"
case .tiger:
return "🐯"
case .lion:
return "🦁"
case .elephant:
return "🐘"
@unknown default:
return "🐥"
}
}
}

@ -13,4 +13,6 @@ public struct Colors {
static let Button = Color("ButtonColor")
static let MeepleP1 = UIColor(named: "MeepleP1")
static let TextButton = Color("ButtonTextColor")
static let MeepleP2 = UIColor(named: "MeepleP2")
static let WinnerBackground = Color("WinnerBackground")
}

@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
"blue" : "0.765",
"green" : "0.855",
"red" : "0.000"
}
},
"idiom" : "universal"

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "0.150",
"red" : "0.150"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "0.150",
"red" : "0.150"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.800",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

@ -6,20 +6,23 @@
//
import SwiftUI
import DouShouQiModel
struct TopGameBoard: View {
@ObservedObject var gameVM: PlayingGameVM
var body: some View {
VStack {
HStack {
Circle()
.fill(Color.white)
.frame(width: 40, height: 40)
Text("Player 1 Turn")
Text("\(gameVM.currentPlayerName)'s Turn")
.font(.title)
.foregroundColor(.white)
}
.padding()
.background(Color.red)
.background(Color(gameVM.currentPlayerColor))
.cornerRadius(10)
Spacer().frame(height: 20)
@ -37,14 +40,14 @@ struct TopGameBoard: View {
Spacer()
HStack {
Text("Last moove :")
Text("Last move :")
.font(.title2)
.foregroundColor(.black)
/*Image(systemName: "cheetah")
.resizable()
.frame(width: 30, height: 30)*/
Text("🦁")
Text("2.3")
Text(gameVM.lastPieceMoved)
Text(gameVM.lastMove)
.font(.title2)
.foregroundColor(.black)
}
@ -60,8 +63,8 @@ struct TopGameBoard: View {
}
}
struct TopGameBoard_Previews: PreviewProvider {
static var previews: some View {
TopGameBoard()
}
}
//struct TopGameBoard_Previews: PreviewProvider {
// static var previews: some View {
// TopGameBoard(gameVM: vm)
// }
//}

@ -6,43 +6,43 @@
//
import Foundation
import SwiftUI
import SpriteKit
import DouShouQiModel
class GameScene : SKScene {
var player1: HumanPlayer = HumanPlayer(withName: "Rémi", andId: .player1)!
var player2: HumanPlayer = HumanPlayer(withName: "Rayhan", andId: .player2)!
var player1: DouShouQiModel.Player?
var player2: DouShouQiModel.Player?
var game: Game
var game: Game?
let pieces: [Owner : [Animal:SpriteMeeple]] = [
.player1: [
.rat: SpriteMeeple(imageNamed: AppImages.Rat, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!),
.cat: SpriteMeeple(imageNamed: AppImages.Cat, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!),
.dog: SpriteMeeple(imageNamed: AppImages.Dog, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!),
.wolf: SpriteMeeple(imageNamed: AppImages.Wolf, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!),
.leopard: SpriteMeeple(imageNamed: AppImages.Leopard, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!),
.lion: SpriteMeeple(imageNamed: AppImages.Lion, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!),
.tiger: SpriteMeeple(imageNamed: AppImages.Tigger, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!),
.elephant: SpriteMeeple(imageNamed: AppImages.Elephant, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!),
.rat: SpriteMeeple(imageNamed: AppImages.Rat, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!, imageRotation: 180),
.cat: SpriteMeeple(imageNamed: AppImages.Cat, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!, imageRotation: 180),
.dog: SpriteMeeple(imageNamed: AppImages.Dog, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!, imageRotation: 180),
.wolf: SpriteMeeple(imageNamed: AppImages.Wolf, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!, imageRotation: 180),
.leopard: SpriteMeeple(imageNamed: AppImages.Leopard, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!, imageRotation: 180),
.lion: SpriteMeeple(imageNamed: AppImages.Lion, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!, imageRotation: 180),
.tiger: SpriteMeeple(imageNamed: AppImages.Tigger, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!, imageRotation: 180),
.elephant: SpriteMeeple(imageNamed: AppImages.Elephant, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP1!, imageRotation: 180),
],
.player2: [
.rat: SpriteMeeple(imageNamed: AppImages.Rat, size: CGSize(width: 100, height: 100), backgroundColor: .blue, imageRotation: 180),
.cat: SpriteMeeple(imageNamed: AppImages.Cat, size: CGSize(width: 100, height: 100), backgroundColor: .blue, imageRotation: 180),
.dog: SpriteMeeple(imageNamed: AppImages.Dog, size: CGSize(width: 100, height: 100), backgroundColor: .blue, imageRotation: 180),
.wolf: SpriteMeeple(imageNamed: AppImages.Wolf, size: CGSize(width: 100, height: 100), backgroundColor: .blue, imageRotation: 180),
.leopard: SpriteMeeple(imageNamed: AppImages.Leopard, size: CGSize(width: 100, height: 100), backgroundColor: .blue, imageRotation: 180),
.lion: SpriteMeeple(imageNamed: AppImages.Lion, size: CGSize(width: 100, height: 100), backgroundColor: .blue, imageRotation: 180),
.tiger: SpriteMeeple(imageNamed: AppImages.Tigger, size: CGSize(width: 100, height: 100), backgroundColor: .blue, imageRotation: 180),
.elephant: SpriteMeeple(imageNamed: AppImages.Elephant, size: CGSize(width: 100, height: 100), backgroundColor: .blue, imageRotation: 180),
.rat: SpriteMeeple(imageNamed: AppImages.Rat, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP2!),
.cat: SpriteMeeple(imageNamed: AppImages.Cat, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP2!),
.dog: SpriteMeeple(imageNamed: AppImages.Dog, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP2!),
.wolf: SpriteMeeple(imageNamed: AppImages.Wolf, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP2!),
.leopard: SpriteMeeple(imageNamed: AppImages.Leopard, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP2!),
.lion: SpriteMeeple(imageNamed: AppImages.Lion, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP2!),
.tiger: SpriteMeeple(imageNamed: AppImages.Tigger, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP2!),
.elephant: SpriteMeeple(imageNamed: AppImages.Elephant, size: CGSize(width: 100, height: 100), backgroundColor: Colors.MeepleP2!),
],
]
let imageBoard: SKSpriteNode = SKSpriteNode(imageNamed: AppImages.boardGame)
override init(size: CGSize) {
game = try! Game(withRules: ClassicRules(), andPlayer1: player1, andPlayer2: player2)
super.init(size: size)
imageBoard.size = size
//self.scaleMode = .aspectFit
@ -50,48 +50,41 @@ class GameScene : SKScene {
self.backgroundColor = .white
self.addChild(imageBoard)
}
convenience init(size: CGSize, gameVM: PlayingGameVM) {
self.init(size: size)
self.game = gameVM.game
self.player1 = self.game?.players[.player1]
self.player2 = self.game?.players[.player2]
for piece in pieces.flatMap({owner, pieces in pieces.values}) {
self.addChild(piece)
//piece.setOnMove(onMove: onMeepleMove)
piece.setOnMove(onMove: gameVM.onMeepleMove)
}
initializeBoard(game.board)
initializeBoard(game!.board)
gameVM.game.addPieceRemovedListener { _, _, piece in
self.pieces[piece.owner]![piece.animal]?.removeFromParent()
}
gameVM.start()
}
func initializeBoard(_ board: Board) {
for (lineIndex, currentLine) in game.board.grid.enumerated() {
for (lineIndex, currentLine) in game!.board.grid.enumerated() {
for (cellIndex, currentCell) in currentLine.enumerated() {
if let piece = currentCell.piece {
pieces[piece.owner]?[piece.animal]?.cellPosition = CGPoint(x: cellIndex-3, y: lineIndex-4)
pieces[piece.owner]?[piece.animal]?.cellPosition = CGPoint(x: cellIndex, y: lineIndex)
pieces[piece.owner]?[piece.animal]?.cellPosition = CGPoint(x: 0, y: 0)
print("line :", lineIndex, " cologne: ", cellIndex)
}
}
}
}
required init?(coder aDecoder: NSCoder) {
game = try! Game(withRules: ClassicRules(), andPlayer1: player1, andPlayer2: player2)
game = try! Game(withRules: ClassicRules(), andPlayer1: DouShouQiModel.Player(withName: "P1", andId: .player1)!, andPlayer2: DouShouQiModel.Player(withName: "P2", andId: .player2)!)
super.init(coder: aDecoder);
}
func onMeepleMove(_ start: CGPoint, _ end: CGPoint) async {
let owner = game.rules.getNextPlayer()
let player = game.players[owner]
let move = Move(of: owner, fromRow: Int(start.x), andFromColumn: Int(start.y), toRow: Int(end.x), andToColumn: Int(end.y))
print("Meeple moved")
try! await (player as! HumanPlayer).chooseMove(move)
}
public func start() async throws {
try await game.start()
}
}

@ -10,8 +10,8 @@ import SpriteKit
class SpriteMeeple : SKNode {
static let offset = CGPoint(x: 0, y: 0)
static let direction = CGVector(dx: 100, dy: 100)
static let offset = CGPoint(x: -300, y: 400)
static let direction = CGVector(dx: 100, dy: -100)
let imageNode : SKSpriteNode
var ellipseNode : SKShapeNode
@ -19,15 +19,21 @@ class SpriteMeeple : SKNode {
var originalSize: CGSize
var originalEllipseSize: CGSize
var onMove: ((CGPoint, CGPoint) async -> ())?
var onMove: ((SpriteMeeple, CGPoint, CGPoint) -> ())?
var cellPosition: CGPoint{
didSet(cellPosition){
self.position.x = SpriteMeeple.offset.x + SpriteMeeple.direction.dx*cellPosition.x
self.position.y = SpriteMeeple.offset.y + SpriteMeeple.direction.dx*cellPosition.y
self.position.y = SpriteMeeple.offset.y + SpriteMeeple.direction.dy*cellPosition.y
}
}
private var oldCellPosition: CGPoint?
func getCellPosition() -> CGPoint {
return CGPoint(x: Int((self.position.x - SpriteMeeple.offset.x)/SpriteMeeple.direction.dx), y: Int((self.position.y - SpriteMeeple.offset.y)/SpriteMeeple.direction.dy))
}
init(imageNamed imageName: String, size: CGSize, backgroundColor: UIColor, imageRotation : Double = 0){
imageNode = SKSpriteNode(imageNamed: imageName)
originalSize = CGSize(width: 80, height: 65)
@ -59,7 +65,7 @@ class SpriteMeeple : SKNode {
super.init(coder: aDecoder)
}
public func setOnMove(onMove: @escaping (CGPoint, CGPoint) -> ()) { self.onMove = onMove }
public func setOnMove(onMove: @escaping (SpriteMeeple, CGPoint, CGPoint) -> ()) { self.onMove = onMove }
override var isUserInteractionEnabled: Bool{
set { }
@ -67,6 +73,8 @@ class SpriteMeeple : SKNode {
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){
self.oldCellPosition = getCellPosition()
imageNode.size = CGSize(width: imageNode.size.width * 1.1, height: imageNode.size.height * 1.1)
ellipseNode.path = SKShapeNode(ellipseOf: CGSize(width: originalEllipseSize.width*1.1, height: originalEllipseSize.height*1.1)).path
self.zPosition = 1
@ -88,14 +96,13 @@ class SpriteMeeple : SKNode {
imageNode.size = originalSize
ellipseNode.path = SKShapeNode(ellipseOf: originalEllipseSize).path
if let onMove: (CGPoint, CGPoint) async -> () = onMove {
//onMove(CGPoint(x: 100, y: 100), CGPoint(x: 200, y: 100))
if let onMove: (SpriteMeeple, CGPoint, CGPoint) -> () = onMove {
onMove(self, self.oldCellPosition!, self.getCellPosition())
}
self.zPosition = 0
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?){
self.position = touches.first?.location(in: parent!) ?? CGPoint(x: 0, y: 0)
}

@ -0,0 +1,136 @@
//
// PlayingGameVM.swift
// DouShouQi_App
//
// Created by Rémi REGNAULT on 21/06/2024.
//
import Foundation
import SwiftUI
import DouShouQiModel
class PlayingGameVM: ObservableObject {
// Properties
@Published var game: Game
// Computed properties
public var currentPlayerName: String { game.players[game.rules.getNextPlayer()]?.name ?? (game.rules.getNextPlayer() == .player1 ? "P1" : "P2") }
public var lastMove: String {
if let move: Move = game.rules.historic.last {
return "\(move.columnDestination).\(move.rowDestination)"
}
else {
return ""
}
}
public var lastPieceMoved: String {
if let move: Move = game.rules.historic.last {
return game.board.grid[move.rowDestination][move.columnDestination].piece?.animal.symbol ?? ""
} else {
return ""
}
}
public var currentPlayerColor: UIColor {
return game.rules.getNextPlayer() == .player1 ? Colors.MeepleP1! : Colors.MeepleP2!
}
public var winner: String {
guard self.game.isOver else {
return ""
}
guard let lastMove: Move = self.game.rules.historic.last else {
return ""
}
guard let winner: DouShouQiModel.Player = game.players[lastMove.owner] else {
return ""
}
return winner.name
}
// Inits
init(withGame game: Game) {
self.game = game
}
init?(withRules rules: Rules, andPlayer1 p1: DouShouQiModel.Player, andPlayer2 p2: DouShouQiModel.Player) {
do {
self.game = try Game(withRules: rules, andPlayer1: p1, andPlayer2: p2)
self.game.addInvalidMoveCallbacksListener { _, move, player, result in
if result {
return
}
print("**************************************")
print("⚠️⚠️⚠️⚠️ Invalid Move detected: \(move) by \(player.name) (\(player.id))")
print("**************************************")
}
self.game.addGameOverListener { board, result, player in
switch(result){
case .notFinished:
print("⏳ Game is not over yet!")
case .winner(winner: let o, reason: let r):
print(board)
print("**************************************")
print("Game Over!!!")
print("🥇🏆 and the winner is... \(o == .player1 ? "🟡" : "🔴") \(player?.name ?? "")!")
switch(r){
case .denReached:
print("🪺 the opponent's den has been reached.")
case .noMorePieces:
print("🐭🐱🐯🦁🐘 all the opponent's animals have been eaten...")
case .noMovesLeft:
print("⛔️ the opponent can not move any piece!")
case .tooManyOccurences:
print("🔄 the opponent seem to like this situation... but enough is enough. Sorry...")
default:
print("Reason unknown...")
}
print("**************************************")
default:
break
}
}
} catch {
print("Error")
return nil
}
}
// Customs funcs
func onMeepleMove(_ sender: SpriteMeeple, _ start: CGPoint, _ end: CGPoint) {
let owner = game.rules.getNextPlayer()
let player: DouShouQiModel.Player = game.players[owner]!
let move = Move(of: owner, fromRow: Int(start.y), andFromColumn: Int(start.x), toRow: Int(end.y), andToColumn: Int(end.x))
if (game.rules.isMoveValid(onBoard: game.board, withMove: move)) {
print("Meeple moved = ", start, " -> ", end)
Task {
try! await (player as! HumanPlayer).chooseMove(move)
}
self.objectWillChange.send()
} else {
sender.cellPosition = start
sender.cellPosition = start
}
}
public func start() {
Task {
try await self.game.start()
}
}
}

@ -7,21 +7,53 @@
import SwiftUI
import SpriteKit
import DouShouQiModel
struct GameView: View {
var gameScene: GameScene = GameScene(size: CGSize(width: 700, height: 900))
@StateObject var gameVM: PlayingGameVM
@State private var showHome = false
var body: some View {
VStack {
TopGameBoard().frame(maxHeight: 200)
SpriteView(scene: gameScene)
}
.onAppear {
playSound(named: "Fight")
ZStack {
VStack {
TopGameBoard(gameVM: gameVM).frame(maxHeight: 200)
SpriteView(scene: GameScene(size: CGSize(width: 700, height: 900), gameVM: gameVM))
}
.onAppear {
playSound(named: "Fight")
//MusicPlayer.shared.playBackgroundMusic(music: "GameMusic")
//MusicPlayer.shared.playBackgroundMusic(music: "GameMusic")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
MusicPlayer.shared.playBackgroundMusic(music: "GameMusic")
}
}
.onDisappear {
MusicPlayer.shared.stopBackgroundMusic()
}
if (gameVM.game.isOver) {
HStack {
Spacer()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
MusicPlayer.shared.playBackgroundMusic(music: "GameMusic")
VStack(alignment: .center) {
Text("Game Over")
.font(.title2)
Text("Winner: \(gameVM.winner)")
}
.background(Colors.WinnerBackground)
Spacer()
}
.onAppear {
Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { _ in
// Il faut retourner au home
}
}
}
}
.onDisappear {
@ -31,8 +63,8 @@ struct GameView: View {
}
}
struct GameView_Previews: PreviewProvider {
/*struct GameView_Previews: PreviewProvider {
static var previews: some View {
GameView()
}
}
}*/

@ -7,6 +7,7 @@
import SwiftUI
import SpriteKit
import DouShouQiModel
struct SelectPlayerView: View {
@ -26,8 +27,9 @@ struct SelectPlayerView: View {
HStack {
VStack(alignment: .trailing)
{
MainMenuButton(text: "Start", destination: GameView(), sound: "Start", horizontalAlignment: .trailing, topLeftCorner: 10, bottomLeftCorner: 10)
MainMenuButton(text: "Start", destination: GameView(gameVM: PlayingGameVM(withRules: ClassicRules(), andPlayer1: HumanPlayer(withName: player1.player.name, andId: .player1)!, andPlayer2: HumanPlayer(withName: player2.player.name, andId: .player2)!)!), sound: "Start", horizontalAlignment: .trailing, topLeftCorner: 10, bottomLeftCorner: 10)
MainMenuButton(text: "Settings", destination: ContentView(), sound: "TitleScreenButtonSound", horizontalAlignment: .trailing, topLeftCorner: 10, bottomLeftCorner: 10)
}
}

Loading…
Cancel
Save