• ベストアンサー

Delphiでキューを作りたい

Delphi初心者です。ゲームを制作中なのですが、相談に乗って頂けますでしょうか。 プログラムの骨格は、演算→描画の繰り返しなんですが、演算結果を次々と描画ルーチンに渡すと、描画が間に合わなくなったときに破綻してしまいます。 (描画で使っているコンポーネントがクラッシュしてしまう) そこで、演算部で表示させるものを計算しキューに追加していき、CPUのアイドル時間を見つけてはキューから順次取り出して描画、という方法を試したいと思います。 (オーバーフローしたら破棄する) そこで、スタックとかキューを使ったことがないのですが、単純に配列を使って、 1.データを最後尾に加える 2.データを先頭から出し、順次前に詰める 簡単な方法があったら教えて頂きたいと思います。 (それくらい手動でやれと言われそうですね(^_^;) よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • mikiki_7
  • ベストアンサー率100% (2/2)
回答No.3

補足です。 上記ではちょっと説明が足りないようなのでかってに補足させてもらいます 実際のバッファリング処理では 演算の結果 ↓ 描画(描画用のスレッドにてバッファに書き込み) 更新タイミング *作成者指定 ↓ 転送(描画部分のスレッドと同期してる状態が前提) 画面更新 以上のプロセスを経て表示が行なわれます。 これが基本的なバッファリング描画です トリプルバッファリングはこの描画用のバッファが2つになり交互に描画を行なうわけです。 ただ、交互に行なうのでは意味が無いので一部特殊な処理がありますが :-) 前提 演算の結果を描画する場合に転送待ち、描画中のバッファで利用できるバッファが無い時はその回の描画処理をキャンセルする。 演算の結果 ↓ 描画(描画用のスレッドにてバッファに書き込み) 更新タイミング ※画面のリフレッシュレートに併せたかたち ↓ 転送(描画部分のスレッドと同期 ※描画が完了してなければ行なわない。 ↓    この時点で後からの描画処理が完了してるようであればそちらを表示する ↓    後からの描画処理が完了した時点で前のバッファの内容を破棄し描画処理を行なえるように処理) 画面更新 ↓ 描画、転送用のバッファを切り替え 大体こんな感じです ダブルバッファリングですと描画転送が完了してからでないと描画処理が新たに行なえないので物によっては大幅に描画速度が低下します。(フレーム落ちが出ます) トリプルバッファリングですと、描画中に再度描画処理が行なえますのでマシンのパフォーマンスを最大限に発揮できますが、マシンスペックが極端に低いと速度低下が激しくなります。

pythian
質問者

お礼

詳細なご説明、ありがとうございます。簡単そうで実は奥が深いんですね。ゲームプログラミングの専門書で勉強してみたいと思います。まずは簡単なものから始めて、自在にバッファを操れるようになりたいです(自作モノの改良はそれから^^;)。ありがとうございました。

その他の回答 (2)

  • honiyon
  • ベストアンサー率37% (331/872)
回答No.2

こんにちは、honiyonです。  Delphiでしたら、DelphiXを使うと簡単ですよ。  さて、それはさておきキューの実現方法ですが、TStringListクラスはご存じですか?簡単に説明すると、リストボックスみたいに文字列を「リスト」にして保存しておく事の出来るクラスです。(詳しくはヘルプを参照してください)  データが文字列の場合はこれを使えば良いですが、そうでない時は TStringListの抽象クラスにあたる TListをオーバーライドして使えばそんな事も簡単に実現出来ちゃいます。(TListはデータのポインタを保持します)  で、実際の使い方は、 List.Add(Data); で追加して、取り出し時は Data := List[0]; List.Delete(0); こんな感じです。  参考になれば幸いです(..  

pythian
質問者

お礼

なるほど、とても参考になりました。初心者なもので、いまいち直接目に見えないクラスは苦手なもので・・・いろいろと試してみます。ありがとうございました。

  • MarrowG
  • ベストアンサー率53% (41/76)
回答No.1

動きの激しいゲームをコンポーネントだけで作るのはちょっと厳しいかと思いますが…。(^^; 動きの激しいゲームでは以下のようにしているのが普通です。 画面描画用のワークメモリに描画する。 ワークメモリの内容をBITMAPとして画面に一括転送。(WindowsAPIで言えばBitBlt) いわゆるダブルバッファという方法ですが、これだと画面のちらつきが抑えられます。 また画面描画メモリを2つ使用するトリプルバッファという方法もあります。 これは、 1.画面描画用のワークメモリAに描画する。 2.ワークメモリAの内容をBITMAPとして画面に一括転送。 3.画面描画用のワークメモリBに描画する。 4.ワークメモリBの内容をBITMAPとして画面に一括転送。 の繰り返しです。(実際には2と4は1、3終了後に非同期で行うのが普通) これですと、1が間に合わなければ、次に描画するタイミングでは3を行うので、ワークメモリAやBの処理量は半分で済むことになります。 描画コンポーネントで実現するのであれば、ワーク用に2つ、実際の表示用に1つ作成して、上記のようなトリプルバッファ方式を使えば少しはマシになるかと思います。 でも、出来るかどうかわかりませんが…。(汗

pythian
質問者

お礼

単純な描画でそんなに動きは激しくないので、コンポーネントでやっています。自分でバッファリングするほど技量もないもので・・・。(^^; 描画メモリを確保して転送しながらというのは、いつかやってみたいです。もし参考になるページや書籍等ありましたら、教えていただければ幸いです。 もう少し頑張ってみます。ありがとうございました。

関連するQ&A

  • DelphiからHDDを直接読みたいのですが・・

    最終的には数テラの容量があるハードディスクドライブを,Delphi6からWin32APIのSetFilePointerで位置付けて,ReadFileでセクタを直接読み取りたいと思っていますが,現在,125GB辺りでエラーが発生し,以降がのセクタが読めません。(DelphiXEでも同じエラーとなります)  参考にできる日本語のサンプルも乏しく困り果てています。  どなたか,お教えください。  m(_ _)m  よろしくお願いいたします。 【動作環境】 OS:Windows7 (32) professional 言語: Delphi6(personal) 及びDelphi XE メモリ:2GB 対象ドライブ:USB外付けHDD 250GB(1論理ドライブWindows7でフォーマット) 名称:\\.\PHYSICALDRIVE1 CylindersLo : 30401 CylindersHi : 0 TracksPerCylinder : 255 SectorsPerTrack : 63 BytesPerSector: 512 【問題点】 セクタ0からセクタ245127535までは読める様なのですが,1セクタ進めて245127536セクタを読み込もうとすると,SetFilePointerはエラーなしで通過するも,ReadFileでエラーとなってしまいます。 エラーが起きた時のSetFilePointerとReadFileに与えたパラメータは次の通りです。 Stsector : 245,127,536 real ofset: 125,505,298,432 p_hi: 58 p_lo: 951,246,848 p_hiの戻り値: 58 【プログラムのソース】 var DHandle : Thandle; // ハンドル drv_cnt : integer; // 接続ドライブ数 drvname : String; // 扱おうとするドライブの名称 sectorSize: integer; // セクタのサイズ SectorNum : word; // セクタ番号 Max_num : word; // 読み込もうとするバイト数 buf : array[0..4095*2] of byte; // 読み取りデータの格納域 STsector : int64; // 読み込み開始のセクタ番号 //----------------------------------------------------------- function getSector:boolean; // ダイレクト読み取り var dwRet : integer; // Seekのリターンコード dwSize : DWORD; // 読み取ったバイト数 iRet : Boolean; // Readのリターンコード real_ofs : int64; // 読み込もうとする位置(先頭からのバイト数) p_lo : integer; // SetFilePointerで使用するseek相対位置の下位32bit p_hi : integer; // 上位32bit begin result := false; SectorNum := 1; //一度に読むセクタ数 Max_num := SectorNum * SECTORSIZE; // 一度に読むバイト数 // ハンドルの取得 DHandle:=CreateFile(PChar(drvname),GENERIC_READ or GENERIC_WRITE, 0,nil,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0 ); if DHandle = INVALID_HANDLE_VALUE then begin // Openエラー処理 showmessage('open device エラー'); exit; end else begin // real_ofs := STsector * SECTORSIZE; // seek位置をバイト単位で取得 p_hi := real_ofs div 2147483648; // 上位32bitを計算 p_lo := real_ofs mod 2147483648; // 下位32bitを計算 dwRet:= SetFilePointer(DHandle, p_lo, @p_hi, FILE_BEGIN ); // seek if dwRet <> -1 then begin // 1セクタ分をbuf[]へ読み込み iRet := ReadFile(DHandle,buf,Max_num,dwSize,nil); if iRet = False then begin // Readエラー処理 showmessage('Read device エラー'); CloseHandle(DHandle); exit; end // dump_Buf; 読み取ったバッファの16進ダンプルーチン呼び出し end else begin // seekエラー処理 showmessage('Seek エラー'); CloseHandle(DHandle); exit; end; end; CloseHandle(DHandle); result := true; end; ※申し訳ありません,先頭の空白がGooによって自動的に削除されてしまうようです。

  • 自作アプリでアクセス違反が発生して困っています

    プログラムをDelphiで作成しているのですが、実行中に「致命的なエラー」で終了することが多くなりました。 そこで、エラーログを開いてみると、 アプリケーション例外が発生しました: 例外番号: c0000005 (アクセス違反) と言われています。思い当たる節は、単に存在しないアドレスにアクセスをしたとかそういうレベルだとは思うのですが、どうしても場所が特定できません。 (デバッガを積んでいない他人の環境でだけ発生するのです) スタックバックトレースを参照すると、以下のようなものがありました。 ntdll!ZwYieldExecution kernel32!ProcessIdToSessionId ntdll!NtWaitForMultipleObjects kernel32!WaitForMultipleObjects kernel32!lstrcmpiW ntdll!NtReplyWaitReceivePortEx rpcrt4!NdrConformantArrayMemorySize winmm!DriverCallback winmm!waveOutSetVolume ちなみに、MMTimerを使い数値を演算して、ApplicationIdleを見つけて描画を行っている普通の(?)シミュレーションプログラムです。(サウンドとシリアルからの入力も使っています) 詳しくはないのですが、この近辺でコケているということなのでしょうか・・・。

  • Delphi

    Delphi 2010についてお問い合わせ致します。 VB 2008用のSDKがあります。 販売元に問い合わせしたところ Delphiに対応するかわからないという回答でした。 試してみたいのですが、SDKをインストールしたことがなく、 インストール方法がわかりません。 どのたか、おわかりのかたいらっしゃいましたら、 ご教授お願いいたします。

  • DELPHIにて

    こんにちは。またまた質問させていただきもうしわけありません。 DELPHIで2つ(以上)の表の連携を取りたいと考えています。 <例> FORM1にはエディットとボタンのみでエディットに入力された 文字列をFORM2(ラベルのみ)のラベルに表示するという 簡単なものですが、これはどうすれば実現するのでしょうか? 宜しくお願い致します。

  • Delphiって何なんでしょう?

    Delphiというのはプログラミング言語の名前なんでしょうか? それともプログラムを組む際に、 楽できるソフトウェアの名前なのでしょうか?

  • Delphi 6

    Delphi6でプログラミングしているのですが 何分不慣れなもので・・・・ もし、お知りの方おられましたら ご教授お願い致します。 ******************************** あるpasファイルにてvarで定義した変数を色々な .pasファイルで使用したいのですがどうすれば よいのでしょうか?

  • Delphi 6

    いつもお世話になりありがとうございます。 Delphi 6についてご教授お願い致します。 CopyFileにてファイルをコピーしているのですが、 コピーできない時があります。 サイズの大きいファイルとか関係あるのでしょうか? ************************************************ CopyFile('C:\TEST1.TXT', 'Z:\TEST1.TXT', False); CopyFile('C:\TEST2.TXT', 'Z:\TEST2.TXT', False); CopyFile('C:\TEST3.TXT', 'Z:\TEST3.TXT', False); というように連続でコピーしたいのですが・・・

  • delphiで

     delphiでXのY乗といった数値計算をさせたいのですが、演算子を見つけることができません。どなたか教えていただけないでしょうか。また、演算子がないのであれば簡単なロジックを教えてください。

  • Delphi5について

    Delphi5でのコンソールアプリケーションの作り方が分かりません。ヘルプを見ると『新規作成を選択しダイアログボックスのコンソールアプリケーションを選択する』とありますが、ダイアログボックス内にはコンソールアプリケーションの項目はありませんでした。 何か設定を変える必要があるのでしょうか。

  • Delphiについて

    Delphiを使い始めてちょっとの初心者ですが、 Imageコンポーネントなのですが、 プロパティのPictureを変えれば画像を表示できるのですが、 ソース中に書き込んで変える方法はないのでしょうか? Image1.Pricture := .... とこんな感じで変えられないでしょうか? その画像の拡張子は「.bmp」です。

専門家に質問してみよう