Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 55 additions & 39 deletions ComputerSolitaire/Animation/WinCelebrationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@ final class WinCelebrationController {
phase == .animating
}

/// `launchPiles` are the piles the cascade erupts from, with `launchTargets`
/// naming each pile's on-board drop target (aligned by index): the four
/// foundations for the build-up variants, the discard for Pyramid.
func beginIfNeededForWin(
foundations: [[Card]],
launchPiles: [[Card]],
launchTargets: [DropTarget],
dropFrames: [DropTarget: DropTargetGeometry],
boardViewportSize: CGSize
) {
guard phase == .idle else { return }
begin(
foundations: foundations,
hiddenFoundationCardIDs: Self.foundationCardIDs(from: foundations),
launchPiles: launchPiles,
launchTargets: launchTargets,
hiddenLaunchCardIDs: Self.launchCardIDs(from: launchPiles),
dropFrames: dropFrames,
boardViewportSize: boardViewportSize
)
Expand All @@ -44,7 +49,8 @@ final class WinCelebrationController {
}

func syncForLoadedGame(
foundations: [[Card]],
launchPiles: [[Card]],
launchTargets: [DropTarget],
isWin: Bool,
dropFrames: [DropTarget: DropTargetGeometry],
boardViewportSize: CGSize
Expand All @@ -53,14 +59,15 @@ final class WinCelebrationController {
cascadeTask = nil
if isWin {
let completedCards = completedStatesForLoadedWin(
foundations: foundations,
launchPiles: launchPiles,
launchTargets: launchTargets,
dropFrames: dropFrames,
boardViewportSize: boardViewportSize
)
cards = completedCards
hiddenFoundationCardIDs = completedCards.isEmpty
? []
: Self.foundationCardIDs(from: foundations)
: Self.launchCardIDs(from: launchPiles)
phase = .completed
} else {
cards = []
Expand All @@ -75,36 +82,27 @@ final class WinCelebrationController {
}

private func begin(
foundations: [[Card]],
hiddenFoundationCardIDs: Set<UUID>,
launchPiles: [[Card]],
launchTargets: [DropTarget],
hiddenLaunchCardIDs: Set<UUID>,
dropFrames: [DropTarget: DropTargetGeometry],
boardViewportSize: CGSize
) {
self.hiddenFoundationCardIDs = hiddenFoundationCardIDs
self.hiddenFoundationCardIDs = hiddenLaunchCardIDs
let boardBounds = CGRect(origin: .zero, size: boardViewportSize)
guard boardBounds.width > 0, boardBounds.height > 0 else {
phase = .completed
return
}

var launchFrames: [Int: CGRect] = [:]
for index in foundations.indices {
if let frame = dropFrames[.foundation(index)]?.snapFrame, frame != .zero {
launchFrames[index] = frame
}
}

let fallbackLaunchFrame = launchFrames[0]
?? launchFrames.values.first
?? CGRect(
x: boardBounds.midX - 50,
y: max(0, boardBounds.height * 0.22 - 72),
width: 100,
height: 145
)
let launchFrames = Self.launchFrames(for: launchTargets, dropFrames: dropFrames)
let fallbackLaunchFrame = Self.fallbackLaunchFrame(
launchFrames: launchFrames,
boardBounds: boardBounds
)

let initialStates = WinCascadeCoordinator.makeInitialStates(
foundations: foundations,
foundations: launchPiles,
foundationFrames: launchFrames,
fallbackLaunchFrame: fallbackLaunchFrame
)
Expand Down Expand Up @@ -146,36 +144,54 @@ final class WinCelebrationController {
phase = .completed
}

private static func foundationCardIDs(from foundations: [[Card]]) -> Set<UUID> {
Set(foundations.flatMap { pile in pile.map(\.id) })
private static func launchCardIDs(from launchPiles: [[Card]]) -> Set<UUID> {
Set(launchPiles.flatMap { pile in pile.map(\.id) })
}

private func completedStatesForLoadedWin(
foundations: [[Card]],
dropFrames: [DropTarget: DropTargetGeometry],
boardViewportSize: CGSize
) -> [WinCascadeCardState] {
let boardBounds = CGRect(origin: .zero, size: boardViewportSize)
guard boardBounds.width > 0, boardBounds.height > 0 else { return [] }

private static func launchFrames(
for launchTargets: [DropTarget],
dropFrames: [DropTarget: DropTargetGeometry]
) -> [Int: CGRect] {
var launchFrames: [Int: CGRect] = [:]
for index in foundations.indices {
if let frame = dropFrames[.foundation(index)]?.snapFrame, frame != .zero {
for (index, target) in launchTargets.enumerated() {
if let frame = dropFrames[target]?.snapFrame, frame != .zero {
launchFrames[index] = frame
}
}
return launchFrames
}

let fallbackLaunchFrame = launchFrames[0]
private static func fallbackLaunchFrame(
launchFrames: [Int: CGRect],
boardBounds: CGRect
) -> CGRect {
launchFrames[0]
?? launchFrames.values.first
?? CGRect(
x: boardBounds.midX - 50,
y: max(0, boardBounds.height * 0.22 - 72),
width: 100,
height: 145
)
}

private func completedStatesForLoadedWin(
launchPiles: [[Card]],
launchTargets: [DropTarget],
dropFrames: [DropTarget: DropTargetGeometry],
boardViewportSize: CGSize
) -> [WinCascadeCardState] {
let boardBounds = CGRect(origin: .zero, size: boardViewportSize)
guard boardBounds.width > 0, boardBounds.height > 0 else { return [] }

let launchFrames = Self.launchFrames(for: launchTargets, dropFrames: dropFrames)
let fallbackLaunchFrame = Self.fallbackLaunchFrame(
launchFrames: launchFrames,
boardBounds: boardBounds
)

return WinCascadeCoordinator.makeCompletedStates(
foundations: foundations,
foundations: launchPiles,
foundationFrames: launchFrames,
fallbackLaunchFrame: fallbackLaunchFrame,
boardBounds: boardBounds
Expand Down
3 changes: 2 additions & 1 deletion ComputerSolitaire/Fixtures/ScreenshotFixtures.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ enum ScreenshotFixtures {
ScreenshotFixture(name: "klondike-draw3", title: "Klondike – Draw 3"),
ScreenshotFixture(name: "freecell", title: "FreeCell – fresh deal"),
ScreenshotFixture(name: "yukon", title: "Yukon – fresh deal"),
ScreenshotFixture(name: "spider", title: "Spider – 2 suits")
ScreenshotFixture(name: "spider", title: "Spider – 2 suits"),
ScreenshotFixture(name: "pyramid", title: "Pyramid – fresh deal")
]

static func payloadFromLaunchArguments() -> SavedGamePayload? {
Expand Down
Loading