グラフィックハンドルの数が限界数に達するということ

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
金太郎

グラフィックハンドルの数が限界数に達するということ

#1

投稿記事 by 金太郎 » 5年前

ステージをクリアしていくタイプのゲームを作っています。
ケチってひとつの変数(配列)に、毎ステージの背景画像をLoadDivGraphして使っています。
すると、6ステージ目で必ず背景が真っ黒になってしまい、
ログには「グラフィックハンドルの数が限界数( 32768 )に達していて新たなハンドルを作成できません」と
表示されています。
この掲示板で検索したところ、
「ループする様な関数にLoadDivGraphは掘り込んではならない」、といったアドバイスがありました。
とりあえずこの掲示板で確認できた対処?はそれくらいでした。
しかし、自分のそのLoadDivGraphは毎度ステージクラスを実行時の
初期化関数内に設置しており、ステージが始まった時点で
LoadDivGraphは読み込みなどされていないはずなんです。
つまり、ループはしてないはずです。

しかし、正直申しますと
「グラフィックハンドルの数が限界数」というところから自分は理解出来ておりません。
グラフィックハンドル(変数)は、普段の数値を入れるだけの変数と違って
上書きされてはいかない、ということでしょうか?
しかし、そう考えた場合、自分のイメージでは
ステージ2の段階から背景はおかしくなるはずなんですが。。。
なぜ6ステージまではまともに機能しているのか、わかりません。

とりあえず、構成はこうです。

コード:


ステージクラスの初期化関数{
   //毎回、そのステージ№に合わせて、ひとつしか無いグラフィックハンドル変数に個々の画像情報を入れる
   switch(ステージ数){
   case 1:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
   case 2:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
   case 3:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
   case 4:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
   case 5:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
   case 6:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
   case 7:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
   以下、ずっと続きます
  }
}

ステージクラスの描画関数{

    グラフィックを描画する
}

そもそも、このやり方はまずいのでしょうか?
素直に、各ステージ用のグラフィックハンドルを作って読み込ませたほうがいいのでしょうか?
しかし、この方法をしてる方もぜんぜんいらっしゃると思うのです。
だとすれば、私の処理になにがどう足りないのでしょうか?
教えてください。

もしかして、グラフィックハンドル内を初期化する命令ってあるのでしょうか?
それをステージが終わるたびにしてやると、いいとか、、、

Referia
記事: 24
登録日時: 5年前
住所: 奈良

Re: グラフィックハンドルの数が限界数に達するということ

#2

投稿記事 by Referia » 5年前

LoadGraphic系の関数を実行すると「メモリ上」に画像データを展開し、そのハンドル(メモリ上の画像識別番号)が返されます
したがってハンドルを上書きしてもメモリ上に展開された画像データは削除されません
ですのでDeleteGraphを行ってからGraphicHandleを上書きするようにしてください

未検証ですがこのようにすると良いと思います

コード:

 
ステージクラスの初期化関数{
   //毎回、そのステージ№に合わせて、ひとつしか無いグラフィックハンドル変数に個々の画像情報を入れる
   DeleteGraph(グラフィックハンドル変数);
   switch(ステージ数){
   case 1:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
   case 2:
      LoadDivGraph("1面のファイル名",5400,60,90,8,8,グラフィックハンドル変数);
      break;
  ・・・
  }
}
 
ステージクラスの描画関数{
 
    グラフィックを描画する
}

【追記】
LoadDivGraphで作成していることを見逃していました
配列内の要素全てのグラフィックハンドルを使用してDeleteGraphするようにしてください。

金太郎

Re: グラフィックハンドルの数が限界数に達するということ

#3

投稿記事 by 金太郎 » 5年前

回答ありがとうございます。
Referia さんが書きました: 配列内の要素全てのグラフィックハンドルを使用してDeleteGraphするようにしてください。
今回、グラフィックハンドルは二次元配列で宣言しておりますので

コード:

  for(int i=0; i<m_line; i++){
	  for(int j=0; j<m_col; j++){
		  DeleteGraph( グラフィックハンドル[i][j] )
	  }
  }
毎回、ステージ終了後に、こんな感じで処理をさせれば大丈夫でしょうか?

Rittai_3D
記事: 525
登録日時: 7年前

Re: グラフィックハンドルの数が限界数に達するということ

#4

投稿記事 by Rittai_3D » 5年前

いっそのこと、画像を一枚にまとめてしまい、まとめた画像をLoadGraph()するというのはどうでしょうか。

> グラフィックハンドルの数が限界数
とは、おそらくDxLibが一度に保持できる画像ハンドルの数です。

推測ですが、たとえば、

コード:

int hdl[ 30 ];
LoadDivGraph( "ggraph.png", 5400, 60, 90, 8, 8, hdl );
とすると、画像ハンドルを30個使用するのと同じだと思います。
手元にDxLibが扱える環境が無いので推測です。すいません。

ステージごとの画像を一枚にまとめてLoadDivGraph()せずにLoadGraph()すれば、ステージ数だけの画像ハンドルの保持で済みます。
描画するときはDrawRectGraph()を使用すれば問題ないでしょう。
初心者です

金太郎

Re: グラフィックハンドルの数が限界数に達するということ

#5

投稿記事 by 金太郎 » 5年前

Rittai_3D さんが書きました:いっそのこと、画像を一枚にまとめてしまい、まとめた画像をLoadGraph()するというのはどうでしょうか。

> グラフィックハンドルの数が限界数
とは、おそらくDxLibが一度に保持できる画像ハンドルの数です。

推測ですが、たとえば、

コード:

int hdl[ 30 ];
LoadDivGraph( "ggraph.png", 5400, 60, 90, 8, 8, hdl );
とすると、画像ハンドルを30個使用するのと同じだと思います。
手元にDxLibが扱える環境が無いので推測です。すいません。

ステージごとの画像を一枚にまとめてLoadDivGraph()せずにLoadGraph()すれば、ステージ数だけの画像ハンドルの保持で済みます。
描画するときはDrawRectGraph()を使用すれば問題ないでしょう。

金太郎

Re: グラフィックハンドルの数が限界数に達するということ

#6

投稿記事 by 金太郎 » 5年前

レスありがとうございます。
ただ、多分ですが

コード:

 int hdl[ 30 ];
 LoadDivGraph( "ggraph.png", 5400, 60, 90, 8, 8, hdl );
これは、LoadDivGraphの引数の内容を考えたらエラーだと思います。

5400はマスの総数で、8, 8はその1マスのサイズをあらわしてます。
だとすれば、hdlの1要素の中に、さらに配列を入れなければならないと思うのです。

なんにしても、とりあえず今回は
背景をbloc状に入れて描画することが重要なので
1枚の画像をそのまま描画する云々は考えません。

Rittai_3D
記事: 525
登録日時: 7年前

Re: グラフィックハンドルの数が限界数に達するということ

#7

投稿記事 by Rittai_3D » 5年前

すいません、LoadDivGraph()の引数の内容を忘れていました。

コード:

	int LoadDivGraph( char *FileName , int AllNum ,
          int XNum , int YNum ,
          int XSize , int YSize , int *HandleBuf ) ;
LoadDivGraph()
でしたね。

あくまで適当に書いたコードですので、読みやすいように書きなおすと

コード:

static const int GRAPH_X_NUM = 4;
static const int GRAPH_Y_NUM = 4;
static const int GRAPH_NUM = GRAPH_X_NUM * GRAPH_Y_NUM;

static const int GRAPH_WIDTH = 256; // 適当
static const int GRAPH_HEIGHT = 256; // 適当

int hdl[ GRAPH_NUM ] = {};

LoadDivGraph(
             "ggraph.png", // ファイル名
             GRAPH_NUM , // 画像総数
             GRAPH_X_NUM , // x方向の画像数
             GRAPH_Y_NUM , // y方向の画像数
             GRAPH_WIDTH  / GRAPH_X_NUM , // x方向の一つ当りの画像のサイズ
             GRAPH_HEIGHT / GRAPH_Y_NUM , // y方向の一つ当りの画像のサイズ
             hdl // 画像ハンドルの配列
 );
こんな感じでしょうか。
金太郎 さんが書きました:なんにしても、とりあえず今回は
背景をbloc状に入れて描画することが重要なので
1枚の画像をそのまま描画する云々は考えません。
いえ、違います。
DrawRectGraph()のリファレンスを読めばわかると思いますが、

コード:

	int DrawRectGraph( int DestX, int DestY,
          int SrcX, int SrcY, int Width, int Height,
          int GraphHandle, int TransFlag, int TurnFlag ) ;
# 参照のURLは前回書いたので割愛します
となっています。
つまり、一枚の画像から、矩形を指定して、指定した部分だけを抜き出して描画することができます。
だから、

コード:

static const int GRAPH_X_NUM = 4;
static const int GRAPH_Y_NUM = 4;
static const int GRAPH_NUM = GRAPH_X_NUM * GRAPH_Y_NUM;

static const int ONE_GRAPH_X_SIZE = GRAPH_WIDTH  / GRAPH_X_NUM; // 一つの画像のサイズ
static const int ONE_GRAPH_Y_SIZE =  GRAPH_HEIGHT / GRAPH_Y_NUM;

int hdl[ GRAPH_NUM ] = {};
LoadDivGraph( "ggraph.png", GRAPH_NUM, GRAPH_X_NUM, GRAPH_Y_NUM, GRAPH_X_SIZE , GRAPH_Y_SIZE , hdl );

/*
*     ウィンドウ上の(10,20)の位置に、画像の
*    (3 * ONE_GRAPH_X_SIZE, 0)から( ONE_GRAPH_X_SIZE  , ONE_GRAPH_Y_SIZE )
*    の矩形を抜き出して描画する
*/

DrawGraph( 10, 20, hdl[ 3 ], TRUE ); 

コード:

static const int GRAPH_X_NUM = 4;
static const int GRAPH_Y_NUM = 4;
static const int GRAPH_NUM = GRAPH_X_NUM * GRAPH_Y_NUM;

static const int ONE_GRAPH_X_SIZE = GRAPH_WIDTH  / GRAPH_X_NUM; // 一つの画像のサイズ
static const int ONE_GRAPH_Y_SIZE =  GRAPH_HEIGHT / GRAPH_Y_NUM;

int handle = LoadGraph( "ggraph.png" );

/*
*     ウィンドウ上の(10,20)の位置に、画像の
*    (3 * ONE_GRAPH_X_SIZE, 0)から( ONE_GRAPH_X_SIZE  , ONE_GRAPH_Y_SIZE )
*    の矩形を抜き出して描画する
*/

DrawRectGraph( 10, 20, 3 * ONE_GRAPH_X_SIZE, 0, ONE_GRAPH_X_SIZE, ONE_GRAPH_Y_SIZE, handle, FALSE, FALSE );
は同じことです。

# コンパイルはしていませんし、テストもしていません。
# 手元に環境がないのです・・・
初心者です

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: グラフィックハンドルの数が限界数に達するということ

#8

投稿記事 by softya(ソフト屋) » 5年前

利用している画像ハンドルが完全に管理できていて、解放を確実に行えるなら今のままの方法でも構わないと思います。
しかし、8x8とはまた細かいパーツですね。ファミコン時代を思い出させます。

Rittai_3Dさんの方法のほうが最終的にはシンプルかもしれません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

金太郎

Re: グラフィックハンドルの数が限界数に達するということ

#9

投稿記事 by 金太郎 » 5年前

Rittai_3D さんが書きました: は同じことです。
なるほどです、理解できました。
ちなみに、私のやり方と比較して
要領はどうなりますか?

どちらが要領に負担が無いとか

Rittai_3Dさんが
いきなり、それを薦めてこられたというのは
理由があってのことだと思うんですが。

金太郎

Re: グラフィックハンドルの数が限界数に達するということ

#10

投稿記事 by 金太郎 » 5年前

softya(ソフト屋) さんが書きました:解放を確実に行えるなら今のままの方法でも構わないと思います。
回答をありがとうございます。

ちなみに、
グラフィックハンドルの解放を自力でするのは初めてなんですが、

グラフィックハンドルを
int A[30];
と配列で宣言していた場合

解放の処理は

コード:

  for(int i=0; i<30; i++){
          DeleteGraph( グラフィックハンドル[i] );
  }
といった感じにしなければなりませんか?

まとめて、こう書いたら駄目ですか?

コード:

 DeleteGraph( グラフィックハンドル );

Rittai_3D
記事: 525
登録日時: 7年前

Re: グラフィックハンドルの数が限界数に達するということ

#11

投稿記事 by Rittai_3D » 5年前

金太郎さんの方法ですと、画像ハンドルは配列の要素*ステージ分必要になり、また、画像の解放処理も煩雑になります。

しかし、わたしの方法ですと画像ハンドルはステージ分ですみます。また、解放処理も単純になります。
金太郎 さんが書きました: グラフィックハンドルを
int A[30];
と配列で宣言していた場合

解放の処理は

コード:

  for(int i=0; i<30; i++){
          DeleteGraph( グラフィックハンドル[i] );
  }
といった感じにしなければなりませんか?

まとめて、こう書いたら駄目ですか?

コード:

 DeleteGraph( グラフィックハンドル );
DxLibのリファレンスを読みましょう。

# 訂正します。ステージ分はいりません。変数を使い回すなら
# 金太郎さんの方法ですとint型配列の要素分、
# わたしの方法ですとint型変数ひとつで済みます。
最後に編集したユーザー Rittai_3D on 2015年6月10日(水) 21:09 [ 編集 1 回目 ]
初心者です

金太郎

Re: グラフィックハンドルの数が限界数に達するということ

#12

投稿記事 by 金太郎 » 5年前

Rittai_3D さんが書きました: DxLibのリファレンスを読みましょう。
いえ、確認したんですが
グラフィックハンドルを配列で宣言している場合の
DeleteGraphの解説が無いので、、、

Rittai_3D
記事: 525
登録日時: 7年前

Re: グラフィックハンドルの数が限界数に達するということ

#13

投稿記事 by Rittai_3D » 5年前

LiadDivGraph()のリファレンス
分割した分だけ作成されたグラフィックハンドルはHandleBufで指定した int型変数配列のポインタに順に格納されていきます。
とありますので、きちんと要素分ループして解放処理を書いてやる必要があります。

また、「LoadDivGraph DeleteGraph」と検索すれば解決法が出てきます。
他人に聞く前にきちんと調べましょう。
最後に編集したユーザー Rittai_3D on 2015年6月11日(木) 07:39 [ 編集 1 回目 ]
初心者です

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 9年前
住所: 東海地方
連絡を取る:

Re: グラフィックハンドルの数が限界数に達するということ

#14

投稿記事 by softya(ソフト屋) » 5年前

Rittai_3Dさん の方法のメリットは面毎にステージ・グラフィックのサイズが違った場合の管理が凄くシンプルになることです。
全ステージが同じサイズなら、今の方法のままでもデメリットはさほど多くないはずです。
2次元配列で管理されているのが少し危険そうな要素ぐらいですかね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe()

Re: グラフィックハンドルの数が限界数に達するということ

#15

投稿記事 by ISLe() » 5年前

LoadDivGraphを使う上での注意として、SetUseDivGraphFlagの説明も読んでおくと良いと思います。

Rittai_3D
記事: 525
登録日時: 7年前

Re: グラフィックハンドルの数が限界数に達するということ

#16

投稿記事 by Rittai_3D » 5年前

Rittai_3D さんが書きました:

コード:

/*
*     ウィンドウ上の(10,20)の位置に、画像の
*    (3 * ONE_GRAPH_X_SIZE, 0)から( ONE_GRAPH_X_SIZE  , ONE_GRAPH_Y_SIZE )
*    の矩形を抜き出して描画する
*/
の部分についてですが、LoadDivGraph()は違いますね。

たとえば、

コード:

static const int GRAPH_X_NUM = 2;
static const int GRAPH_Y_NUM = 2;
static const int GRAPH_NUM = GRAPH_X_NUM * GRAPH_Y_NUM;
 
static const int GRAPH_WIDTH = 256; // 適当
static const int GRAPH_HEIGHT = 256; // 適当
 
static const int ONE_GRAPH_X_SIZE = GRAPH_WIDTH  / GRAPH_X_NUM; // 一つの画像のサイズ
static const int ONE_GRAPH_Y_SIZE =  GRAPH_HEIGHT / GRAPH_Y_NUM;

int hdl[ GRAPH_NUM ] = {};

LoadDivGraph(
             "ggraph.png", // ファイル名
             GRAPH_NUM, // 画像総数
             GRAPH_X_NUM, // x方向の画像数
             GRAPH_Y_NUM, // y方向の画像数
             ONE_GRAPH_X_SIZE, // x方向の一つ当りの画像のサイズ
             ONE_GRAPH_Y_SIZE, // y方向の一つ当りの画像のサイズ
             hdl // 画像ハンドルの配列
 );
というコードがあった場合(数字は添え字です)

コード:

+--------++--------+
|    0  ||    1    |
+--------++--------+
+--------++--------+
|    2   ||    3   |
+--------++--------+
のように画像ハンドルが格納されています。

コード:

DrawGraph( 10, 20, hdl[ 2 ], TRUE );
というコードがあった場合、「hdl[ 2 ]に格納された画像ハンドルの画像を描画する」ですので、コメントが間違えております。
このコードで、上の訂正前のような言い方をするならば、
「ウィンドウ上の(10,20)の位置に、hdl[2]に割り当てられた画像
(画像上の座標で(0, ONE_GRAPH_X_SIZE )からサイズ(ONE_GRAPH_X_SIZE , ONE_GRAPH_Y_SIZE )の矩形)を描画する」でしょうか。
初心者です

閉鎖

“C言語何でも質問掲示板” へ戻る