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

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

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

SpriteKitは、iOSやOS Xで使用できるApple社製の2Dゲーム開発フレームワークです。

Swift

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

Q&A

解決済

1回答

918閲覧

発射したTimerの消し方について

exampapa

総合スコア13

SpriteKit

SpriteKitは、iOSやOS Xで使用できるApple社製の2Dゲーム開発フレームワークです。

Swift

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

0グッド

0クリップ

投稿2018/03/18 02:46

編集2018/03/18 02:47

SpriteKitでシューティングゲームを作っているのですが、
Timerを使って60秒後に特定の処理(実際はedgeLoopを設定)を
しているのですが、途中30秒後にゲームオーバーとなって別の
Sceneに移行しても、まだそのタイマーが有効なままになってしまい、
エラーが出てしまいます。

自分なりに調べてTimerはランループに登録され、
強参照となっているのでそれをSceneが移行する時に
削除しないといけないといけないようなのですが、タイマーは
リピートなしで発射してる為、gameTimer?.invalidate()では
発射した内容がすでに削除されている(?)ため、削除されないようです。
Timer変数をweakにしたりprivateにしてもダメでした。

根本的にTimerの使い方を理解してないからだと思うのですが、
ご教授いただければ助かります。

class Game8Scene: SKScene, SKPhysicsContactDelegate {
var gameTimer:Timer!
override func didMove(to view: SKView) {
gameTimer = Timer.scheduledTimer( timeInterval: 30.0, target: self, selector: #selector(gameover), userInfo: nil, repeats: false )
gameTimer = Timer.scheduledTimer( timeInterval: 60.0, target: self, selector: #selector(消したい処理), userInfo: nil, repeats: false )
}

@objc func gameover(){
gameTimer?.invalidate()
let scene = GameOverScene(size: self.size)
let skView = self.view as! GameSKView!
skView?.presentScene(scene)
}

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

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

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

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

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

guest

回答1

0

ベストアンサー

gameTimer?.invalidate()で問題ないはずです。
提示されたコードだとgameTimerに2回代入していますが、実際のコードでは消したい処理のタイマーを作成した後に別のタイマーをgameTimerに代入してたりしませんか?
アプリからタイマーを止めないならそれぞれ別の変数にしないといけませんが。

投稿2018/03/18 05:22

toki_td

総合スコア2850

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

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

exampapa

2018/03/18 06:40

toki_td様、ご回答ありがとうございます。 toki_td様のご指摘通り原因は別のタイマーを全てgameTimerという変数に入れていたからでした(これでも動いているので問題ないと思ってました)。 2回目の変数をgameTimer2に変えて、gameTimer2?invalidate()で問題なく削除できました。 本当にありがとうございました。 実はなぜ同じ変数を使っているかというと、 シューティングゲームで敵やテキストをタイマーで時間さで出現させる為に、タイマーを40個程度設置する為に、それらに全てグローバル変数を当て、それらを全て画面切り替えの際にinvalidate()するのは正しいやり方なのかと思っていたからです。 こういう場合良いコードの書き方ってあるんですかね? もし可能であれば追加でご教授いただければ助かります。 いずれにしても私の質問の完全回答をいただきました。 改めてお礼申し上げます。
toki_td

2018/03/18 16:12

各敵の出現時間を個別のタイマーで表しているということですか? それはいずれ破綻すると思います、、、 ゲームの内容によっても作りが変わってくるので例えばですが、各敵が出現するまでの残り時間が100ms単位で入った配列を用意して、100ms間隔のタイマーでそれぞれを減算していき、0になったら出現させてその敵が次回現れる時間にカウンタをリセットする、としてやれば敵の出現を司るタイマーは1つで済みます。 ただ、ゲームを作る場合は本来ならタイマーを使わずにフレームを動かすときに呼ばれるupdate(currentTime:)の前回との間隔で管理したほうがいいと思いますよ。 こちらとか参考になると思います。 https://qiita.com/mochizukikotaro/items/6d3a7e445ea67e5b4643 1秒おきの部分を配列にして個別に管理するイメージです。
exampapa

2018/03/18 17:25

toki_tdさん、追加の回答ありがとうございます。 updateを使って出現時間を管理する方法は目から鱗で本当に勉強になります。 今は個別のタイマーで力技で作っているのですが、次回は教えていただいたやり方で挑戦してみようと思います。 プログラミングは本当に楽しいのですが、selfとかdelegateとか色々十分に理解できない事が多く、今回toki_tdさんに的確なご指導をいただき本当に助かりました。 これからも頑張って勉強していきたいです。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問