トップページ > 記事閲覧
リプレイとSRandについて
名前:774 日時: 2025/06/13 01:24

SRand()の使い方について伺いたく思います。 シューティングゲーム等のリプレイの実装の際に、SRand()を使ってランダムの初期値を保存して再生に用いると思いますが、 SRand()の仕様について分からず悩んでおります。 今、リプレイを繰り返し流したい(リプレイが終わったら最初からまたリプレイを流したい)と思い、 リプレイ記録:SRand(固定値)宣言→「初期化・ロード(初回)」→「ゲーム(リプレイデータ記録)」→リプレイデータ書き出し リプレイ再生:SRand(固定値)宣言→「初期化・ロード(初回)」→「ゲーム(リプレイデータ再生)」→「デリート」→「初期化・ロード(2週目)」→「ゲーム(リプレイデータ再生)(2週目)」… のループでリプレイを再生しても、初回でのゲームしかリプレイが再現できませんでした、 なので以下のように、 リプレイ記録:「初期化・ロード(初回)・SRand(固定値)宣言」→「ゲーム(リプレイデータ記録)」→リプレイデータ書き出し リプレイ再生:「初期化・ロード(初回)・SRand(固定値)宣言」→「ゲーム(リプレイデータ再生)」→「デリート」→「初期化・ロード(2週目)SRand(固定値)宣言」→「ゲーム(リプレイデータ再生)(2週目)」 に変更してみたのですが、やはり初回しかリプレイが再現しません。 「ゲーム」の中でランダムをオフにすればこのループでリプレイが再現できるので、ランダムの値がループの度に変わってしまっていることが要因だと考えているのですが、 こういった場合、どうやったらSRand()を用いてランダム状態を保存、再生できるのでしょうか。 過去ログでDxLib_Init()の中でSrand(GetNowCount())としていると少しありましたので、 SRand()の仕様と使用方法について、ご教授いただければと思います。
メンテ

Page: 1 |

Re: リプレイとSRandについて ( No.1 )
名前:管理人 日時:2025/06/14 12:48

1.SRand( 123456 ) を呼んだ後、GetRand( 1000000 ) を 10000000回実行して、その戻り値を保存する 2.1をもう一度行って、2つの GetRand 10000000回の結果を比較して一致しているか確認する ↑ こちらのようなテストを行うのが以下のプログラムなのですが #include "DxLib.h" #define TEST_NUM 10000000 int RandResult1[ TEST_NUM ] ; int RandResult2[ TEST_NUM ] ; int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int i ; // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // 乱数を初期化 SRand( 123456 ) ; // 乱数を取得 for( i = 0; i < TEST_NUM; i++ ) { RandResult1[ i ] = GetRand( 1000000 ) ; } // 乱数を初期化 SRand( 123456 ) ; // 乱数を取得 for( i = 0; i < TEST_NUM; i++ ) { RandResult2[ i ] = GetRand( 1000000 ) ; } // 2つの乱数列が一致しているかチェック for( i = 0; i < TEST_NUM; i++ ) { if( RandResult1[ i ] != RandResult2[ i ] ) { break ; } } // 結果を表示 DrawFormatString( 0, 0, GetColor( 255,255,255 ), "%d回の2つの乱数は一致%s", TEST_NUM, i == TEST_NUM ? "しています" : "していません" ) ; // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } 結果は『10000000回の2つの乱数は一致しています』となりました なので、本来であれば SRand を事前に行う > リプレイ記録:「初期化・ロード(初回)・SRand(固定値)宣言」→「ゲーム(リプレイデータ記録)」→リプレイデータ書き出し > リプレイ再生:「初期化・ロード(初回)・SRand(固定値)宣言」→「ゲーム(リプレイデータ再生)」→「デリート」→「初期化・ロード(2週目)SRand(固定値)宣言」→「ゲーム(リプレイデータ再生)(2週目)」 ↑こちらの処理であれば正常にリプレイを再現できるはずです なので、リプレイ処理に関わらない意図しない箇所で GetRand を使用してしまっていないか確認してみてください また、リファレンスには載っていませんがプログラム全体で乱数の情報を共有してしまう SRand, GetRand ではなく、独立した乱数取得を行うための以下の関数がありますので // 乱数ハンドルを作成する( 戻り値 0以外:乱数ハンドル 0:エラー ) DWORD_PTR CreateRandHandle( int Seed = -1 ) ; // 乱数ハンドルを削除する int DeleteRandHandle( DWORD_PTR RandHandle ) ; // 乱数ハンドルの初期値を再設定する int SRandHandle( DWORD_PTR RandHandle, int Seed ) ; // 乱数ハンドルを使用して乱数を取得する( RandMax : 返って来る値の最大値 ) int GetRandHandle( DWORD_PTR RandHandle, int RandMax ) ; リプレイに関わる乱数については上記の関数を使用して取得したほうが確実かと思います 使い方の例 グローバル変数の定義箇所 DWORD_PTR GameRandHandle; ゲーム開始の初期化処理 // 乱数ハンドルを作成 GameRandHandle = CreateRandHandle( 固定値 ); ゲーム中のリプレイ処理に関わる乱数の取得箇所 // GetRandHandle で乱数を取得 int RandNum = GetRandHandle( GameRandHandle, 乱数最大値 ); ゲーム終了( ゲームオーバー後など ) // 乱数ハンドルを削除 DeleteRandHandle( GameRandHandle ); リプレイ開始前の初期化処理 // 乱数ハンドルを作成 GameRandHandle = CreateRandHandle( 固定値 ); リプレイ中の乱数の取得箇所 // GetRandHandle で乱数を取得 int RandNum = GetRandHandle( GameRandHandle, 乱数最大値 ); リプレイ終了 // 乱数ハンドルを削除 DeleteRandHandle( GameRandHandle ); よろしければお試しください m(_ _)m
メンテ
Re: リプレイとSRandについて ( No.2 )
名前:774 日時:2025/06/14 22:01

お手数おかけいたします。 テストプログラムでランダムが保存されることも確認いたしました。 ゲーム内容:Srand(n)→loop→Srand(n)→…で再現しない理由を洗い直してみたいと思います。 原因が判明した後、リプレイに関係する部分にはGetRandHandle()関係を使ってみたいと思います。 ありがとうございます。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存