├── .gitignore
├── Newton's Notebook.swiftpm
├── .swiftpm
│ └── xcode
│ │ └── package.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── ContentView.swift
├── ContentViewModel.swift
├── GameSceneViewController.swift
├── GameSceneViewRepresentable.swift
├── Item.swift
├── MyApp.swift
├── NodeType.swift
├── Package.swift
├── Resources
│ ├── Media.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ └── スクリーンショット 2023-04-20 3.45.10.png
│ │ ├── Contents.json
│ │ ├── ball.imageset
│ │ │ ├── Contents.json
│ │ │ └── ball2.png
│ │ ├── basket.imageset
│ │ │ ├── Contents.json
│ │ │ └── 名称未設定のアートワーク 2.png
│ │ ├── basketWithApple.imageset
│ │ │ ├── Contents.json
│ │ │ └── 名称未設定のアートワーク 7.png
│ │ ├── fire.imageset
│ │ │ ├── Contents.json
│ │ │ └── fire.png
│ │ ├── items
│ │ │ ├── Contents.json
│ │ │ ├── astronomy.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── アセット 8.png
│ │ │ ├── atom.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── アセット 7.png
│ │ │ ├── electricity.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── アセット 6.png
│ │ │ ├── fluid.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── アセット 3.png
│ │ │ ├── gravity.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── アセット 5.png
│ │ │ ├── magnet.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── アセット 10.png
│ │ │ ├── mechanic.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── アセット 2.png
│ │ │ └── wave.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── アセット 9.png
│ │ ├── note.imageset
│ │ │ ├── Contents.json
│ │ │ └── note.jpg
│ │ ├── sounds
│ │ │ ├── Contents.json
│ │ │ ├── burnSound.dataset
│ │ │ │ ├── Contents.json
│ │ │ │ └── open_bottle_gas_2-43620.mp3
│ │ │ ├── drawingSound.dataset
│ │ │ │ ├── Contents.json
│ │ │ │ └── scribble_short-104286.mp3
│ │ │ ├── goalSound.dataset
│ │ │ │ ├── Contents.json
│ │ │ │ └── success_bell-6776.mp3
│ │ │ └── itemSound.dataset
│ │ │ │ ├── Contents.json
│ │ │ │ └── item.mp3
│ │ ├── stroke.imageset
│ │ │ ├── Contents.json
│ │ │ └── stroke.png
│ │ └── tree.imageset
│ │ │ ├── Contents.json
│ │ │ └── 名称未設定のアートワーク 5.png
│ ├── bounceSound.m4a
│ ├── opening_11.sks
│ ├── opening_12_9.sks
│ ├── stage1_11.sks
│ ├── stage1_12_9.sks
│ ├── stage2_11.sks
│ ├── stage2_12_9.sks
│ ├── stage3_11.sks
│ ├── stage3_12_9.sks
│ ├── stage4_11.sks
│ └── stage4_12_9.sks
├── ResultView.swift
├── RotationModifier.swift
├── SKNodeExtension.swift
├── Stage.swift
├── TopView.swift
└── VisualEffectView.swift
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
40 | # Packages/
41 | # Package.pins
42 | # Package.resolved
43 | # *.xcodeproj
44 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 | .DS_Store
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/ContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import UIKit
3 |
4 | struct ContentView: View {
5 |
6 | @ObservedObject var viewModel: ContentViewModel
7 | @State var orientation = UIDeviceOrientation.unknown
8 |
9 | var body: some View {
10 | NavigationView {
11 | ZStack {
12 | NavigationLink("", destination: ResultView(collectedItems: viewModel.collectedItems), isActive: $viewModel.showResult)
13 | .opacity(0)
14 | GameSceneViewRepresentable(contentViewModel: viewModel)
15 | .ignoresSafeArea()
16 | .layoutPriority(2)
17 | VStack {
18 | HStack {
19 | Spacer()
20 | .frame(maxWidth: 16)
21 | if viewModel.isRightHanded {
22 | playRetryButton
23 | Spacer()
24 | collectedItemView
25 | } else {
26 | collectedItemView
27 | Spacer()
28 | playRetryButton
29 | }
30 | Spacer()
31 | .frame(maxWidth: 16)
32 | }
33 | Spacer()
34 | }
35 | HStack {
36 | Button {
37 | viewModel.showGoalConfirm = false
38 | viewModel.didTapPlay()
39 | } label: {
40 | Image(systemName: "arrow.clockwise")
41 | .resizable()
42 | .aspectRatio(contentMode: .fit)
43 | .frame(width: 80, height: 80)
44 | .fontWeight(.heavy)
45 | .tint(.black)
46 | }
47 | Spacer()
48 | .frame(maxWidth: 40)
49 | Button {
50 | viewModel.showGoalConfirm = false
51 | viewModel.didTapGoNext()
52 | } label: {
53 | Image(systemName: "forward.fill")
54 | .resizable()
55 | .aspectRatio(contentMode: .fit)
56 | .frame(width: 80, height: 80)
57 | .fontWeight(.heavy)
58 | .tint(.black)
59 | }
60 | }
61 | .frame(maxWidth: .infinity, maxHeight: .infinity)
62 | .background {
63 | VisualEffectView(effect: UIBlurEffect(style: .regular))
64 | .ignoresSafeArea()
65 | }
66 | .opacity(viewModel.showGoalConfirm ? 1 : 0)
67 | VStack {
68 | Text("Play this game in landscape mode")
69 | .font(.largeTitle)
70 | Image(systemName: "rotate.right.fill")
71 | .resizable()
72 | .aspectRatio(contentMode: .fit)
73 | .frame(width: 200, height: 200)
74 | }
75 | .frame(maxWidth: .infinity, maxHeight: .infinity)
76 | .background {
77 | VisualEffectView(effect: UIBlurEffect(style: .regular))
78 | }
79 | .opacity(orientation == .landscapeLeft || orientation == .landscapeRight ? 0 : 1)
80 | }
81 | }
82 | .navigationBarBackButtonHidden(true)
83 | .navigationViewStyle(.stack)
84 | .onAppear {
85 | orientation = (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape)! ? .landscapeLeft : .portrait
86 | }
87 | .onRotate { isLandscape in
88 | orientation = isLandscape ? .landscapeLeft : .portrait
89 | }
90 | .preferredColorScheme(.light)
91 | }
92 |
93 | var playRetryButton: some View {
94 | Button {
95 | viewModel.didTapPlay()
96 | } label: {
97 | Image(systemName: viewModel.isReadyToPlay ? "play.fill" : "arrow.clockwise")
98 | .resizable()
99 | .aspectRatio(contentMode: .fill)
100 | .frame(width: 60, height: 60)
101 | .fontWeight(.heavy)
102 | .tint(.black)
103 | .padding()
104 | }
105 | .opacity((viewModel.showGoalConfirm || viewModel.isPlayButtonHidden) ? 0 : 1)
106 | }
107 |
108 | var collectedItemView: some View {
109 | HStack {
110 | ForEach(Item.firstFourItems + Item.lastFourItems, id: \.self) { item in
111 | ZStack {
112 | Image(item.rawValue)
113 | .resizable()
114 | .aspectRatio(contentMode: .fit)
115 | .frame(width: 40, height: 40)
116 | .opacity(viewModel.collectedItems.contains(item) ? 1 : 0)
117 | Image(item.rawValue)
118 | .resizable()
119 | .aspectRatio(contentMode: .fit)
120 | .frame(width: 40, height: 40)
121 | .opacity(0.2)
122 | }
123 | }
124 | }
125 | .padding(16)
126 | .background(
127 | RoundedRectangle(cornerRadius: 16)
128 | .fill(Color.accentColor.opacity(0.2))
129 | )
130 | }
131 | }
132 |
133 | struct ContentView_Previews: PreviewProvider {
134 | static var previews: some View {
135 | ContentView(viewModel: .init(isRightHanded: true))
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/ContentViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentViewModel.swift
3 | // SketchMaze
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/14.
6 | //
7 |
8 | import Foundation
9 | import Combine
10 |
11 | class ContentViewModel: ObservableObject {
12 | @Published var isRightHanded: Bool
13 | @Published var isReadyToPlay = true
14 | @Published var isPlayButtonHidden = false
15 | @Published var showResult = false
16 | @Published var showGoalConfirm = false
17 | let retryAction = PassthroughSubject()
18 | let playAction = PassthroughSubject()
19 | let goNextAction = PassthroughSubject()
20 |
21 | @Published var collectedItems = [Item]()
22 |
23 | init(isRightHanded: Bool) {
24 | self.isRightHanded = isRightHanded
25 | }
26 |
27 | func didTapPlay() {
28 | if isReadyToPlay {
29 | playAction.send()
30 | } else {
31 | retryAction.send()
32 | }
33 | isReadyToPlay.toggle()
34 | }
35 |
36 | func didTapGoNext() {
37 | isReadyToPlay = true
38 | goNextAction.send()
39 | }
40 |
41 | func showResultView() {
42 | showResult = true
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/GameSceneViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // SketchPuzzle
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/12.
6 | //
7 |
8 | import AVFoundation
9 | import UIKit
10 | import PencilKit
11 | import SpriteKit
12 |
13 | class GameSceneViewController: UIViewController, UIPencilInteractionDelegate {
14 |
15 | var coordinator: GameSceneViewRepresentable.Coordinator?
16 |
17 | var canvasView: PKCanvasView!
18 | var skView: SKView!
19 | var currentStage: Stage = .opening
20 | var scene: SKScene!
21 |
22 | var pencilAudioPlayer: AVAudioPlayer!
23 | var itemAudioPlayer: AVAudioPlayer!
24 | var goalAudioPlayer: AVAudioPlayer!
25 | var bounceAudioPlayer: AVAudioPlayer!
26 | var burnAudioPlayer: AVAudioPlayer!
27 |
28 | let blackInk = PKInkingTool(ink: PKInk(.pen, color: .gray), width: 3)
29 |
30 | let bounceAudioNode = SKAudioNode(url: Bundle.main.url(forResource: "bounceSound", withExtension: "m4a")!)
31 | var isPlayingAudio = false
32 | var collectedItems = [Item]()
33 | var newlyCollectedItems = [Item]()
34 |
35 | override func viewDidLoad() {
36 | super.viewDidLoad()
37 | setupSpriteKitView()
38 | setupCanvasView()
39 | setupAudioPlayer()
40 | setupScene(stage: .opening)
41 | }
42 |
43 | func setupAudioPlayer() {
44 | if let pencilSoundDataAsset = NSDataAsset(name: "drawingSound") {
45 | do {
46 | pencilAudioPlayer = try AVAudioPlayer(data: pencilSoundDataAsset.data)
47 | pencilAudioPlayer.numberOfLoops = -1
48 | pencilAudioPlayer.volume = 0.2
49 | pencilAudioPlayer.prepareToPlay()
50 | } catch {
51 | print("Error loading audio file: \(error.localizedDescription)")
52 | }
53 | }
54 |
55 | if let itemSoundDataAsset = NSDataAsset(name: "itemSound") {
56 | do {
57 | itemAudioPlayer = try AVAudioPlayer(data: itemSoundDataAsset.data)
58 | itemAudioPlayer.volume = 0.2
59 | itemAudioPlayer.prepareToPlay()
60 | } catch {
61 | print("Error loading audio file: \(error.localizedDescription)")
62 | }
63 | }
64 |
65 | if let goalSoundDataAsset = NSDataAsset(name: "goalSound") {
66 | do {
67 | goalAudioPlayer = try AVAudioPlayer(data: goalSoundDataAsset.data)
68 | goalAudioPlayer.volume = 0.2
69 | goalAudioPlayer.prepareToPlay()
70 | } catch {
71 | print("Error loading audio file: \(error.localizedDescription)")
72 | }
73 | }
74 |
75 | if let bounceSoundDataAsset = NSDataAsset(name: "bounceSound") {
76 | do {
77 | bounceAudioPlayer = try AVAudioPlayer(data: bounceSoundDataAsset.data)
78 | bounceAudioPlayer.volume = 0.2
79 | bounceAudioPlayer.prepareToPlay()
80 | } catch {
81 | print("Error loading audio file: \(error.localizedDescription)")
82 | }
83 | }
84 |
85 | if let burnSoundDataAsset = NSDataAsset(name: "burnSound") {
86 | do {
87 | burnAudioPlayer = try AVAudioPlayer(data: burnSoundDataAsset.data)
88 | burnAudioPlayer.volume = 0.2
89 | burnAudioPlayer.prepareToPlay()
90 | } catch {
91 | print("Error loading audio file: \(error.localizedDescription)")
92 | }
93 | }
94 | }
95 |
96 | func setupCanvasView() {
97 | canvasView = PKCanvasView(frame: view.bounds)
98 | canvasView.backgroundColor = .clear
99 | canvasView.delegate = self
100 | canvasView.tool = blackInk
101 | canvasView.drawingPolicy = .pencilOnly
102 | canvasView.isUserInteractionEnabled = false
103 | let pencilInteraction = UIPencilInteraction()
104 | pencilInteraction.delegate = self
105 | view.addInteraction(pencilInteraction)
106 | view.addSubview(canvasView)
107 | }
108 |
109 | func setupSpriteKitView() {
110 | skView = SKView(frame: view.bounds)
111 | print(view.frame)
112 | skView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
113 | skView.preferredFramesPerSecond = 120
114 | skView.ignoresSiblingOrder = true
115 | view.addSubview(skView)
116 | }
117 |
118 | func setupScene(stage: Stage, isRetry: Bool = false) {
119 | if scene != nil {
120 | scene.removeFromParent()
121 | }
122 | currentStage = stage
123 | scene = stage.scene(screenFrame: UIScreen.main.nativeBounds)
124 | print(UIScreen.main.nativeBounds)
125 | scene.size = view.bounds.size
126 | scene.scaleMode = .aspectFit
127 | scene.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
128 | scene.delegate = self
129 | scene.physicsWorld.contactDelegate = self
130 | scene.childNode(withName: "background")?.zPosition = -1
131 | [NodeType.fire, NodeType.basket].forEach { nodeType in
132 | scene.enumerateChildNodes(withName: nodeType.name) { node, _ in
133 | guard let texture = (node as? SKSpriteNode)?.texture else { return }
134 | node.physicsBody = SKPhysicsBody(texture: texture, size: node.frame.size)
135 | node.physicsBody?.affectedByGravity = false
136 | node.physicsBody?.isDynamic = false
137 | node.zPosition = 1
138 | node.setup(with: nodeType)
139 | }
140 | }
141 | Item.allCases.forEach { item in
142 | scene.enumerateChildNodes(withName: item.name) { node, _ in
143 | guard let texture = (node as? SKSpriteNode)?.texture else { return }
144 | node.physicsBody = SKPhysicsBody(texture: texture, size: node.frame.size)
145 | node.physicsBody?.affectedByGravity = false
146 | node.physicsBody?.isDynamic = false
147 | node.zPosition = 1
148 | node.setup(with: .item)
149 | let fadeInAction = SKAction.fadeAlpha(to: 0.3, duration: 1.0)
150 | let fadeOutAction = SKAction.fadeAlpha(to: 1.0, duration: 1.0)
151 | let fadeSequence = SKAction.sequence([fadeInAction, fadeOutAction])
152 | let repeatFadeAction = SKAction.repeat(fadeSequence, count: 1)
153 | node.run(repeatFadeAction)
154 |
155 | }
156 | }
157 | setupBall()
158 | setupBounceAudio()
159 | if stage == .opening || isRetry {
160 | skView.presentScene(scene)
161 | } else {
162 | skView.presentScene(scene, transition: .push(with: .up, duration: 2))
163 | coordinator?.setPlayButtonHidden(hidden: true)
164 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
165 | self.canvasView.isUserInteractionEnabled = true
166 | self.coordinator?.setPlayButtonHidden(hidden: false)
167 | }
168 | }
169 | }
170 |
171 | func setupBall() {
172 | guard let ballNode = scene.childNode(withName: NodeType.ball.name) else { return }
173 | ballNode.physicsBody = SKPhysicsBody(circleOfRadius: 20)
174 | ballNode.physicsBody?.affectedByGravity = true
175 | ballNode.physicsBody?.isDynamic = true
176 | ballNode.setup(with: .ball)
177 | ballNode.zPosition = 2
178 | }
179 |
180 | func setupBounceAudio() {
181 | bounceAudioNode.removeFromParent()
182 | bounceAudioNode.autoplayLooped = false
183 | scene.addChild(bounceAudioNode)
184 | }
185 |
186 | func setGravity(enabled: Bool) {
187 | scene.physicsWorld.gravity = CGVector(dx: 0, dy: enabled ? -9.8 : 0)
188 | if currentStage == .opening {
189 | coordinator?.setPlayButtonHidden(hidden: true)
190 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
191 | self.setupNextScene()
192 | self.coordinator?.setReadyToPlay(isReady: true)
193 | }
194 | }
195 | }
196 |
197 | func retry() {
198 | setupScene(stage: currentStage, isRetry: true)
199 | newlyCollectedItems = []
200 | coordinator?.updateCollectedItems(collectedItems: collectedItems + newlyCollectedItems)
201 | print("Collected Items: \(collectedItems)")
202 | canvasView.drawing = PKDrawing()
203 | }
204 | }
205 |
206 | extension GameSceneViewController: SKPhysicsContactDelegate, SKSceneDelegate {
207 | func didBegin(_ contact: SKPhysicsContact) {
208 | guard let nodeA = contact.bodyA.node, let nodeB = contact.bodyB.node else { return }
209 | switch nodeA.name {
210 | case NodeType.line.name:
211 | if !isPlayingAudio {
212 | bounceAudioNode.run(.play())
213 | isPlayingAudio = true
214 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
215 | self.isPlayingAudio = false
216 | }
217 | }
218 | case NodeType.fire.name:
219 | DispatchQueue.global(qos: . userInitiated).async {
220 | self.burnAudioPlayer.currentTime = 0
221 | self.burnAudioPlayer.play()
222 | }
223 | removeBall()
224 | case NodeType.basket.name:
225 | if currentStage == .opening {
226 | nodeB.removeFromParent()
227 | }
228 | goal()
229 | default:
230 | if Item.allCases.map({ $0.name }).contains(nodeA.name) {
231 | getItem(node: nodeA)
232 | }
233 | }
234 | }
235 |
236 | func getItem(node: SKNode) {
237 | node.removeFromParent()
238 | guard let item = Item(rawValue: node.name ?? "") else { return }
239 | newlyCollectedItems.append(item)
240 | coordinator?.updateCollectedItems(collectedItems: collectedItems + newlyCollectedItems)
241 | DispatchQueue.global(qos: .userInitiated).async {
242 | self.itemAudioPlayer.currentTime = 0
243 | self.itemAudioPlayer.play()
244 | }
245 | }
246 |
247 | func goal() {
248 | removeBall()
249 | DispatchQueue.global(qos: .background).async {
250 | self.goalAudioPlayer.currentTime = 0
251 | self.goalAudioPlayer.play()
252 | }
253 | if currentStage != .opening {
254 | coordinator?.showGoalConfirm()
255 | }
256 | }
257 |
258 | func removeBall() {
259 | scene.childNode(withName: NodeType.ball.name)?.removeFromParent()
260 | }
261 |
262 | func setupNextScene() {
263 | collectedItems += newlyCollectedItems
264 | newlyCollectedItems = []
265 | bounceAudioNode.removeFromParent()
266 | guard let nextStage = currentStage.next else {
267 | showResultView()
268 | return
269 | }
270 | canvasView.isUserInteractionEnabled = false
271 | setupScene(stage: nextStage)
272 | }
273 |
274 | func showResultView() {
275 | coordinator?.showResultView()
276 | }
277 | }
278 |
279 | extension GameSceneViewController: PKCanvasViewDelegate {
280 | func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
281 | let lastStrokeIndex = canvasView.drawing.strokes.count - 1
282 | guard lastStrokeIndex >= 0 else { return }
283 | guard let lastStroke = canvasView.drawing.strokes.last else { return }
284 | let canvasViewBounds = canvasView.bounds
285 | DispatchQueue.global(qos: .userInitiated).async {
286 | let image = canvasView.drawing.image(from: canvasViewBounds, scale: UIScreen.main.scale)
287 | let texture = SKTexture(image: image)
288 | let lineNode = SKSpriteNode(texture: texture)
289 | lineNode.position = CGPoint(x: self.scene.frame.midX, y: self.scene.frame.midY)
290 | lineNode.size = canvasViewBounds.size
291 | lineNode.physicsBody = SKPhysicsBody(texture: texture, size: lineNode.size)
292 | lineNode.physicsBody?.isDynamic = false
293 | lineNode.physicsBody?.affectedByGravity = false
294 | lineNode.setup(with: .line)
295 | lineNode.physicsBody?.restitution = self.calculateRestitution(from: lastStroke)
296 | lineNode.zPosition = 1
297 |
298 | DispatchQueue.main.async {
299 | self.scene.addChild(lineNode)
300 | var updatedDrawing = canvasView.drawing
301 | updatedDrawing.strokes.removeAll()
302 | canvasView.drawing = updatedDrawing
303 | self.scene.physicsWorld.speed = 1
304 | }
305 | }
306 | }
307 |
308 | func calculateRestitution(from stroke: PKStroke) -> CGFloat {
309 | let path = stroke.path
310 | let average = path.map({ $0.force }).reduce(0, +) / CGFloat(path.count)
311 | if average > 1.5 {
312 | return 1.5
313 | } else {
314 | return average
315 | }
316 | }
317 |
318 | func canvasViewDidEndUsingTool(_ canvasView: PKCanvasView) {
319 | pencilAudioPlayer.stop()
320 | }
321 |
322 | func canvasViewDidBeginUsingTool(_ canvasView: PKCanvasView) {
323 | self.scene.physicsWorld.speed = 0.3
324 | DispatchQueue.global(qos: .userInitiated).async {
325 | self.pencilAudioPlayer.play()
326 | }
327 | }
328 | }
329 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/GameSceneViewRepresentable.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import Combine
3 |
4 | struct GameSceneViewRepresentable: UIViewControllerRepresentable {
5 | typealias UIViewControllerType = GameSceneViewController
6 |
7 | @ObservedObject var contentViewModel: ContentViewModel
8 |
9 | func makeUIViewController(context: Context) -> GameSceneViewController {
10 | return context.coordinator.viewController
11 | }
12 |
13 | func updateUIViewController(_ uiViewController: GameSceneViewController, context: Context) {
14 | // 何もしない
15 | }
16 |
17 | func makeCoordinator() -> Coordinator {
18 | let viewController = GameSceneViewController()
19 | return Coordinator(contentViewModel: contentViewModel, viewController: viewController)
20 | }
21 |
22 | class Coordinator: NSObject {
23 |
24 | var cancellables = Set()
25 |
26 | var contentViewModel: ContentViewModel
27 | var viewController: GameSceneViewController
28 |
29 | init(contentViewModel: ContentViewModel, viewController: GameSceneViewController) {
30 | self.contentViewModel = contentViewModel
31 | self.viewController = viewController
32 | super.init()
33 | viewController.coordinator = self
34 | subscribeToContentViewModel()
35 | }
36 |
37 | func subscribeToContentViewModel() {
38 | contentViewModel.retryAction.sink { [weak self] _ in
39 | self?.retry()
40 | }.store(in: &cancellables)
41 |
42 | contentViewModel.playAction.sink { [weak self] _ in
43 | self?.applyGravity()
44 | }.store(in: &cancellables)
45 |
46 | contentViewModel.goNextAction.sink { [weak self] _ in
47 | self?.goNext()
48 | }.store(in: &cancellables)
49 | }
50 |
51 | func retry() {
52 | viewController.retry()
53 | }
54 |
55 | func applyGravity() {
56 | viewController.setGravity(enabled: true)
57 | }
58 |
59 | func goNext() {
60 | viewController.setupNextScene()
61 | }
62 |
63 | func showResultView() {
64 | contentViewModel.showResultView()
65 | }
66 |
67 | func showGoalConfirm() {
68 | contentViewModel.showGoalConfirm = true
69 | }
70 |
71 | func setPlayButtonHidden(hidden: Bool) {
72 | contentViewModel.isPlayButtonHidden = hidden
73 | }
74 |
75 | func setReadyToPlay(isReady: Bool) {
76 | contentViewModel.isReadyToPlay = isReady
77 | }
78 |
79 | func updateCollectedItems(collectedItems: [Item]) {
80 | contentViewModel.collectedItems = collectedItems
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Item.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Item.swift
3 | // SketchMaze
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/17.
6 | //
7 |
8 | import Foundation
9 |
10 | enum Item: String, CaseIterable {
11 | case fluid
12 | case magnet
13 | case mechanic
14 | case gravity
15 | case wave
16 | case electricity
17 | case atom
18 | case astronomy
19 |
20 | var name: String {
21 | rawValue
22 | }
23 |
24 | var displayName: String {
25 | switch self {
26 | case .fluid:
27 | return "Fluids"
28 | case .magnet:
29 | return "Magnetism"
30 | case .mechanic:
31 | return "Mechanics"
32 | case .gravity:
33 | return "Gravity"
34 | case .wave:
35 | return "Waves"
36 | case .electricity:
37 | return "Electricity"
38 | case .atom:
39 | return "Atoms"
40 | case .astronomy:
41 | return "Astronomy"
42 | }
43 | }
44 |
45 | var description: String {
46 | switch self {
47 | case .fluid:
48 | return "Fluids, like water or air, can flow and change their shape to fill up any container.\n They are an important part of physics that studies how liquids and gases behave."
49 | case .magnet:
50 | return "Have you ever played with a pair of magnets and felt them attract or repel each other?\nMagnetism is the force behind that, and it's a fascinating area of physics that deals with the behavior of magnets and magnetic materials."
51 | case .mechanic:
52 | return "When you ride a bicycle, mechanics is the part of physics that explains how the wheels, pedals, and gears work together to make you move easily.\nIt's all about understanding motion and the forces involved."
53 | case .gravity:
54 | return " Imagine dropping a ball, and it falls to the ground.\nGravity is the force that pulls the ball and everything else towards the Earth. It's just one aspect of physics that how things interact."
55 | case .wave:
56 | return "Imagine the sound you hear when someone plays a guitar or the way your radio receives signals.\nWaves are a way that energy moves through things like sound, electromagnetic waves (including radio waves), and light.\nThey are an important part of physics that helps us understand how energy travels and interacts with our world."
57 | case .electricity:
58 | return "When you turn on a light or charge your iPhone, electricity powers these devices.\nThis aspect of physics explores the movement of tiny particles called electrons and how they create the energy we use every day."
59 | case .atom:
60 | return "Everything you see and touch is made up of tiny building blocks called atoms.\nThey are part of the branch of physics called atomic physics, which helps us understand how these tiny particles come together to create the world around us."
61 | case .astronomy:
62 | return "When you look at the stars in the night sky, you're seeing just a tiny part of our vast universe.\nAstronomy is the branch of physics that studies outer space and celestial objects, helping us learn more about the cosmos."
63 | }
64 | }
65 |
66 | static var firstFourItems: [Item] {
67 | [.astronomy, .gravity, .magnet, .wave]
68 | }
69 |
70 | static var lastFourItems: [Item] {
71 | [.mechanic, .fluid, .atom, .electricity]
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/MyApp.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import UIKit
3 | import AVFoundation
4 |
5 | @main
6 | struct MyApp: App {
7 |
8 | @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
9 |
10 | var body: some Scene {
11 | WindowGroup {
12 | TopView()
13 | }
14 | }
15 | }
16 |
17 |
18 | class AppDelegate: NSObject, UIApplicationDelegate {
19 |
20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
21 | try! AVAudioSession.sharedInstance().setCategory(.ambient)
22 | try! AVAudioSession.sharedInstance().setActive(true)
23 | return true
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/NodeType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NodeType.swift
3 | // SketchMaze
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/14.
6 | //
7 |
8 | import Foundation
9 | import SpriteKit
10 |
11 | enum NodeType: UInt32 {
12 | case ball = 1
13 | case line = 2
14 | case basket = 4
15 | case fire = 8
16 | case item = 16
17 |
18 | var name: String {
19 | switch self {
20 | case .ball:
21 | return "ball"
22 | case .line:
23 | return "line"
24 | case .basket:
25 | return "basket"
26 | case .fire:
27 | return "fire"
28 | case .item:
29 | return ""
30 | }
31 | }
32 |
33 | var categoryBitMask: UInt32 {
34 | return rawValue
35 | }
36 |
37 | var collisionBitMask: UInt32 {
38 | switch self {
39 | case .ball:
40 | return NodeType.line.categoryBitMask
41 | case .line:
42 | return NodeType.ball.categoryBitMask
43 | case .fire, .basket, .item:
44 | return 0
45 | }
46 | }
47 |
48 | var contactTestBitMask: UInt32 {
49 | switch self {
50 | case .ball:
51 | return NodeType.line.categoryBitMask | NodeType.fire.categoryBitMask | NodeType.basket.categoryBitMask
52 | case .line, .basket, .fire, .item:
53 | return NodeType.ball.categoryBitMask
54 | }
55 | }
56 |
57 | var restitution: CGFloat {
58 | switch self {
59 | case .line:
60 | return 1.0
61 | case .ball:
62 | return 0.2
63 | default:
64 | return 0.2
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.6
2 |
3 | // WARNING:
4 | // This file is automatically generated.
5 | // Do not edit it by hand because the contents will be replaced.
6 |
7 | import PackageDescription
8 | import AppleProductTypes
9 |
10 | let package = Package(
11 | name: "Newton's Notebook",
12 | platforms: [
13 | .iOS("16.0")
14 | ],
15 | products: [
16 | .iOSApplication(
17 | name: "Newton's Notebook",
18 | targets: ["AppModule"],
19 | bundleIdentifier: "com.kyoya.SketchPuzzle",
20 | teamIdentifier: "3X7LEN654Y",
21 | displayVersion: "1.0",
22 | bundleVersion: "1",
23 | appIcon: .asset("AppIcon"),
24 | accentColor: .presetColor(.indigo),
25 | supportedDeviceFamilies: [
26 | .pad
27 | ],
28 | supportedInterfaceOrientations: [
29 | .portrait,
30 | .landscapeRight,
31 | .landscapeLeft,
32 | .portraitUpsideDown(.when(deviceFamilies: [.pad]))
33 | ]
34 | )
35 | ],
36 | targets: [
37 | .executableTarget(
38 | name: "AppModule",
39 | path: ".",
40 | resources: [
41 | .process("Resources")
42 | ]
43 | )
44 | ]
45 | )
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "スクリーンショット 2023-04-20 3.45.10.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/AppIcon.appiconset/スクリーンショット 2023-04-20 3.45.10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/AppIcon.appiconset/スクリーンショット 2023-04-20 3.45.10.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/ball.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "ball2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/ball.imageset/ball2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/ball.imageset/ball2.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/basket.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "名称未設定のアートワーク 2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/basket.imageset/名称未設定のアートワーク 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/basket.imageset/名称未設定のアートワーク 2.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/basketWithApple.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "名称未設定のアートワーク 7.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/basketWithApple.imageset/名称未設定のアートワーク 7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/basketWithApple.imageset/名称未設定のアートワーク 7.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/fire.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "fire.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/fire.imageset/fire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/fire.imageset/fire.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/astronomy.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "アセット 8.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/astronomy.imageset/アセット 8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/astronomy.imageset/アセット 8.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/atom.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "アセット 7.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/atom.imageset/アセット 7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/atom.imageset/アセット 7.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/electricity.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "アセット 6.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/electricity.imageset/アセット 6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/electricity.imageset/アセット 6.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/fluid.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "アセット 3.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/fluid.imageset/アセット 3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/fluid.imageset/アセット 3.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/gravity.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "アセット 5.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/gravity.imageset/アセット 5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/gravity.imageset/アセット 5.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/magnet.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "アセット 10.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/magnet.imageset/アセット 10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/magnet.imageset/アセット 10.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/mechanic.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "アセット 2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/mechanic.imageset/アセット 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/mechanic.imageset/アセット 2.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/wave.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "アセット 9.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/wave.imageset/アセット 9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/items/wave.imageset/アセット 9.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/note.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "note.jpg",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/note.imageset/note.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/note.imageset/note.jpg
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/burnSound.dataset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "data" : [
3 | {
4 | "filename" : "open_bottle_gas_2-43620.mp3",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/burnSound.dataset/open_bottle_gas_2-43620.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/burnSound.dataset/open_bottle_gas_2-43620.mp3
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/drawingSound.dataset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "data" : [
3 | {
4 | "filename" : "scribble_short-104286.mp3",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/drawingSound.dataset/scribble_short-104286.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/drawingSound.dataset/scribble_short-104286.mp3
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/goalSound.dataset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "data" : [
3 | {
4 | "filename" : "success_bell-6776.mp3",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/goalSound.dataset/success_bell-6776.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/goalSound.dataset/success_bell-6776.mp3
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/itemSound.dataset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "data" : [
3 | {
4 | "filename" : "item.mp3",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/itemSound.dataset/item.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/sounds/itemSound.dataset/item.mp3
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/stroke.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "stroke.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/stroke.imageset/stroke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/stroke.imageset/stroke.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/tree.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "名称未設定のアートワーク 5.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/Media.xcassets/tree.imageset/名称未設定のアートワーク 5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/Media.xcassets/tree.imageset/名称未設定のアートワーク 5.png
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/bounceSound.m4a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/bounceSound.m4a
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/opening_11.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/opening_11.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/opening_12_9.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/opening_12_9.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/stage1_11.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/stage1_11.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/stage1_12_9.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/stage1_12_9.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/stage2_11.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/stage2_11.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/stage2_12_9.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/stage2_12_9.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/stage3_11.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/stage3_11.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/stage3_12_9.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/stage3_12_9.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/stage4_11.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/stage4_11.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Resources/stage4_12_9.sks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kyoya1123/Newtons-Notebook/e7815dc257e702fd6582b48177eba7a3baa9cac1/Newton's Notebook.swiftpm/Resources/stage4_12_9.sks
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/ResultView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResultView.swift
3 | // SketchMaze
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/18.
6 | //
7 |
8 | import UIKit
9 | import SwiftUI
10 |
11 | struct ResultView: View {
12 |
13 | var collectedItems: [Item]
14 | @State var selectedItem = Item.atom
15 | @State var showExplanation = false
16 |
17 | var body: some View {
18 | ZStack {
19 | Image("note")
20 | .resizable()
21 | .aspectRatio(contentMode: .fill)
22 | .ignoresSafeArea()
23 | VStack {
24 | Text("🎉 You've collected all of the fallen apples!! 🎉")
25 | .font(.largeTitle)
26 | .bold()
27 | Image("basketWithApple")
28 | .resizable()
29 | .aspectRatio(contentMode: .fit)
30 | .frame(width: 200, height: 200)
31 | Spacer()
32 | .frame(maxHeight: 50)
33 | Text("Learn more about physics")
34 | .font(.title)
35 | .bold()
36 | VStack(spacing: 8) {
37 | HStack(spacing: 8) {
38 | ForEach(Item.firstFourItems, id: \.self) { item in
39 | ZStack {
40 | Button {
41 | withAnimation(.easeOut(duration: 0.2)) {
42 | selectedItem = item
43 | showExplanation = true
44 | }
45 | } label: {
46 | Image(item.rawValue)
47 | .resizable()
48 | .aspectRatio(contentMode: .fit)
49 | .frame(width: 80, height: 80)
50 | }
51 | .opacity(collectedItems.contains(item) ? 1 : 0)
52 | Image(item.rawValue)
53 | .resizable()
54 | .aspectRatio(contentMode: .fit)
55 | .frame(width: 80, height: 80)
56 | .opacity(0.2)
57 | }
58 | }
59 | }
60 | HStack(spacing: 8) {
61 | ForEach(Item.lastFourItems, id: \.self) { item in
62 | ZStack {
63 | Button {
64 | withAnimation(.easeOut(duration: 0.2)) {
65 | selectedItem = item
66 | showExplanation = true
67 | }
68 | } label: {
69 | Image(item.rawValue)
70 | .resizable()
71 | .aspectRatio(contentMode: .fit)
72 | .frame(width: 80, height: 80)
73 | }
74 | .opacity(collectedItems.contains(item) ? 1 : 0)
75 | Image(item.rawValue)
76 | .resizable()
77 | .aspectRatio(contentMode: .fit)
78 | .frame(width: 80, height: 80)
79 | .opacity(0.2)
80 | }
81 | }
82 | }
83 | }
84 | .padding(32)
85 | .background(
86 | RoundedRectangle(cornerRadius: 32)
87 | .fill(Color.accentColor.opacity(0.2))
88 | )
89 | }
90 | HStack {
91 | Spacer(minLength: 200)
92 | VStack(spacing: 32) {
93 | Image(selectedItem.name)
94 | .resizable()
95 | .aspectRatio(contentMode: .fit)
96 | .frame(width: 200, height: 200)
97 | Text(selectedItem.displayName)
98 | .font(.title)
99 | .bold()
100 | Text(selectedItem.description)
101 | .font(.title2)
102 | }
103 | Spacer(minLength: 200)
104 | }
105 | .frame(maxWidth: .infinity, maxHeight: .infinity)
106 | .background(
107 | VisualEffectView(effect: UIBlurEffect(style: .regular))
108 | .ignoresSafeArea()
109 | )
110 | .onTapGesture {
111 | withAnimation(.easeOut(duration: 0.2)) {
112 | showExplanation = false
113 | }
114 | }
115 | .opacity(showExplanation ? 1 : 0)
116 | }
117 | .navigationBarBackButtonHidden(true)
118 | .preferredColorScheme(.light)
119 | }
120 | }
121 |
122 | struct ResultView_Previews: PreviewProvider {
123 | static var previews: some View {
124 | ResultView(collectedItems: [.magnet, .astronomy])
125 | }
126 | }
127 |
128 |
129 | struct NavigationUtil {
130 | static func popToRootView() {
131 | DispatchQueue.main.asyncAfter(deadline: .now()) {
132 | findNavigationController(viewController:
133 | UIApplication.shared.windows.filter { $0.isKeyWindow
134 | }.first?.rootViewController)?
135 | .popToRootViewController(animated: true)
136 | }
137 | }
138 | static func findNavigationController(viewController: UIViewController?)
139 | -> UINavigationController? {
140 | guard let viewController = viewController else {
141 | return nil
142 | }
143 | if let navigationController = viewController as? UINavigationController
144 | {
145 | return navigationController
146 | }
147 | for childViewController in viewController.children {
148 | return findNavigationController(viewController:
149 | childViewController)
150 | }
151 | return nil
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/RotationModifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RotationModifier.swift
3 | // SketchMaze
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/19.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct DeviceRotationViewModifier: ViewModifier {
11 | let action: (Bool) -> Void
12 |
13 | func body(content: Content) -> some View {
14 | content
15 | .onAppear()
16 | .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
17 | action((UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape)!)
18 | }
19 | }
20 | }
21 |
22 | // A View wrapper to make the modifier easier to use
23 | extension View {
24 | func onRotate(perform action: @escaping (Bool) -> Void) -> some View {
25 | self.modifier(DeviceRotationViewModifier(action: action))
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/SKNodeExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SCNNodeExtension.swift
3 | // SketchMaze
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/14.
6 | //
7 |
8 | import SpriteKit
9 |
10 | extension SKNode {
11 | func setup(with nodeType: NodeType) {
12 | if nodeType != .item {
13 | name = nodeType.name
14 | }
15 | physicsBody?.categoryBitMask = nodeType.categoryBitMask
16 | physicsBody?.collisionBitMask = nodeType.collisionBitMask
17 | physicsBody?.contactTestBitMask = nodeType.contactTestBitMask
18 | physicsBody?.restitution = nodeType.restitution
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/Stage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Stage.swift
3 | // SketchMaze
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/17.
6 | //
7 |
8 | import SpriteKit
9 |
10 | enum Stage: String, CaseIterable {
11 | case opening
12 | case stage1
13 | case stage2
14 | case stage3
15 | case stage4
16 |
17 | func scene(screenFrame: CGRect) -> SKScene {
18 | SKScene(fileNamed: rawValue + (max(screenFrame.width, screenFrame.height) == 2732 ? "_12_9" : "_11") )!
19 | }
20 |
21 | var next: Stage? {
22 | switch self {
23 | case .opening:
24 | return .stage1
25 | case .stage1:
26 | return .stage2
27 | case .stage2:
28 | return .stage3
29 | case .stage3:
30 | return .stage4
31 | case .stage4:
32 | return nil
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/TopView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopView.swift
3 | // SketchMaze
4 | //
5 | // Created by Kyoya Yamaguchi on 2023/04/18.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct TopView: View {
11 |
12 | @State var isRightHanded = true
13 | @State var orientation = UIDeviceOrientation.unknown
14 |
15 | var body: some View {
16 | NavigationView {
17 | ZStack {
18 | Image("note")
19 | .resizable()
20 | .aspectRatio(contentMode: .fill)
21 | .ignoresSafeArea()
22 | VStack {
23 | Text("Welcome to Newton's Notebook!")
24 | .font(.largeTitle)
25 | .bold()
26 | Image("basket")
27 | .resizable()
28 | .aspectRatio(contentMode: .fit)
29 | .frame(width: 200, height: 200)
30 | Spacer()
31 | .frame(maxHeight: 50)
32 | NavigationLink(destination: ContentView(viewModel: .init(isRightHanded: isRightHanded))) {
33 | Text("Play")
34 | .font(.title)
35 | .foregroundColor(.white)
36 | .padding(EdgeInsets(top: 16, leading: 32, bottom: 16, trailing: 32))
37 | .background(Color.accentColor)
38 | .cornerRadius(10)
39 | }
40 | Spacer()
41 | .frame(maxHeight: 32)
42 | Text("Which is your dominant hand?")
43 | .font(.title)
44 | Picker("", selection: $isRightHanded) {
45 | Text("Left")
46 | .tag(false)
47 | Text("Right")
48 | .tag(true)
49 | }
50 | .pickerStyle(.segmented)
51 | .frame(maxWidth: 200)
52 | }
53 | VStack {
54 | Text("Play this game in landscape mode")
55 | .font(.largeTitle)
56 | Image(systemName: "rotate.right.fill")
57 | .resizable()
58 | .aspectRatio(contentMode: .fit)
59 | .frame(width: 200, height: 200)
60 | }
61 | .frame(maxWidth: .infinity, maxHeight: .infinity)
62 | .background {
63 | VisualEffectView(effect: UIBlurEffect(style: .regular))
64 | .ignoresSafeArea()
65 | }
66 | .opacity(orientation == .landscapeLeft || orientation == .landscapeRight ? 0 : 1)
67 | }
68 | }
69 | .navigationViewStyle(.stack)
70 | .onAppear {
71 | orientation = (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape)! ? .landscapeLeft : .portrait
72 | print(UIScreen.main.bounds)
73 | }
74 | .onRotate { isLandscape in
75 | orientation = isLandscape ? .landscapeLeft : .portrait
76 | }
77 | .navigationBarBackButtonHidden(true)
78 | .preferredColorScheme(.light)
79 | }
80 | }
81 |
82 | struct TopView_Previews: PreviewProvider {
83 | static var previews: some View {
84 | TopView()
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Newton's Notebook.swiftpm/VisualEffectView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VisualEffectView.swift
3 | // dragonx
4 | //
5 | // Created by Masakaz Ozaki on 2022/09/15.
6 | //
7 |
8 | import SwiftUI
9 | import UIKit
10 |
11 | struct VisualEffectView: UIViewRepresentable {
12 | var effect: UIVisualEffect?
13 | func makeUIView(context: UIViewRepresentableContext) -> UIVisualEffectView {
14 | UIVisualEffectView()
15 | }
16 | func updateUIView(_ uiView: UIVisualEffectView, context: UIViewRepresentableContext) {
17 | uiView.effect = effect
18 | }
19 | }
20 |
21 | struct VisualEffectView_Previews: PreviewProvider {
22 | static var previews: some View {
23 | VisualEffectView()
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Newton's Notebook
2 |
3 | Swift Student Challenge 2023 application (Accepted!)
4 |
5 |
6 | https://github.com/kyoya1123/Newtons-Notebook/assets/19247234/e7db503d-b5bd-45c5-8733-408a89a0b17e
7 |
8 |
--------------------------------------------------------------------------------