ページ 11

分割グラフィックの格納

Posted: 2009年1月18日(日) 19:15
by s-rush
いつもお世話になってます。
もうご存知の方が多いかと思いますが今私はポケモンのゲームを作ってます。

ゲームプログラミングの館で第17章にある”画像を分割して読み込む”というものがあったと思います。

その章を参考にして構造体の初期化の際にメンバ内に保存したいのですが、
どのようにすれば分からないんです。
typedef struct{
  int number;
  char name[32];
  int type1;
  int type2;
  int image[4];   //画像イメージ

//各ステータスの種族値
  int hp;
  int atk;
  int def;
  int t_atk;
  int t_def;
  int speed;

//覚える技
  int lv_skill[20];			//熟練度で覚える技
  int secret_skill[7];		//秘伝マシンで覚える技
}poke_tag;

/*構造体宣言および初期化*/
poke_tag poke[492]={
   {1,"フシギダネ",5,0,/*ここに画像イメージを格納*/,(略)},
  (略)
};
画像イメージは64X64なので、(画像を添付しておきます)
LoadDivGraph( "../data/img/pokemon/フシギダネ.png" , 4 , 2 , 2 , 64 , 64 , image ) ;
というような処理をどこかに組み込めばいいと思うのですが・・・

開発環境はVC++ 2008 EEです。

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 20:32
by Justy

>その章を参考にして構造体の初期化の際にメンバ内に保存したいのですが

 宣言と同時に初期化をする場合の話ですか?
 
 であれば、結論から言えば、いろいろややこしい問題が付きまといますが、
出来なくはないです。

 例えばこんな風に。
[color=#d0d0ff" face="monospace]
struct poke_tag
{
poke_tag(int number_, const char *name_, int type1_, int type2_, const char *image_path,
int hp_, int atk_, int def_, int t_atk_, int t_def_, int speed_)
: number(number_), type1(type1_), type2(type2_),
hp(hp_), atk(atk_), def(def_), t_atk(t_atk_), t_def(t_def_), speed_(speed_)
{
strcpy(name, name_);
LoadDivGraph(image_path, 4, 2, 2, 64, 64, image) ;
}

int number;
char name[32];
int type1;
int type2;
int image[4]; //画像イメージ

//各ステータスの種族値
int hp;
int atk;
int def;
int t_atk;
int t_def;
int speed;
};

poke_tag poke[/url]={
poke_tag(1,"フシギダネ",5,0, "../data/img/pokemon/フシギダネ1.png", 100, 50, 20, 10, 5, 25),
poke_tag(2,"??",5,0, "../data/img/pokemon/フシギダネ2.png", 100, 50, 20, 10, 5, 25),
};
[/color]

 但し、LoadDivGraph()は DxLib_Init()されていることが前提となりますので、
poke配列が初期化される前に DxLib_Init()を呼ばなければなりません。

 これさえクリアできれば、上記の方法で可能です。


※ 後から別途ロード(LoadDivGraph)するではダメなのでしょうか?

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 22:07
by s-rush
>後から別途ロード(LoadDivGraph)するではダメなのでしょうか?
というのは、どのようにすればよいのでしょうか?

poke[492]のグローバル変数(になるんでしょうか?)に
初期化するというかロードする関数
たとえば
void load_image(){
/*画像保存変数*/
 int image1;
 int image2;
(略)
 int image492;
/*画像のロード*/
 LoadDivGraph( "../data/img/pokemon/フシギダネ.png" , 4 , 2 , 2 , 64 , 64 , image1 ) ;
 LoadDivGraph( "../data/img/pokemon/フシギソウ.png" , 4 , 2 , 2 , 64 , 64 , image2 ) ;
 (略)
}
みたいな関数(即興で作ったものなので、エラーやおかしい部分もあると思いますが)
を作って、ゲーム起動時に読み込む
という形でいいんでしょうか?

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 22:27
by Justy

>みたいな関数を作って、ゲーム起動時に読み込む

 (関数はちょっとおかしいですが)そうですね。
 最初は 0とか -1とかで初期化しておいて、必要になった段階で読み込みを
行えばいいかと思います。

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 22:58
by s-rush
でも全部で500弱とあるのですが、もっと楽に書く方法はないでしょうか?
for文で
image[4][492]の中に画像をロードしたいと思うのですが、
ファイル名を個々に指定しないといけないような気がするのですが・・・

>最初は 0とか -1とかで初期化しておいて、必要になった段階で読み込みを行えばいいかと思います。
ということもよく分からないので、よろしければもう少し詳しく教えていただけませんか?

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 23:26
by Justy

>でも全部で500弱とあるのですが、もっと楽に書く方法はないでしょうか?

 poke[n]の nに依存するファイル名にすれば解決しませんか?
 つまり、
[color=#d0d0ff" face="monospace]
for(int n=0; n<492; ++n)
{
char path[0x80];
sprintf(path, "%s%03d%s", "../data/img/pokemon/poke_", n, ".png");
LoadDivGraph(path, 4, 2, 2, 64, 64, poke[n].image);
}
[/color]

 とか。(09/01/19 00:03 修正)


 これで、"poke_000.png"、"poke_001.png"、と連番でロードを行うことが出来ます。



>>最初は 0とか -1とかで初期化しておいて、必要になった段階で読み込みを行えばいいかと思います
>ということもよく分からないので、よろしければもう少し詳しく教えていただけませんか?

 要するに、とりあえず最初の宣言時の初期化の段階では、 image[n]は 0とか -1とか
無効な画像ハンドルにしておいて実際に画像が必要になった段階で、読み込みを行えばいい、
ということですね。

 読み込むタイミングとしては……ゲームの規模とかシステムとか判らないので、
最適かどうかはわかりませんが、ゲーム本編が始まる直前あたりで、ロードすれば
いいかと思います。

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 23:37
by Dixq (管理人)
500個も画像を使うんですか?
その配列を見ると、2000個もロードすることも?

画像を分割してロードするならファイル名を個々に指定しないといけないことは無いですが、
そうではなく、500個の画像ファイルからロードしたいなら、
連番のファイル名にし、カウンタとsprintfで文字列作ればループ文で読み込めます。

しかし500個も画像が必要なことってあるんでしょうか?
そちらを見直したほうがよさそうな気がします。

今ふと思ったのですが、解らないのは、一つの配列の異なる部分に画像を分割して複数の画像を読み込みたいんでしょうか?
例えば
[0]~[9]にはファイル1を10個に分割した画像を、
[10]~[24]にはファイル2を15個に分割した画像を、、、、
みたいな感じで?
そうではなく?

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 23:39
by Dixq (管理人)
う、、被ってすみません^^;
この掲示板書いてる途中に投稿があったら何か通知されるシステムほしいな・・。

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 23:49
by kazuoni
>char path[0x80]; 
>sprintf("%s%03d%s", "../data/img/pokemon/poke_", n, ".png");
こんな使い方できるのですか^^;
いやー、ビット演算系勉強しないとなぁ・・・。

管理人さんのおっしゃる通り、一気に500×4も不必要かなぁって思います。
出るんだかどうかわかんないような(○ュウ)ポケモンをずーっと読み込みっぱなしは
ちょっともったいないですね。
せめて○×タウンの周辺で出現するモンスターを
ロードするなら分かりますが。


>この掲示板書いてる途中に投稿があったら何か通知されるシステムほしいな・・。
自分は投稿前に新しいタブ開いて確認してますw

Re:分割グラフィックの格納

Posted: 2009年1月18日(日) 23:58
by Dixq (管理人)
>>Justyさん
あれ、sprintfの第一引数はpathではなくて、、、ですか?

>>kazuoniさん
これはビット演算とは関係無いのでは?

>タブ
そうすべきですね^^;

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:02
by Justy

>あれ、sprintfの第一引数はpathではなくて、、、ですか?

 あー、ありがとうございます。
 直しておきます。

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:07
by s-rush
kazuoniさんのおっしゃる通り、○×タウンの周辺で出現するモンスターをロードする、
ということも考えてはみたのですが、アルゴリズムが思い浮かばなかったので^^;

なので、管理人さんのおっしゃる通り、瞬間的?には2000も正直必要はないと思います。

それに
poke[0]にフシギダネの画像をロード
poke[1]にフシギソウの画像をロード
poke[2]にフシギバナの画像をロード

という形で、はじめに初期化しておけばエンカウントした時や、バトルシーンに突入した時など
処理が簡単になるのでは?
と思ったので、一気にロードしてみようと考えただけです。

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:08
by Dixq (管理人)
>>Justyさん
>>あれ、sprintfの第一引数はpathではなくて、、、ですか?

>? あれ?
>合ってませんか?


あら?今直されたんじゃなくてですか?
先ほどは

あー、ですね。
直しておきます。

と書いていらっしゃいませんでした??

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:10
by Dixq (管理人)
あら、何か誤解があったようですね^^;
ちょっと時間を置いてから投稿するようにします;

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:10
by Justy
> と書いていらっしゃいませんでした??
 すみません、ソース見て修正しているうちに、間違えた箇所を修正してしまったりと
ちょっと混乱してしまって。

 結局間違っていたので、修正しました。

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:14
by Dixq (管理人)
>>Justyさん

あぁ、そうでしたか。
今までミス記述されたのはほとんど見たことが無いので、
何か複雑な方法で出来るのかと思ってました^^;

>>s-rushさん

多分2000個も同時にロードしたらロード時間がすごくながくなって、
使用メモリもかなりの量になってしまう気がします。
やはりある程度量が多くなったら必要ない画像は読み込まないアルゴリズムを考える必要がありそうです。
一度タスクマネージャーのプロセスでどれ位メモリ食ってるかみてみてはどうでしょう?

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:29
by kazuoni
アルゴリズムでなくても外部から読み込めば
すぐにできてしまいそうですが。
マップのある出口を出たら次のタウンに行くと共に、
モンスターの更新なんて感じですかね。
そのとき以前のモンスターグラフィックは削除。
常にロードされているのは自分のパーティにいるモンスターだけでいいんじゃないですか?

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:29
by Justy

# Dixq (管理人) さん
>何か複雑な方法で出来るのかと思ってました^^;

 申し訳ないです。
 あわてるとダメですね。
 つい間違ったところを直してしまったりすると、何度修正してもうまく行かなかったり・・・。
 
 修正時にプレビューがあるといいですね。



> この掲示板書いてる途中に投稿があったら何か通知されるシステムほしいな・・。

 あれ? 来ないですか?
 てっきり Dixqさんの方にメールが飛んでいるものだと思っていました。



# s-rushさん
>はじめに初期化しておけばエンカウントした時や、バトルシーンに突入した時など
処理が簡単になるのでは?

 処理は簡単になりますけど、やっぱり Dixqさんが仰っているように
ロード時間が気になるかもしれませんね。

 仮にロードに10秒かかったすると、ユーザーがその時間待たされるというのもありますが、
デバッグの際にテストで実行するたびに10秒待たされるということでもあるので
結構苦痛になるような気がします。

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 00:45
by Dixq (管理人)
> あれ? 来ないですか?
> てっきり Dixqさんの方にメールが飛んでいるものだと思っていました。

あ、来るんですが、一日にこれだけ投稿があるので、通知されるメルアドは普段使わないそれ専用のものにわけてあります。
そうでないと、通知で埋まってしまうので^^;
なので、必要がある時にログインしてメールを見ることは出来るのですが、
投稿されたかどうかはわからないのです。
昔は携帯に転送してたんですが、
すぐ受信ボックスが埋まることや寝てる時や授業中でも投稿通知が来てしまうなど、問題があるのでやめました^^;


> データのロード

ロード関連はいろいろ悩みますよねぇ・・。
単純にはマルチスレッド化しても意味の無いDXライブラリの読み込み関数ですが、
いろいろと工夫してマルチスレッドするとか、そうすると同期の問題どうするかとか・・。
まぁポケモン程度ならその画面ごとに区切ってデータのロード&削除してもいいと思いますよ。
ロードの瞬間画面が止まってしまいますが、画面が切り替わる瞬間など、一瞬でいいので、戦闘突入の音楽を流したまま画面が真っ暗になる瞬間を作り、そこで読み込んだりすれば
画面が一瞬とまってもわからないので、そういう工夫をすればいいと思います。

音楽はロード中も途切れないので、こうすることで、黒い画面がコンマ何秒かあっても演出の一つに見えると思います。

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 02:36
by Justy

>必要がある時にログインしてメールを見ることは出来るのですが、
>投稿されたかどうかはわからないのです

 あー、そうだったんですか。
 納得です。

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 19:41
by BEMANI
例えば、出現ポケモン格納構造体みたいなのを仮に10個分程作成して
マサラ周辺でコラッタ・ポッポなどのポケモンデータを入れておき、
トキワ周辺になったらビードル・キャタピー等のデータに
オツキミヤマでズバットやイシツブテ・・・などのデータに上書きするとか。
そしたら、必要な場所で必要なポケモンデータのロードになるのではないかなーと。
こうしておけば、最大で10匹のポケモンのデータを読み込むだけで済みそうです。

技全部を構造体にまとめているということでしたので
もしかしたらポケモンも全部まとめてるのではないかなーと思い
こんな方法ですが思いつきました。

余談ですが、
さらにロードする時に連番で読み込みできるようにしていたり、
ポケモン図鑑の番号と一緒にしておくと後々便利になるかもしれません。

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 21:15
by s-rush
やっぱり2000ものデータをロードするのは時間がかかりますか・・・
管理人さんのおっしゃる通り、メモリもだいぶ多く使用するみたいでした^^;

他に少なくともフィールド上に出現するトレーナー(人)のためにもロードする必要がありそうですし。

kazuoniさんやBEMANIさんのおっしゃるようにマップの切り替え時に
再ロードするような処理に挑戦してみようと思います。
(マップの切り替え処理をどのようにすればよいのかいまいち分からないですが^^;)

>char path[0x80];
>sprintf(path, "%s%03d%s", "../data/img/pokemon/poke_", n, ".png");
の処理の解説をお願いしてよろしいですか?
2つ目の処理は何となくわかるのですが、1つ目の”0x80”という部分が分からないです^^;

Re:分割グラフィックの格納

Posted: 2009年1月19日(月) 22:03
by BEMANI
さすがに2000個ものファイルをロードするのはやめた方がいいですね;

>char path[0x80];
0xと付くものは16進数です。
普段私たちが使っている数字は10進数です。(0~9で10になる時に桁上がりする)
16進数は16になった時に桁上がりするものです。

0x80は10進数で128と同じです。

128は(100の位*1 + 10の位*2 + 1の位*8)とそれぞれの桁がいくつ集まっているかということですよね。
0x80も同じで16進数でということですので(16の位*8 + 1の位*0)で128ということになります。
よって、path[128]と同じです。

もしお暇なら、
printf("%d", 0x80); とやってみるか、
printf("%x", 128); とやってみるかしてみて下さい^^
%dは10進数・%xは16進数です。


>sprintf(path, "%s%03d%s", "../data/img/pokemon/poke_", n, ".png");
仮に、「n」に1が入っていたとしますと、
../data/img/pokemon/poke_001.png と表示されます。
%sは文字列。
%03dではそれぞれ、「0」は0の付加・「3」は桁数・「d」は符号付きの10進数(整数)です。
nが5の場合../data/img/pokemon/poke_005.pngと表示されます。

それをpathに入れるという感じです。

Re:分割グラフィックの格納

Posted: 2009年1月20日(火) 11:27
by s-rush
BEMANIさん、解説ありがとうございます。
%xで16進表記ということは知っていたのですが、
0xをつけることで16進数扱いになるということは知りませんでした^^;

となると、ファイル名を001.pngというように変えておかないといけないですね。

ちなみにロードする数が400くらいなら許容範囲ですかね?

Re:分割グラフィックの格納

Posted: 2009年1月20日(火) 13:45
by Dixq (管理人)
400でも多いのでは・・。
ただ、細かいマップチップや、キャラチップになると、どうしても数が多くなると思うので、
そういうので増えているのはいいと思います。
なので、どういう画像かによると思います。

もし全部の敵を読み込むとかだったら必要な敵だけ読み込んだほうがいいと思います。

400個ロードしたときの使用メモリはいくつになってます?

Re:分割グラフィックの格納

Posted: 2009年1月20日(火) 16:49
by BEMANI
>となると、ファイル名を001.pngというように変えておかないといけないですね。
この001という数字を手当たり次第・適当に使うのではなく、
ポケモン図鑑の番号とリンクさせておくと後々便利になるかもしれません。
001 フシギダネ
002 フシギソウ



151 ミュウ


>ちなみにロードする数が400くらいなら許容範囲ですかね?
管理人さんが仰る通り、何を読み込むかによりますが、
ポケモンの画像を400読み込むというのであればかなり多いと思われます。
多分100でも多いかと;


画像をロード・・・というわけではないですが、
マップによってポケモンの名前を表示するサンプルプログラムを添付してみました。
マップが変わったら、その都度「PokeData[要素数]」を上書き(更新)しています。

こうすることで、一気に画像を読み込む必要がなくなります。
(はじめてファイルを投稿するので失敗していたらごめんなさい;)

Re:分割グラフィックの格納

Posted: 2009年1月20日(火) 16:55
by s-rush
どこを見ればよいのかわからないですけど、
タスクマネージャで見てみるとこんな感じでした。
物理メモリ
合計 2044
キャッシュ済み 1106
空きメモリ 5

カーネルメモリ
合計 231
ページ 159
非ページ 72

ただ400もグラフィックを製作済みというわけではないので10個ロードで試してみました。

キャラチップやマップチップは16X16なので、使用するメモリはもうちょっと少なくなると
思うのですが・・・