2026/07/02(木) [n年前の日記]
#1 [prog] スプライトのzソートについて調べてる。その2
スプライトの描画順をz値に基づいて決定したい。
以前 love2d 関係の解説ページで目にしたような記憶があったのだけど、たぶん以下のページかな…。内容はまだ理解できてない…。
_Tutorial:Drawing Order - LOVE
_Skip list:Drawing Order - LOVE
Google Gemini にも尋ねてみたら、C言語で以下のサンプルが提示された。クイックソートとポインタ変数配列を使って描画順を得られる。
Windows11 x64 25H2上で、MSYS2 の gcc を使ってコンパイルしてみた。
実行結果は以下。
たしかに、z値の小→大の順で結果が得られてる。
ただ、この方法だとスプライト枚数が増えた時に処理時間がかかってしまいそうな気もするのだけど…。AI (Google Gemini) は「C言語のクイックソート使ってるから全然大丈夫ッスよ」と言ってるけれど…。いやまあ、処理時間を測定してみないとなんとも言えないけれど…。
AI曰く、「z値が整数値で、取り得る値の範囲がそれほど広くないなら、オーダリングテーブル(Ordering Table)がオススメ」とも言ってきた。そうだった…。プレステ1で使ってたよな…。キーワード自体をすっかり忘れてた…。
ググったら、有名なゲームプログラマーさんがわざわざ解説してくれていた。ありがたや。
_オーダリングテーブル : プログラミング指南 - Code Knowledge
以前 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
[ ツッコむ ]
#2 [anime] 「劇場版 幼女戦記」劇場版を視聴
BS11で放送されていたので視聴。ライトノベルを原作とするTVアニメの劇場版。
ググってみたら2019年の公開だったらしい。TVアニメ1期と2期の間を埋める内容だろうか。今月から2期が放送開始されるので、それに合わせて復習/履修/宣伝を兼ねた放送なのだろう…。これを見ておかないと2期の内容が分からないということでもあるのかな。
空中戦闘シーンのカメラワークが派手派手で、これを劇場の大スクリーンで見たら迫力がありそうだなと…。
ライバルキャラ?の登場で、更に戦闘が派手派手になった印象を受けた。今後もずっと配置されて活躍するキャラなのだろう…。
TVアニメ1期を視聴してること前提の構成ではあったけれど、作画クオリティは高いし、アクションシーンも多いしで、これならファンも満足しそうだなと…。
ググってみたら2019年の公開だったらしい。TVアニメ1期と2期の間を埋める内容だろうか。今月から2期が放送開始されるので、それに合わせて復習/履修/宣伝を兼ねた放送なのだろう…。これを見ておかないと2期の内容が分からないということでもあるのかな。
空中戦闘シーンのカメラワークが派手派手で、これを劇場の大スクリーンで見たら迫力がありそうだなと…。
ライバルキャラ?の登場で、更に戦闘が派手派手になった印象を受けた。今後もずっと配置されて活躍するキャラなのだろう…。
TVアニメ1期を視聴してること前提の構成ではあったけれど、作画クオリティは高いし、アクションシーンも多いしで、これならファンも満足しそうだなと…。
[ ツッコむ ]
以上、1 日分です。