質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

1回答

423閲覧

画面をタッチしてリスタートさせたい

tetutaroz

総合スコア12

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2019/05/17 05:57

編集2022/01/12 10:55

前提・実現したいこと

「SpriteKitではじめる2Dゲームプログラミング」という本を読んでiOSゲームを勉強して
いる初心者です。
「HelpNagoyaSpeciality」というサンプルゲームをつくりました。
Swift5の環境で動作することは確認できました。

ただこのサンプルコードでは、ゲームオーバーしたあとのリスタートとするためのコードが
実装されておりません。画面をタッチするだけで簡単にリスタートするように改造したいと
思っていますが、具体的にどうやれば良いのかがわかりません。

実現したいことは、ゲームオーバー後に画面をタッチすると「GAME OVER」や落下してきた
スプライトを消せて、スコアも「0」に戻しリスタートさせたいと思っています。

考え方を含めどのようにすればよいのか具体的な方法を教えてもらえないでしょうか。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

Swift5 import Foundation import SpriteKit class GameScene: SKScene, SKPhysicsContactDelegate { // どんぶり var bowl: SKSpriteNode? // タイマー var timer: Timer? // 落下判定用しシェイプ var lowestShape: SKShapeNode? // スコア用プロパティ var score = 0 var scoreLabel: SKLabelNode? // 名古屋名物ごとのスコア var scoreList = [100, 200, 300, 500, 800, 1000, 1500] override func didMove(to view: SKView) { self.physicsWorld.gravity = CGVector(dx: 0.0, dy: -2.0) self.physicsWorld.contactDelegate = self // 背景スプライトの追加 let background = SKSpriteNode(imageNamed: "background") background.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5) background.size = self.size self.addChild(background) // 落下検知用シェイプノードを追加 let lowestShape = SKShapeNode(rectOf: CGSize(width: self.size.width*3, height: 10)) // 画面外に配置 lowestShape.position = CGPoint(x: self.size.width*0.5, y: -10) // シェイプに合わせてPhysicsBodyを生成 // シェイプの大きさで物理シミュレーションを行う let physicsBody = SKPhysicsBody(rectangleOf: lowestShape.frame.size) // 落下しないよう固定 physicsBody.isDynamic = false // 衝突を検知する対象のビットマスクを指定 // 名古屋名物との衝突を検知する physicsBody.contactTestBitMask = 0x1 << 1 lowestShape.physicsBody = physicsBody self.addChild(lowestShape) self.lowestShape = lowestShape // どんぶりを追加 let bowlTexture = SKTexture(imageNamed: "bowl") let bowl = SKSpriteNode(texture: bowlTexture) bowl.position = CGPoint(x: self.size.width*0.5, y: 100) bowl.size = CGSize(width: bowlTexture.size().width*0.5, height: bowlTexture.size().height*0.5) // テクスチャの不透過部分の形状で物理シミュレーションを行う bowl.physicsBody = SKPhysicsBody(texture: bowlTexture, size: bowl.size) // 落下しないよう固定 bowl.physicsBody?.isDynamic = false self.bowl = bowl self.addChild(bowl) // スコア用ラベル var scoreLabel = SKLabelNode(fontNamed: "Helvetica") scoreLabel.position = CGPoint(x: self.size.width*0.92, y: self.size.height*0.78) scoreLabel.text = "¥0" scoreLabel.fontSize = 32 scoreLabel.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.right // 右寄せ scoreLabel.fontColor = UIColor.green self.addChild(scoreLabel) self.scoreLabel = scoreLabel self.fallNagoyaSpecialty() // タイマーを生成 self.timer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(GameScene.fallNagoyaSpecialty), userInfo: nil, repeats: true) } // 名古屋名物を落下させる @objc func fallNagoyaSpecialty() { // 0〜6のランダムな整数を発生させる let index = Int(arc4random_uniform(7)) // 選択された番号のテクスチャを読み込む let texture = SKTexture(imageNamed: "(index)") // テクスチャからスプライトを生成する let Nagoyasprite = SKSpriteNode(texture: texture) Nagoyasprite.position = CGPoint(x: self.size.width*0.5, y: self.size.height) Nagoyasprite.size = CGSize(width: texture.size().width*0.5, height: texture.size().height*0.5) // テクスチャからPhysicsBodyを追加 Nagoyasprite.physicsBody = SKPhysicsBody(texture: texture, size: Nagoyasprite.size) Nagoyasprite.physicsBody?.contactTestBitMask = 0x1 << 1 // 衝突を検知する対象のビットマスクを指定 self.addChild(Nagoyasprite) // 落下した物に応じてスコアを加算する self.score += self.scoreList[index] // 金額のラベルを更新 self.scoreLabel?.text = "¥(self.score)" } // 衝突が発生したときに呼ばれるメソッド func didBegin(_ contact: SKPhysicsContact) { // 衝突した一方が落下判定用シェイプだったら if contact.bodyA.node == self.lowestShape || contact.bodyB.node == self.lowestShape { // ゲームオーバースプライトを表示 let GameOversprite = SKSpriteNode(imageNamed: "gameover") GameOversprite.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5) self.addChild(GameOversprite) // アクションを停止させる self.isPaused = true // タイマーを止める self.timer?.invalidate() } } // タッチ開始時に呼ばれるメソッド override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { for touch: AnyObject in touches { // シーン上のタッチされた位置を取得する let location = touch.location(in: self) // タッチされた位置にノードを移動させるアクションを作成する let action = SKAction.move(to: location, duration: 0.2) // どんぶりのスプライトでアクションを実行する self.bowl?.run(action) } } // ドラック時 override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) { for touch: AnyObject in touches { let location = touch.location(in: self) let action = SKAction.move(to: location, duration: 0.2) self.bowl?.run(action) } } }

試したこと

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {

この部分にやりたいことをコード化して実装してやればできると思いやってみようとしましたが
具体的な方法がわからずギブアップ状態です。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

考え方を含めどのようにすればよいのか具体的な方法を教えてもらえないでしょうか。

その本が手元にあるわけではないので、具体的な方法を提示することは無理があります。

考え方的には2パターンぐらいがあるのかなと思います。

方法1 シーンをまるごと差し替える

たぶんこっちの方が主流かなと思われます。楽ですし。

swift

1// ※注:擬似コードです 2override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 3 if ゲームオーバー中だったら { 4 if let scene = SKScene(fileNamed: "GameplayScene") { // この行は適当です。とにかく自分と同じシーンを作り直します。 5 self.view?.presentScene(scene) 6 } 7 } else { 8 for touch: AnyObject in touches { 9 // シーン上のタッチされた位置を取得する 10 let location = touch.location(in: self) 11 // タッチされた位置にノードを移動させるアクションを作成する 12 let action = SKAction.move(to: location, duration: 0.2) 13 // どんぶりのスプライトでアクションを実行する 14 self.bowl?.run(action) 15 } 16 } 17}

方法2 頑張って現状から初期状態にあらゆる状態を戻す処理を書く

方法1のシーン差し替えが仕様上うまくいかない場合はこちらになるのかなと。

swift

1// ※注:擬似コードです 2override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 3 if ゲームオーバー中だったら { 4 GAME OVERのスプライトを消す 5 落下してきたスプライトを消す 6 スコアを0にする 7 ゲームを再スタートさせる 8 } else { 9 for touch: AnyObject in touches { 10 // シーン上のタッチされた位置を取得する 11 let location = touch.location(in: self) 12 // タッチされた位置にノードを移動させるアクションを作成する 13 let action = SKAction.move(to: location, duration: 0.2) 14 // どんぶりのスプライトでアクションを実行する 15 self.bowl?.run(action) 16 } 17 } 18}

投稿2019/05/17 06:57

takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tetutaroz

2019/05/18 01:22

早々にアドバイスしていただきましてありがとうございます。 アドバイスしていただいている方法1,2とも「ゲームオーバー中」の判定方法(条件)がわかりません。 方法1のやり方が良いように思いますが、「シーンを丸ごと差し替える」具体的なやり方を教えてもらえないでしょうか。 方法2の「GAME OVERのスプライトを消す」「落下してきたスプライトを消す」は 「GameOversprite.removeFormParent()」「Nagoyasprite.removeFormParent()」でよろしいでしょうか。 ソースコードは全文を載せるように変更しております。申し訳ありませんがよろしくお願いします。
takabosoft

2019/05/20 00:07

> 「ゲームオーバー中」の判定方法(条件)がわかりません。 まずは何でも良いので考えて実験してみてください。
stdio

2019/05/20 02:55 編集

我々はHelpNagoyaSpecialityというゲームを詳しく知らない為、どんな条件になればゲームオーバーになるか分からない。プログラムだけ開示されても困るので、ゲーム画面を見せて下さると回答する側は非常に助かります。
tetutaroz

2019/05/20 13:00

takabosoftさん stdioさん アドバイスありがとうございます。もう少し色々試してから再度質問させてもらうようにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問