ゲームでN秒ごとに何かを発生させる方法は?


8

N秒ごとに何かが発生したいのですが、どうすればよいですか?タイマーを使うかもしれませんが、どうやって?


この方法はより多くの人々にとってより役立つと思うので、私はあなたの質問をより一般的にしました。
MichaelHouse

回答の1つに対するコメントに基づいて、ポスターがタイマービットを探しているのではなく、スプライトフレームを変更する方法を考えています。それは私たちが話しているプラ​​ットフォームにもっと依存しています。とにかく、質問が編集された今、それは彼が本当に求めていることを表していない。Java 2Dは、彼が尋ねようとしている質問にとって重要でした。
プロトタイプ

スプライトを変更して5秒ごとに発生させることは無関係であり、別の質問として尋ねる必要があります。スプライトの変更について新しい質問をしてください。あなたが試したこととそれがうまくいかないことについては必ず含めてください。
MichaelHouse

回答:


14

これに対する一般的なアプローチは、更新ループとデルタ時間を使用することです。

float timerCurrent = 0f;
float timerTotal = 5f;


Update() {
    timerCurrent += deltaTime;
    if(timerCurrent >= timerTotal) {
        //do timer action
        timerCurrent -= timerTotal;
    }
}

これは、deltaTime変数にアクセスできることを前提としています。デルタ時間は、最後のフレームから経過した時間です。多くのエンジンでこれを利用できますが、独自のエンジンの設定についてはこちらをご覧ください


これは、@ Joshの回答のように明示的なタイマーを開始するよりも技術的な意味で望ましいですか?
Jack M

@JackMそれはタイマーの実装に依存します。私がこのように答えた理由は、言語にとらわれず、実装が非常に簡単だからです。
MichaelHouse

1
@JackM:デバッガーの下で実行することも望ましいです。累積されたゲーム時間は、すべてのタイマーが期限切れになり、継続時に即座に発火するのではなく、ブレークポイントに到達すると停止することがあります。
ベンジャクソン

たとえばゲームがフリーズし、ティックが失われる可能性があるため、注意が必要です。したがって、1等一度だけでなく、合格としている指定されたデルタとの各目盛りのためのタイマーのアクションを呼び出すために持っている
クリスチャンIvicevic

この方法は、ティックのカウントに依存せず、デルタ時間に依存します。フレームが非常に長い場合、デルタ時間も非常に長くなります。ただし、多くの場合、デルタ時間を制限することをお勧めします。非常に長いフレームは、物理などに問題を引き起こす可能性があります。この方法は、現在の時間から開始時間を引いたものを使用するよりも優れています。デルタ時間のスパンを制限するときに、ゲームの他の計算とよりよく同期するからです。
MichaelHouse

3

ほとんどの言語ではclock.startTimer()、メインループに入る前に、ある種の関数呼び出しでクロックを開始する必要があります。次に、メインループに入る前に、のような関数を使用して、時刻値を変数に格納する必要がありますtime = clock.getTime()。ステップ時間を変数に格納しますn

あなたのメインループでは、あなたがしたいチェックはの線に沿ったものです

if(time + n <= clock.getTime())
     //do stuff
     time = clock.getTime() //important to assign new time value here

注:どの言語/ライブラリを見ているのかわからないので、これは頭の中で考えた一般的なアルゴリズムにすぎません。ニーズに正確に適合しない場合があります。一部の言語/ライブラリでは時計オブジェクトを作成する必要がありますが、他の言語/ライブラリでは関数を直接呼び出すだけです。

以下のコメントのとおり、使用している言語に応じてスレッドの問題に注意する必要があります。また、格納するためにダブルフロートを使用する必要がありますtime


1
いい答えです。一部の言語(.NETなど)では、タイマーがゲームループとは別のスレッドに実装されているため、スレッドの問題が発生する可能性があります。
ashes999

1
timeゲームの経過時間を保存する場合は、倍精度浮動小数点形式を使用する必要があることにも注意してください。
kevintodisco 2013年

これらは良い点です。答えに追加します。
Josh、

2

他の回答がすでに指摘したように、タイマーの実装は、格納された値を各フレームのでインクリメントし、deltaTimeそれを期待される持続時間と比較することで実行できます。完全を期すために、他の回答と非常によく似たコードを含めます。

float elapsed = 0.0f;
float duration = 4.0f;

void update(float deltaTime) {
    elapsed += deltaTime;
    if (elapsed <= duration) {
        // Run code.
        elapsed = 0.0f;
        // Maybe remove from update loop?
    }
}

扱い方はあなた次第// Run code.です。多分あなたはTimerクラスを持っています、そのインスタンスはdelegate(C#)またはcallback(C ++)を取り、タイマーが切れたときにそれを呼び出します。また、タイマーを一時停止するには、タイマーを更新ループから削除します。

別のアプローチは、タイマーの開始時間をマークし、代わりに経過時間のオンデマンド計算を行うことです:

double startTime = 0.0; // This is a double for a reason, I'll explain below.
bool running = false;

void start() {
    startTime = getTime(); // This is whatever system time call you want to use.
    running = true;
}

double getElapsed() {
    double elapsed = getTime() - startTime;
    return elapsed;
}

このスタイルは、タイマーのユーザーにもう少し制御を与えます。構造自体は、経過時間が特定のポイントに達したときに何をすべきかについては関係ありません。更新さえしていません。ユーザーは、必要なときに経過時間を問い合わせることができます。このパターンには、デバッガーに適さないという残念な副作用があります。プログラムがデバッガーで停止している間、システム時間は継続するため、このようなタイマーはプログラムをステップ実行するときに異なる動作をします。これに対する潜在的な解決策は、システム固有の経過時間を使用してフレームごとに更新されるプログラム固有の経過時間値を維持することです。

特にゲーム開発に関しては、コンピューターでのタイミングの2つの癖が最も重要だと思います。1つ目は浮動小数点精度で、2つ目はネイティブタイマーの解像度です。

2番目の例では、最初の例と同様に、のdouble代わりにタイプを使用したことに注意してください(タイプ名は、使用floatしている言語によって異なります)。これの理由は、2番目の例が合計経過ゲーム時間を格納することです。ゲームを長時間実行し続けると、単精度浮動小数点形式の値は、経過時間正確に測定するには精度が不十分になり、安定性の問題が発生します。最初の例はfloat、大きな期間が予想されない限り、タイプを使用して問題ありません。

逆に、予想される更新時間が十分に短い場合、システム時間の取得方法によっては、実際には最初にそれを達成できない場合があります。タイマーは、多くの場合、実行中のOSのタイマー解像度に依存します。たとえば、Windows 7以下のデフォルトのタイマー解像度は15.6ミリ秒です。つまり、タイマーの解像度を変更しない限り、timeGetTimeまたはなどの関数を使用して達成できる最低のタイマー精度GetTickCountは15.6 msです(それに関連する危険もあります)。

少し長くなりましたが、タイマーを実装するときに注意する必要がある重要な事項です。


はい、しかし、私は今、どのようにそれを行うかですが、スプライトを元に戻し、前向きに変更するにはどうすればよいですか
user2957632

@ user2957632それはあなたの質問が今尋ねていることではありません。より明確にしてください。
kevintodisco 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.