iPadのSwift Playgroundsで書いています。
(出来るならSwiftUIだけでやりたいのですが知識が決定的に無い為)
(下記コードでは省略していますが)ランダム機能やシークエンス機能を使いたいが為にSpriteKitをSwiftUIと併用して使っています。
質問事は、
SwiftUI(SecondView)のSegmentedControlで選ばれたタグナンバーに基づいてGameScene(SpriteKit)内のfuncのリピート時間を決定する為、
タグナンバー(もしくはそこから導き出された秒数)をGameScene内の変数に渡したいのですが、どうしたら可能でしょうか。
//iPadOS14、Swift5.3 import PlaygroundSupport import SwiftUI import SpriteKit final class ViewModel: ObservableObject { @Published var mins = 0 } //ややこしくてすみません。SegmentedControlが設置してあるのはContentViewではなく、SecondViewになります。 //ContentViewの記述は無視していただいても問題ない部分です。 struct ContentView: View { let timeText = ["05mins", "10mins", "60mins"] @State var showSecondView = false @ObservedObject var selectedIndex = ViewModel() var body: some View { let width = UIScreen.main.bounds.size.width let height = UIScreen.main.bounds.size.height ZStack { SpriteView(scene: scene) .frame(width: width, height: height) .ignoresSafeArea() VStack { HStack { Text("Exercise Time: (timeText[selectedIndex.mins])") .padding(.trailing, 180) .padding(.bottom, 480) Button(action: { self.showSecondView.toggle() }) { Image(systemName: "gearshape.fill") .font(.system(size: 30)) .padding(.bottom, 480) } } } .sheet(isPresented: self.$showSecondView) { SecondView(isPresent: self.$showSecondView, selectedIndex: self.selectedIndex) } } } } struct SecondView: View { @Binding var isPresent: Bool @ObservedObject var selectedIndex: ViewModel let timeText = ["05mins", "10mins", "60mins"] var body: some View { NavigationView { VStack { // ここのタグナンバー(もしくはそこからSwitch文等を使って秒数に変換した値が入っている変数)をGameScene(SpriteKit)に渡したいです。 Picker(selection: $selectedIndex.mins, label: Text("ExerciseTime")) { Text("05mins").tag(0) Text("10mins").tag(1) Text("60mins").tag(2) } .pickerStyle(SegmentedPickerStyle()) Text("Exercise Time: (timeText[selectedIndex.mins])") .navigationBarTitle("SecondView", displayMode: .inline) .navigationBarItems(trailing: Button(action: {self.isPresent = false}) { Text("Done") }) } } } } //長ったらしくて本当に申し訳ありません。 //質問はこの中のexcTimeにSecondViewのSegmentedControlで選ばれたタグナンバーに応じて秒数(Double型)を渡したいというものなので、それ以外の細かい部分は無視可能です。 var scene: SKScene { let scene = GameScene() let width = UIScreen.main.bounds.size.width let height = UIScreen.main.bounds.size.height scene.size = CGSize(width: width, height: height) scene.scaleMode = .aspectFit return scene } class GameScene: SKScene { var playMode = false let tones = ["C4"] // 本当はもっと長いリストです。コードを単純化する為にC4だけにしてあります。 var Icon: SKSpriteNode! var c4: SKAudioNode! @ObservedObject var selectedIndex = ViewModel() var excTime: Double = 10 // このexcTimeにSecondViewのSegmentedControlで選択した時間(秒数に変換したもの)を渡したいです。 var playIcon = "play.fill" let soundKey = "RemoveSoundKey" //"play.fill"と"pause.fill"の切り替えfunc func icon() { if playMode == false { playIcon = "play.fill" } else { playIcon = "pause.fill" } //長ったらしくてすみません。SF SymbolをSpriteKitで無理やり表示する為のコードなのでここは無視可能です。 let image = UIImage(systemName: playIcon)!.withTintColor(.white) let data = image.pngData() let newImage = UIImage(data: data!) let texture = SKTexture(image: newImage!) Icon = SKSpriteNode.init(texture: texture) Icon.position = CGPoint(x: self.frame.midX, y: 250) Icon.size = CGSize(width: 50, height: 50) Icon.name = "playModeIcon" self.addChild(Icon) } override public func didMove(to view: SKView) { //iPadで作っているのでカラーコードが変ですみません。無視可能な部分です。 backgroundColor = colorLiteral(red: 0.21568629145622253, green: 0.10196079313755035, blue: 0.5803921818733215, alpha: 1.0) icon() } override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?){ for touch: AnyObject in touches { let location = touch.location(in: self) let touchedNode = self.atPoint(location) if let name = touchedNode.name { if name == "playModeIcon" { if playMode == false { playMode = true touchedNode.removeFromParent() icon() //一定時間プレイしたらImage(SF Symbol)を変更して音を止めるfunc var prevTime = Date() func restart() { var currentTime = Date().timeIntervalSince(prevTime) if currentTime < excTime { // ここのexcTime変数にSecondViewのSegmentedControlで選択した時間(秒数に変換したもの)を渡したいです。今は仮として「10(秒)」が入っており、10秒固定ならプログラム自体はうまく作動しております。 print(currentTime) } else { playMode = false Icon.removeFromParent() removeAllActions() icon() } } //play c4 tone let c4URL = Bundle.main.url(forResource: tones[0], withExtension: "aiff")! c4 = SKAudioNode(url: c4URL) c4.autoplayLooped = false self.addChild(c4) //SKActions let c4Play = SKAction.run { [self] in c4.run(SKAction.play()) } let wait15 = SKAction.wait(forDuration: 1.5) let rfp = SKAction.removeFromParent() let reStart = SKAction.run(restart) let seq = SKAction.sequence([c4Play, rfp, wait15, reStart, wait15]) let rep = SKAction.repeatForever(seq) // ここのrepeatForeverを止める為の時間(秒)をSecondViewのSegmentedControlで選択する感じです。 self.run(rep, withKey: soundKey) } else { playMode = false touchedNode.removeFromParent() icon() self.removeAction(forKey: soundKey) } } } } } } PlaygroundPage.current.setLiveView(ContentView())
回答1件
あなたの回答
tips
プレビュー