diff --git a/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/activity-touchToSelect-one_right_answer-image.yml b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/activity-touchToSelect-one_right_answer-image.yml new file mode 100644 index 0000000000..3c78464f14 --- /dev/null +++ b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/activity-touchToSelect-one_right_answer-image.yml @@ -0,0 +1,99 @@ +# Leka - iOS Monorepo +# Copyright 2023 APF France handicap +# SPDX-License-Identifier: Apache-2.0 + +id: 6be7fcc5e32942d5804ec336ef127d03 +name: Touch To Select - One Right Answer - Image +description: L'objectif est de trouver la bonne image ou des les rassembler par famille +image: activity_image_recognition_1 +sequence: + - exercises: + - instructions: Touche les animaux + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: image-placeholder-animals + type: image + isRightAnswer: true + + - instructions: Touche le portrait + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: image-placeholder-food + type: image + - value: image-placeholder-portrait + type: image + isRightAnswer: true + + - instructions: Touche le paysage + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: image-placeholder-landscape + type: image + isRightAnswer: true + - value: image-placeholder-animals + type: image + - value: image-placeholder-food + type: image + + - instructions: Touche la nourriture + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: image-placeholder-animals + type: image + - value: image-placeholder-portrait + type: image + - value: image-placeholder-food + type: image + isRightAnswer: true + - value: image-placeholder-landscape + type: image + + - instructions: Touche les animaux + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: image-placeholder-animals + type: image + - value: image-placeholder-food + type: image + isRightAnswer: true + - value: image-placeholder-landscape + type: image + - value: image-placeholder-portrait + type: image + - value: image-placeholder-food + type: image + + - instructions: Touche le portrait + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: image-placeholder-animals + type: image + - value: image-placeholder-food + type: image + - value: image-placeholder-landscape + type: image + - value: image-placeholder-food + type: image + - value: image-placeholder-portrait + type: image + isRightAnswer: true + - value: image-placeholder-animals + type: image diff --git a/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/activity-touchToSelect-one_right_answer-mixed.yml b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/activity-touchToSelect-one_right_answer-mixed.yml new file mode 100644 index 0000000000..4e1c92131f --- /dev/null +++ b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/activity-touchToSelect-one_right_answer-mixed.yml @@ -0,0 +1,57 @@ +# Leka - iOS Monorepo +# Copyright 2023 APF France handicap +# SPDX-License-Identifier: Apache-2.0 + +id: 9a5431d4a5084ce4abc48109f90b8504 +name: Touch To Select - One Right Answer - Mixed +description: L'objectif est de trouver la bonne réponse ou des les rassembler par famille +image: activity_mixed_recognition_1 +sequence: + - exercises: + - instructions: Touche l'image + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: image-placeholder-food + type: image + isRightAnswer: true + - value: blue + type: color + + - instructions: Touche les images + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: blue + type: color + isRightAnswer: true + - value: image-placeholder-animals + type: image + - value: green + type: color + - value: image-placeholder-portrait + type: image + isRightAnswer: true + + - instructions: Touche toutes les items + type: selection + interface: touchToSelect + gameplay: selectAllRightAnswers + payload: + choices: + - value: blue + type: color + isRightAnswer: true + - value: image-placeholder-food + type: image + isRightAnswer: true + - value: green + type: color + isRightAnswer: true + - value: image-placeholder-landscape + type: image + isRightAnswer: true diff --git a/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-animals.png b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-animals.png new file mode 100644 index 0000000000..e546758794 --- /dev/null +++ b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-animals.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e1f3d2f3d63ede419729a4340e6bd4f67e23e6118dfa794dd30fd532244234e +size 1856400 diff --git a/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-food.png b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-food.png new file mode 100644 index 0000000000..4e6c13466d --- /dev/null +++ b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-food.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53ca4c75dccf79ea995718215b1eeceaeb928ef2ad28f705fcb5ea7412459fd3 +size 1680867 diff --git a/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-landscape.png b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-landscape.png new file mode 100644 index 0000000000..a32a2b479b --- /dev/null +++ b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-landscape.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7566c5b44bbe25919e3d6234fad73a294bc172aa3624d97d618efcb640c601a8 +size 1726674 diff --git a/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-portrait.png b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-portrait.png new file mode 100644 index 0000000000..0ea24ea7dd --- /dev/null +++ b/Modules/GameEngineKit/Examples/GameEngineKitExample/Resources/images/image-placeholder-portrait.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bcb53d1833c0e7b3be1656c6246e303b1324bf3ec531a20d7b18422631b8d14 +size 1144695 diff --git a/Modules/GameEngineKit/Examples/GameEngineKitExample/Sources/ContentView.swift b/Modules/GameEngineKit/Examples/GameEngineKitExample/Sources/ContentView.swift index 935d09db95..745810c9b1 100644 --- a/Modules/GameEngineKit/Examples/GameEngineKitExample/Sources/ContentView.swift +++ b/Modules/GameEngineKit/Examples/GameEngineKitExample/Sources/ContentView.swift @@ -12,7 +12,8 @@ let kActivities: [Activity] = [ // ? dragAndDrop: activity-dragAndDrop--- ContentKit.decodeActivity("activity-touchToSelect-one_right_answer-colors"), - // ContentKit.decodeActivity("activity-touchToSelect-one_right_answer-image"), + ContentKit.decodeActivity("activity-touchToSelect-one_right_answer-image"), + ContentKit.decodeActivity("activity-touchToSelect-one_right_answer-mixed"), // ContentKit.decodeActivity("activity-touchToSelect-multipe_right_answers-mixed"), // ContentKit.decodeActivity("activity-touchToSelect-multipe_right_answers-colors"), // ContentKit.decodeActivity("activity-touchToSelect-multipe_right_answers-images"), diff --git a/Modules/GameEngineKit/Sources/_NewSystem/Views/ChoiceImageView.swift b/Modules/GameEngineKit/Sources/_NewSystem/Views/ChoiceImageView.swift new file mode 100644 index 0000000000..ddad467023 --- /dev/null +++ b/Modules/GameEngineKit/Sources/_NewSystem/Views/ChoiceImageView.swift @@ -0,0 +1,117 @@ +// Leka - iOS Monorepo +// Copyright 2023 APF France handicap +// SPDX-License-Identifier: Apache-2.0 + +//import Combine +import ContentKit +import RobotKit +import SwiftUI + +struct ChoiceImageView: View { + + private let image: String + private let size: CGFloat + private let state: GameplayChoiceState + private let kOverLayScaleFactor: CGFloat = 1.08 + + @State private var animationPercent: CGFloat = .zero + @State private var overlayOpacity: CGFloat = .zero + + init(image: String, size: CGFloat, state: GameplayChoiceState = .idle) { + self.image = image + self.size = size + self.state = state + } + + @ViewBuilder + var circle: some View { + if let uiImage = UIImage(named: image) { + Image(uiImage: uiImage) + .resizable() + .aspectRatio(contentMode: .fit) + .frame( + width: size, + height: size + ) + .clipShape(Circle()) + } else { + Text("❌\nImage not found:\n\(image)") + .multilineTextAlignment(.center) + .frame( + width: size, + height: size + ) + .overlay { + Circle() + .stroke(Color.red, lineWidth: 5) + } + } + } + + var body: some View { + switch state { + case .idle: + circle + .onAppear { + withAnimation { + animationPercent = 0.0 + overlayOpacity = 0.0 + } + } + + case .rightAnswer: + circle + .overlay { + RightAnswerFeedback(animationPercent: animationPercent) + .frame( + width: size * kOverLayScaleFactor, + height: size * kOverLayScaleFactor + ) + } + .onAppear { + withAnimation { + animationPercent = 1.0 + } + } + + case .wrongAnswer: + circle + .overlay { + WrongAnswerFeedback(overlayOpacity: overlayOpacity) + .frame( + width: size * kOverLayScaleFactor, + height: size * kOverLayScaleFactor + ) + } + .onAppear { + withAnimation { + overlayOpacity = 0.8 + } + } + } + } + +} + +#Preview { + VStack(spacing: 30) { + HStack(spacing: 50) { + ChoiceImageView(image: "image-placeholder-animals", size: 200) + ChoiceImageView(image: "image-placeholder-missing", size: 200) + } + + HStack(spacing: 50) { + ChoiceImageView(image: "image-placeholder-animals", size: 200) + ChoiceImageView(image: "image-placeholder-animals", size: 200, state: .rightAnswer) + ChoiceImageView(image: "image-placeholder-animals", size: 200, state: .wrongAnswer) + } + + HStack(spacing: 0) { + ChoiceImageView(image: "image-placeholder-animals", size: 200) + ChoiceColorView(color: "blue", size: 200) + + ChoiceImageView(image: "image-placeholder-animals", size: 200, state: .rightAnswer) + ChoiceColorView(color: "blue", size: 200, state: .rightAnswer) + } + } +} diff --git a/Modules/GameEngineKit/Sources/_NewSystem/Views/SelectionChoiceView.swift b/Modules/GameEngineKit/Sources/_NewSystem/Views/SelectionChoiceView.swift index 19af090696..3285be8172 100644 --- a/Modules/GameEngineKit/Sources/_NewSystem/Views/SelectionChoiceView.swift +++ b/Modules/GameEngineKit/Sources/_NewSystem/Views/SelectionChoiceView.swift @@ -25,7 +25,7 @@ struct SelectionChoiceView: View { } var body: some View { - // TODO(@ladislas): Add image and text + // TODO(@ladislas): Add text switch choice.type { case .color: ChoiceColorView(color: choice.value, size: size, state: state) @@ -34,6 +34,13 @@ struct SelectionChoiceView: View { .fill(isTappable ? .clear : .white.opacity(0.6)) ) .animation(.easeOut(duration: 0.3), value: isTappable) + case .image: + ChoiceImageView(image: choice.value, size: size, state: state) + .overlay( + Circle() + .fill(isTappable ? .clear : .white.opacity(0.6)) + ) + .animation(.easeOut(duration: 0.3), value: isTappable) default: Text("ERROR")