diff --git a/Modules/GameEngineKit/Sources/_NewSystem/Views/DragAndDrop/DragAndDropBaseScene.swift b/Modules/GameEngineKit/Sources/_NewSystem/Views/DragAndDrop/DragAndDropBaseScene.swift index 279e7aaf8a..8d6bc5c8c7 100644 --- a/Modules/GameEngineKit/Sources/_NewSystem/Views/DragAndDrop/DragAndDropBaseScene.swift +++ b/Modules/GameEngineKit/Sources/_NewSystem/Views/DragAndDrop/DragAndDropBaseScene.swift @@ -2,8 +2,8 @@ // Copyright 2023 APF France handicap // SPDX-License-Identifier: Apache-2.0 -import ContentKit import Combine +import ContentKit import SpriteKit import SwiftUI @@ -14,6 +14,7 @@ class DragAndDropBaseScene: SKScene { var dropZoneB: DropZoneDetails? var biggerSide: CGFloat = 130 var selectedNodes: [UITouch: DraggableImageAnswerNode] = [:] + var answerNodes: [DraggableImageAnswerNode] = [] var playedNode: DraggableImageAnswerNode? var dropZoneNodes: [SKSpriteNode] = [] private var spacer: CGFloat = .zero @@ -21,7 +22,9 @@ class DragAndDropBaseScene: SKScene { private var expectedItemsNodes: [String: [SKSpriteNode]] = [:] private var cancellables: Set = [] - init(viewModel: DragAndDropViewViewModel, hints: Bool, dropZoneA: DropZoneDetails, dropZoneB: DropZoneDetails? = nil) { + init( + viewModel: DragAndDropViewViewModel, hints: Bool, dropZoneA: DropZoneDetails, dropZoneB: DropZoneDetails? = nil + ) { self.viewModel = viewModel self.hints = hints self.dropZoneA = dropZoneA @@ -42,7 +45,6 @@ class DragAndDropBaseScene: SKScene { self.removeAllChildren() self.removeAllActions() - setFirstAnswerPosition() if let dropZoneB = dropZoneB { layoutDropZones(dropZones: dropZoneA, dropZoneB) @@ -53,6 +55,13 @@ class DragAndDropBaseScene: SKScene { layoutAnswers() } + func exerciseCompletedBehavior() { + for node in answerNodes { + snapBack(node) + node.isDraggable = false + } + } + func subscribeToChoicesUpdates() { self.viewModel.$choices .receive(on: DispatchQueue.main) @@ -82,6 +91,8 @@ class DragAndDropBaseScene: SKScene { bindNodesToSafeArea([draggableImageAnswerNode, draggableImageShadowNode]) setNextAnswerPosition() + answerNodes.append(draggableImageAnswerNode) + addChild(draggableImageShadowNode) addChild(draggableImageAnswerNode) } @@ -144,26 +155,13 @@ class DragAndDropBaseScene: SKScene { onDropAction(node) if viewModel.exercicesSharedData.state == .completed { DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [self] in - self.reset() + exerciseCompletedBehavior() } } } func wrongAnswerBehavior(_ node: DraggableImageAnswerNode) { - let moveAnimation: SKAction = SKAction.move(to: node.defaultPosition!, duration: 0.25) - .moveAnimation(.easeOut) - let group: DispatchGroup = DispatchGroup() - group.enter() - node.run( - moveAnimation, - completion: { - node.position = node.defaultPosition! - node.zPosition = 10 - group.leave() - }) - group.notify(queue: .main) { - self.onDropAction(node) - } + snapBack(node) } func onDragAnimation(_ node: SKSpriteNode) { @@ -182,6 +180,24 @@ class DragAndDropBaseScene: SKScene { selectedNodes = [:] } + private func snapBack(_ node: DraggableImageAnswerNode) { + let moveAnimation: SKAction = SKAction.move(to: node.defaultPosition!, duration: 0.25) + .moveAnimation(.easeOut) + let group: DispatchGroup = DispatchGroup() + group.enter() + node.scaleForMax(sizeOf: biggerSide) + node.run( + moveAnimation, + completion: { + node.position = node.defaultPosition! + node.zPosition = 10 + group.leave() + }) + group.notify(queue: .main) { + self.onDropAction(node) + } + } + override func didMove(to view: SKView) { self.reset() } @@ -191,7 +207,8 @@ class DragAndDropBaseScene: SKScene { for touch in touches { let location = touch.location(in: self) if let node = self.atPoint(location) as? DraggableImageAnswerNode { - for gameplayChoiceModel in viewModel.choices where node.name == gameplayChoiceModel.choice.value && node.isDraggable { + for gameplayChoiceModel in viewModel.choices + where node.name == gameplayChoiceModel.choice.value && node.isDraggable { selectedNodes[touch] = node onDragAnimation(node) node.zPosition += 100