ページ 11

qsort関数で構造体の中身を並び替え

Posted: 2011年8月19日(金) 13:51
by chalaza
奥にいるキャラクターの画像等から順番に描画させるために、qsort関数というものを使ってみることにしました。
リファレンスに目を通して、文字を変えて同じように書いたつもりなのですが、画面の画像がぶれて点滅してしまうようになってしまいました。
もしかして、常時ソートと描画を繰り返すという処理は間違っているのでしょうか?
移動したときだけソートさせるというのだったら、どのタイミングで更新すればいいのでしょうか…

コード:

// キャラ全員分構造体
typedef struct {
	int X;
	int Y;
	int DrawX;
	int DrawY;
	int MoveBeforeX;
	int MoveBeforeY;
	int img;
	int gazou;
	int muki;
	int MoveBeforeMuki;
	int walk;
	int scope;
	int HP;
	int HPMAX;
	int MP;
	int MPMAX;
	int CP;
	int CPMAX;
}PlayerData_t;

// キャラ構造体の実体
PlayerData_t PlayerData[2]; 

//オブジェクトの比較関数 
int hpcmp(const PlayerData_t *x, const PlayerData_t *y)
{
    return (x->DrawY < y->DrawY ? -1 :
            x->DrawY < y->DrawY ?  1 : 0);
}

//キャラを表示
void print_PlayerData(PlayerData_t PlayerData)
{
	DrawGraph(180+PlayerData.DrawX-CameraX,90+PlayerData.DrawY-CameraY,PlayerData.img,TRUE);//プレイヤー1描画
}

void DrawChara(){//キャラクター描画

	int i;
	int  nx = sizeof(PlayerData) / sizeof(PlayerData[0]);     // 配列の要素数

	//Y座標順にソート
    qsort(PlayerData, nx, sizeof(PlayerData_t), (int(*)(const void*, const void*))hpcmp);

    for (i = 0; i < nx; i++)
		 print_PlayerData(PlayerData[i]);//描画
}

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月19日(金) 15:29
by ookami
こんにちわ。

たぶんですが、
int hpcmp(const PlayerData_t *x, const PlayerData_t *y)
{
return (x->DrawY < y->DrawY ? -1 :
x->DrawY < y->DrawY ? 1 : 0);
}
これは、どっちかの「<」が逆ではないでしょうか?

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月19日(金) 20:20
by chalaza
ookamiさんの通りに x->DrawY > y->DrawY ? 1 : 0); と符号を逆にしてみたら、
おかげで画面が常時ぶれるようなことはなくなったのですが…
プレイヤー1がプレイヤー2より下、プレイヤー2がプレイヤー1より上に動こうとすると画面がぶれ始めてしまい、
動かしていない方のキャラが勝手についてきてしまいます…
比較関数がまだ間違えてたりするのでしょうか?

コード:


// キャラ全員分構造体
typedef struct {
	int X;
	int Y;
	int DrawX;
	int DrawY;
	int MoveBeforeX;
	int MoveBeforeY;
	int img;
	int gazou;
	int muki;
	int MoveBeforeMuki;
	int walk;
	int scope;
	int HP;
	int HPMAX;
	int MP;
	int MPMAX;
	int CP;
	int CPMAX;
}PlayerData_t;

// キャラ構造体の実体
PlayerData_t PlayerData[2]; 

//オブジェクトの比較関数 
int hpcmp(const PlayerData_t *x, const PlayerData_t *y)
{
    return (x->DrawY < y->DrawY ? -1 :
            x->DrawY > y->DrawY ?  1 : 0);
}

//キャラを表示
void print_PlayerData(PlayerData_t PlayerData)
{
	DrawGraph(180+PlayerData.DrawX-CameraX,90+PlayerData.DrawY-CameraY,PlayerData.img,TRUE);//プレイヤー1描画
}

void DrawChara(){//キャラクター描画

	int i;
	int  nx = sizeof(PlayerData) / sizeof(PlayerData[0]);     // 配列の要素数

	//Y座標順にソート
    qsort(PlayerData, nx, sizeof(PlayerData_t), (int(*)(const void*, const void*))hpcmp);

    for (i = 0; i < nx; i++)
		 print_PlayerData(PlayerData[i]);
}


Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月19日(金) 21:14
by h2so5
chalaza さんが書きました: プレイヤー1がプレイヤー2より下、プレイヤー2がプレイヤー1より上に動こうとすると画面がぶれ始めてしまい、
動かしていない方のキャラが勝手についてきてしまいます…
プレイヤーを移動する部分のコードが無いので何とも言えませんが、もしかして、

PlayerData[0].drawX += 1;

のような移動のさせ方をしていませんか?

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月19日(金) 21:45
by chalaza
ああ、その通りです。それのせいならなおさなければいけませんが…
作っているのは、キー入力があったらPlayer.DrawXとY(描画座標)が動いて、
1マス分で割り切れるまで動き切ったらPlayer.XとY(位置座標)が1加算されるという感じです。
座標を基準に画像を表示すると動くときに瞬間移動してしまうから描画座標と分けたのですが、
こういう変わった場合はどう基準に描画すればいいでしょうか…?

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月19日(金) 22:14
by h2so5
ソートしているので、PlayerData[0]はy座標の一番小さいプレイヤーを指しているのであって、
プレイヤー1を指しているわけではありません。

その状態で PlayerData[0].drawX += 1; などと書いたら、
当然おかしな動作になるはずです。

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月19日(金) 23:31
by chalaza
あ、PlayerData自体が並べ替えられてたんですね。
配列に並び順だけを記録してるものかと思ってました…
そうだとすると、一度ソートしてしまうともうプレイヤー1か2かを見分けて処理する方法がなくなってしまいますよね?
一度違う変数に座標を代入してからそれだけ並べ替えるとかした方がよろしいのでしょうか…

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月19日(金) 23:49
by h2so5
この場合は、PlayerDataのポインタを保持する配列を作ってそれをソートするのが妥当な方法だと思います。
PlayerData型の配列をソートすると構造体のコピーが発生するので無駄も多いですしね。

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月20日(土) 01:49
by chalaza
ポインタを実際に使うのが初めてなのでリファレンスとかを見て作ってみたつもりですが、
まず構造体ごと並び替えないで、それぞれの描画Y座標だけ配列に入れてソートするようにしてみました
*SortY[2]というポインタに描画Y座標のアドレスを入れてみて、その*SortYを並び替えました。
実行してみると、画面の動きをみる限り、ぶれたり変な動きはしないのですが…
プレイヤー2だけ表示されていませんでした。ちゃんと位置座標に存在はしているようなので、キャラ描画の部分とかが問題かと思ったのですが
見えない状態で変な動きをしているかもしれないので何とも言えません…
ポインタの使い方がどこか間違っているでしょうか…?

コード:


//オブジェクトの比較関数
int int_cmp(const int *a, const int *b)
{
    if (*a < *b)
        return (-1);
    else if (*a > *b)
        return (1);
    return (0);
}
 
void DrawChara(){//キャラクター描画
 
    int  i;
    int *SortY[2] = { &PlayerData[0].DrawY, &PlayerData[1].DrawY};
    int  nx = sizeof(*SortY) / sizeof(*SortY[0]);     // 配列の要素数

	qsort(*SortY, nx, sizeof(int), (int(*)(const void*, const void*))int_cmp);//ソートする

    for (i = 0; i < nx; i++)
		DrawGraph(180+PlayerData[i].DrawX-CameraX,90+*SortY[i]-CameraY,PlayerData[i].img,TRUE);//プレイヤー描画

}

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月20日(土) 08:04
by h2so5
まずsizeofやqsortの引数がおかしいです。
また、その方法だとプレイヤー1とプレイヤー2のY座標が入れ替わってしまいます。
ソートするならPlayerDataのポインタをソートしないと駄目です。

こんなソースになります。

コード:

//オブジェクトの比較関数
int int_cmp(const PlayerData_t **a, const PlayerData_t **b)
{
    if ((*a)->DrawY < (*b)->DrawY)
        return (-1);
    else if ((*a)->DrawY > (*b)->DrawY)
        return (1);
    return (0);
}

void DrawChara(){//キャラクター描画
 
    int  i;
    PlayerData_t *SortArray[2] = { &PlayerData[0], &PlayerData[1]};
    int  nx = sizeof(SortArray) / sizeof(SortArray[0]);     // 配列の要素数
 
    qsort(SortArray, nx, sizeof(PlayerData_t*), (int(*)(const void*, const void*))int_cmp);//ソートする
 
    for (i = 0; i < nx; i++)
        DrawGraph(180+SortArray[i]->DrawX-CameraX,90+SortArray[i]->DrawY-CameraY,SortArray[i]->img,TRUE);//プレイヤー描画
 
}

Re: qsort関数で構造体の中身を並び替え

Posted: 2011年8月20日(土) 08:32
by chalaza
PlayerDataのポインタごとにしないと駄目だったんですね…
おかげさまで一応処理はできましたが、もう少しqsortとポインタのことを調べてみます
わざわざソースまでありがとうございました。解決とします。