🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

3531閲覧

時間系の処理をUpdateではなくFixedUpdate内でするべきか

BB_

総合スコア1

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/03/31 02:50

編集2021/04/03 10:14

前提・実現したいこと

Update関数にて
ある一定時間入力があればプレイヤーオブジェクトがそれに応じた動作をする(ため攻撃など)
というものを実装したいのですが現在の実装方法が正しいのかが判断つきません。
下記の疑問点について教えていただきたいです。

※詳細は追記をご参照ください。

○現在の仕様
・フレームレートを30に固定
・Update関数内でカウントを取る変数を宣言し1フレームごとに1ずつ加算
(初期化、破棄は別途実装済み)

・上記で宣言した変数を使い時間系の処理を実装(判定等)

○疑問点
・自前のフレーム変数を使い判定しているが
Time.deltaTimeを使用して時間単位で判定するのが適切でしょうか?

・Update関数内で判定を行うと処理落ちしたとき端末により動作に差がでるのではないか
(時間系の処理はFixedUpdateに記載するべきでしょうか? ※FixedUpdateは常に一定のため)

・そもそもUnityで時間を扱う処理を実装するときはFixedUpdateで行うのが一般的でしょうか?

○追記
「フレームレートの固定」
Project SettingsのQualityにてVSync CountをDon't Syncに設定し、
スクリプト内で Application.targetFrameRate = 30; を指定することで固定しています。
処理落ちすることがあるため常に30フレームにはならないという認識です。
また、処理落ちしていない環境では想定通り動作しています。

「プレイヤーオブジェクトと時間系の処理の関係」
例えば溜め攻撃をする際にボタンを押した時点から離した時点の秒数を計測して
規定時間以上なら溜め攻撃、そうでない場合は通常攻撃を出すなどの処理です。
他にもアニメーションの再生時間、ボタン押下から攻撃オブジェクトの生成タイミングなどです。

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

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

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

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

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

sakura_hana

2021/04/02 00:41

まずUnityでフレームレートを完全固定する方法は標準機能としては無いと思うのですがどうやっているのですか?(本当にそれが正常動作しているならそれを使えばいいと思います。その内容を明かさずに「これで正しいですか?」と言われても回答できません) また、「入力があればプレイヤーオブジェクトがそれに応じた動作をする」と「時間系の処理」はどう繋がるのでしょうか? 単純に入力を受け取って何かするだけなら時間を測る必要も無いと思いますが、どういうものを想定しているのかもっと具体的に記載してください。
BB_

2021/04/03 10:08

ご指摘ありがとうございます。 わかりづらくて申し訳ないのですが質問の趣旨としては Unityの仕様的に時間を扱う処理を実装するときにどのような組み方をするのが適切か というものになっています。 ご指摘の内容についての詳細は下記となっております。 「フレームレートの固定」 Project SettingsのQualityにてVSync CountをDon't Syncに設定し、 スクリプト内で Application.targetFrameRate = 30; を指定することで固定しています。 処理落ちすることがあるため常に30フレームにはならないという認識です。 また、処理落ちしていない環境では想定通り動作しています。 「プレイヤーオブジェクトと時間系の処理の関係」 例えば溜め攻撃をする際にボタンを押した時点から離した時点の秒数を計測して 規定時間以上なら溜め攻撃、そうでない場合は通常攻撃を出すなどの処理です。 他にもアニメーションの再生時間、ボタン押下から攻撃オブジェクトの生成タイミングなどです。
moory

2021/04/03 19:27

私なら、stopwatchを使うな…と思ったのですが、updataでカウントする特別な理由などありますでしょうか? また、処理落ちで想定外の動きになってるようですが、どのような想定外が起きているかを書かれた方が、具体的な解決策を回答してもらいやすいのでは?と感じました。 どのようなやり方でやるかはケース・バイ・ケース(=定石がない) な気がするので、定石を尋ねてしまうと回答がつきにくい気もします。
guest

回答1

0

ベストアンサー

自前のフレーム変数を使い判定しているが

Time.deltaTimeを使用して時間単位で判定するのが適切でしょうか?

自前で作る必要はないというかUnityが持っている機能なのでそれを使うのはどうでしょうか?というのが答えです。
Time.deltaTimeがフレームを考慮した時間です。Time.timeScaleの値が1である限りターゲットとするFPS = 1秒になるように前フレームとの経過時間をできる限り正確に返してくれます。

自前で実装する必要はほぼ無いというのが僕の印象ですが、不安な部分があるなら小さなテストシーンを作って期待する動作になるか検証すると良いと思います。

Update関数内で判定を行うと処理落ちしたとき端末により動作に差がでるのではないか

(時間系の処理はFixedUpdateに記載するべきでしょうか? ※FixedUpdateは常に一定のため)

上で話した通りTime.deltaTimeを使う限りほぼ大丈夫です。というか信じる他ありません。
もし00秒である地点に完璧に移動したい時や滑らかに移動したい場合はVector3.Lerpを使うと良いです。モバイル向けなら多用は厳禁ですので注意してください。

FixedUpdateUpdateとまったく違います。Updateは期待するFPS(Application.targetFrameRate)に達するまで出来る限り呼んでくれます。
FixedUpdateはProject Settingsで決めた一定間隔で呼ばれるものです。

それなら一定間隔で呼ばれるFixedUpdateで処理すれば良いと思うかもしれませんが、処理落ちした次のフレームでまた別の処理を呼ばれ処理しきれずフリーズやクラッシュするより、終わるまで少し停止してくれた方が端末に優しいと思いませんか?
なのでUpdateが存在していると思います。

FixedUpdateの呼び出し回数設定
初期値は0.02(FPSで言えば50)
Fixed Timestep

溜め攻撃の実装

溜め攻撃の実装を簡単に書いてみました。
良ければ参考にしてみてください。

C#

1 2using UnityEngine; 3 4public sealed class UserController : MonoBehaviour 5{ 6 /// <summary> 7 /// 何秒押し続ければ溜め攻撃になるか? 8 /// </summary> 9 const float PointerDownDuration = 1f; 10 11 float pointerDownTime; 12 13 void Update() 14 { 15 // 左クリック中は時間を加算 キーの場合はInput.GetButton("キー名"); 16 if (Input.GetMouseButton(0)) 17 { 18 pointerDownTime += Time.deltaTime; 19 } 20 // 左クリックを離したタイミングで攻撃 キーの場合はInput.GetButtonUp("キー名"); 21 else if(Input.GetMouseButtonUp(0)) 22 { 23 // 想定時間経過してれば溜め攻撃 24 if (pointerDownTime >= PointerDownDuration) 25 { 26 ChargeAttack(); 27 } 28 // 想定時間経過していなければ通常攻撃 29 else 30 { 31 Attack(); 32 } 33 pointerDownTime = 0; 34 } 35 } 36 37 /// <summary> 38 /// 通常攻撃 39 /// </summary> 40 void Attack() 41 { 42 Debug.Log("通常攻撃"); 43 } 44 45 /// <summary> 46 /// 溜め攻撃 47 /// </summary> 48 void ChargeAttack() 49 { 50 Debug.Log("溜め攻撃"); 51 } 52} 53

Unirxを使う方法もあります。下記は長押し判定のみです。
もしUnirx使ってなければおすすめですよ。様々な場面で活躍します。

C#

1void Start() 2{ 3 var mouseDownStream = this.UpdateAsObservable().Where(_ => Input.GetMouseButtonDown(0)); 4 var mouseUpStream = this.UpdateAsObservable().Where(_ => Input.GetMouseButtonUp(0)); 5 6 //長押しの判定 7 //マウスクリックされたら3秒後にOnNextを流す 8 mouseDownStream 9 .SelectMany(_ => Observable.Timer(TimeSpan.FromSeconds(3))) 10 //途中でMouseUpされたらストリームをリセット 11 .TakeUntil(mouseUpStream) 12 .RepeatUntilDestroy(this.gameObject) 13 .Subscribe(_ => Debug.Log("長押し")); 14 15}

コードの参照元

投稿2021/04/04 11:04

編集2021/04/04 11:23
IShix

総合スコア1729

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

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

BB_

2024/09/09 06:58

ありがとうございます大変参考になりました! 質問の回答に加え FixedUpdateに頼ることの問題点や Unirxについてまで教えていただきありがとうございます 本当に助かりました あと、年単位で返信できず すみませんでした…
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問