mieki256's diary



2026/07/02(木) [n年前の日記]

#1 [prog] スプライトのzソートについて調べてる。その2

スプライトの描画順をz値に基づいて決定したい。

以前 love2d 関係の解説ページで目にしたような記憶があったのだけど、たぶん以下のページかな…。内容はまだ理解できてない…。

_Tutorial:Drawing Order - LOVE
_Skip list:Drawing Order - LOVE


Google Gemini にも尋ねてみたら、C言語で以下のサンプルが提示された。クイックソートとポインタ変数配列を使って描画順を得られる。

// ポインタ配列とクイックソートでzソートをする事例
// Google Gemini に作成してもらった。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define SPRITE_COUNT 20

// 1. スプライトの構造体(実体)
typedef struct {
    int id;
    int z;  // 描画順(Z値)
    // X, Y座標など
} Sprite;

// 2. qsort用の比較関数
// 「Spriteへのポインタ」の配列をソートするため、引数は「Spriteへのポインタのポインタ」になります
int compare_sprites(const void* a, const void* b) {
    // void* から Sprite* のポインタへとキャストする
    Sprite* spriteA = *(Sprite**)a;
    Sprite* spriteB = *(Sprite**)b;
  
    // 1. まずはZ値で比較(昇順)
    // Z値の昇順(小さい順 = 奥から手前)に並べる
    // spriteA->z が小さければ負、大きければ正、等しければ0を返す
    if (spriteA->z != spriteB->z) {
        return (spriteA->z - spriteB->z);
    }
    
    // 2. Z値が同じならIDが小さい方を優先して返す(描画順の固定、チラつき防止)
    return (spriteA->id - spriteB->id);
}

int main() {
    srand((unsigned int)time(NULL));

    // スプライトの実体を一括確保
    Sprite sprites[SPRITE_COUNT];
    for (int i = 0; i < SPRITE_COUNT; i++) {
        sprites[i].id = i + 1;
        sprites[i].z = rand() % 100; // 0 - 99のランダムなZ値
    }

    // 描画順を管理するための「ポインタの配列」を用意する
    Sprite* draw_pointers[SPRITE_COUNT];
    
    // 初期化:まずはスプライトの実体の住所(ポインタ)をそのままコピー
    for (int i = 0; i < SPRITE_COUNT; i++) {
        draw_pointers[i] = &sprites[i];
    }

    // クイックソートを実行(draw_pointers の中身だけがZ値順に並び替わる)
    // 引数: (ソートする配列, 要素数, 1要素のサイズ, 比較関数)
    qsort(draw_pointers, SPRITE_COUNT, sizeof(Sprite*), compare_sprites);

    // 描画処理のシミュレーション(ポインタ配列を頭から順に回すだけ)
    printf("--- 描画実行(ポインタ配列+qsort) ---\n");
    for (int i = 0; i < SPRITE_COUNT; i++) {
        // draw_pointers[i] には、次に描画すべきスプライトの住所が入っている
        printf("[%02d番目に描画] Sprite ID: %02d (Z値: %02d)\n", 
               i + 1, draw_pointers[i]->id, draw_pointers[i]->z);
    }

    return 0;
}

Windows11 x64 25H2上で、MSYS2 の gcc を使ってコンパイルしてみた。
gcc -o zsort_sample_qsort zsort_sample_qsort.c

実行結果は以下。
> zsort_sample_qsort.exe
--- 描画実行(ポインタ配列+qsort) ---
[01番目に描画] Sprite ID: 18 (Z値: 02)
[02番目に描画] Sprite ID: 08 (Z値: 04)
[03番目に描画] Sprite ID: 04 (Z値: 14)
[04番目に描画] Sprite ID: 07 (Z値: 19)
[05番目に描画] Sprite ID: 14 (Z値: 19)
[06番目に描画] Sprite ID: 12 (Z値: 22)
[07番目に描画] Sprite ID: 17 (Z値: 23)
[08番目に描画] Sprite ID: 19 (Z値: 29)
[09番目に描画] Sprite ID: 13 (Z値: 31)
[10番目に描画] Sprite ID: 02 (Z値: 34)
[11番目に描画] Sprite ID: 20 (Z値: 36)
[12番目に描画] Sprite ID: 16 (Z値: 39)
[13番目に描画] Sprite ID: 10 (Z値: 45)
[14番目に描画] Sprite ID: 01 (Z値: 46)
[15番目に描画] Sprite ID: 05 (Z値: 47)
[16番目に描画] Sprite ID: 09 (Z値: 60)
[17番目に描画] Sprite ID: 15 (Z値: 61)
[18番目に描画] Sprite ID: 03 (Z値: 89)
[19番目に描画] Sprite ID: 11 (Z値: 91)
[20番目に描画] Sprite ID: 06 (Z値: 95)

たしかに、z値の小→大の順で結果が得られてる。

ただ、この方法だとスプライト枚数が増えた時に処理時間がかかってしまいそうな気もするのだけど…。AI (Google Gemini) は「C言語のクイックソート使ってるから全然大丈夫ッスよ」と言ってるけれど…。いやまあ、処理時間を測定してみないとなんとも言えないけれど…。

AI曰く、「z値が整数値で、取り得る値の範囲がそれほど広くないなら、オーダリングテーブル(Ordering Table)がオススメ」とも言ってきた。そうだった…。プレステ1で使ってたよな…。キーワード自体をすっかり忘れてた…。

ググったら、有名なゲームプログラマーさんがわざわざ解説してくれていた。ありがたや。

_オーダリングテーブル : プログラミング指南 - Code Knowledge

以上です。

過去ログ表示

Prev - 2026/07 -
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project