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

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

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

#1

投稿記事 by chalaza » 14年前

奥にいるキャラクターの画像等から順番に描画させるために、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]);//描画
}

アバター
ookami
記事: 214
登録日時: 15年前
住所: 東京都

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

#2

投稿記事 by ookami » 14年前

こんにちわ。

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

chalaza

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

#3

投稿記事 by chalaza » 14年前

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]);
}


アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

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

#4

投稿記事 by h2so5 » 14年前

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

PlayerData[0].drawX += 1;

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

chalaza

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

#5

投稿記事 by chalaza » 14年前

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

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

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

#6

投稿記事 by h2so5 » 14年前

ソートしているので、PlayerData[0]はy座標の一番小さいプレイヤーを指しているのであって、
プレイヤー1を指しているわけではありません。

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

chalaza

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

#7

投稿記事 by chalaza » 14年前

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

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

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

#8

投稿記事 by h2so5 » 14年前

この場合は、PlayerDataのポインタを保持する配列を作ってそれをソートするのが妥当な方法だと思います。
PlayerData型の配列をソートすると構造体のコピーが発生するので無駄も多いですしね。

chalaza

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

#9

投稿記事 by chalaza » 14年前

ポインタを実際に使うのが初めてなのでリファレンスとかを見て作ってみたつもりですが、
まず構造体ごと並び替えないで、それぞれの描画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);//プレイヤー描画

}

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

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

#10

投稿記事 by h2so5 » 14年前

まず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);//プレイヤー描画
 
}

chalaza

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

#11

投稿記事 by chalaza » 14年前

PlayerDataのポインタごとにしないと駄目だったんですね…
おかげさまで一応処理はできましたが、もう少しqsortとポインタのことを調べてみます
わざわざソースまでありがとうございました。解決とします。

閉鎖

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