59 章

先ほど見て頂きましたが、まず、実行結果ご覧下さい。

実行結果



壁が連続でスクロールしているのがわかりますね。

しかし、この壁を一つ一つ登録し、一つ一つを独立して計算し、フェードインやフェードアウトの計算するのはめんどくさそうです。

そこで

「この画像をこの位置にズラーっと壁みたいに表示してくれ!」

「この画像をこの位置にズラーっと地面として表示してくれ!」

のような初期化の仕方をすることで、

丁度いい間隔で一つ一つのポリゴンを設定し、登録も計算も自動でやってくれたら便利そうです。

この章では1行初期化関数を書くだけで、いくらでも壁や地面が追加されていくようなプログラムを考えて見ましょう。

最初面倒でも、後から非常に楽になります。

まず、多くのポリゴンを一括管理するわけですから、先ほどのポリゴン情報の構造体を統括する更なる構造体が必要です。

沢山のポリゴンを統括する構造体をObject_tとして作りました。

個々のポリゴンはその子供と言う意味でObChild_tとして作りました。

構造体は先ほどの構造と大して変わっていませんが、以下のようになっています。

//一つのテクスチャーについての構造体
typedef struct{
    float x,y,z;//中心点
    VERTEX_3D Vertex[6] ;        //描画用頂点6個
} ObChild_t;

//沢山のテクスチャーが集まった一つの情報。
//例えば左にダーっと連続で表示される壁は沢山ののObChild_tをここで管理している。
//Obchild_tの集合
typedef struct{
    int Type;    // 0:画面に平行、1:画面に垂直
    int Img;    //画像
    int ImgSize;
    int ImgX1,ImgX2,ImgY1,ImgY2;
    float LargeX,LargeY;//縦横の大きさ(Typeが1の時はLargeXがLargeZの役割をする)
    float Zhaba;        //奥行き幅
    float FromZ,ToZ;    //どこからどこまで奥行きを設定するか
    float FadeFromZ,FadeToZ;    //どこからどこまでフェードを設定するか(消える瞬間フェードアウト、現れる瞬間フェードインする)
    int ObchindMax;
    ObChild_t ObChild[ OBCHILD_MAX ];
} Object_t;


ここで新しく Zhaba という変数が出てきました。「奥行きZの幅」って意味の変数です。

これは何かと言うと

このように、テクスチャーを何枚も連続で貼っていくわけですが、

「FromZ〜ToZの間、テクスチャ5枚で表現してくれ」みたいな命令をすれば自動的にそれにあったZhabaを計算してテクスチャの

奥行きを計算してくれたら便利そうなので、こういう変数を作りました。

また、「FromZ〜ToZの間、テクスチャ5枚で表現してくれ」と言われたら同時に表示するテクスチャは6枚必要であることに注意して下さい。

何故かというと、進行方向に対して逆の端のテクチャが無いとして、真ん中の5枚だけが、自分の方に近づいていっていると考えると、

「FromZ」の位置に描画するテクスチャがなくなってしまうのが解ると思います。

その為下の画像のように、後ろにもう一枚必要なのです。
この枚数を ObchildMax という変数に格納してやります。

また、もう一つ重要な事があります。それは「奥にあるものから描かないといけない」と言う事です。

手前にあるものを描いた後で、奥にあるものを書いてしまうとおかしなことになってしまいます。

そこで常にZでソートする必要があります。

サンプルでは同じオブジェクト内でしかソートしていませんから、

異なるオブジェクト間で重なりがある場合は、全体でソートする必要があることも頭に入れておいて下さい。

この辺に注意しながらプログラムをみて行きましょう。

まず、構造体の初期化です。初期化に必要な情報が非常に多くなってしまった為、見にくいのですが、頑張ってみて下さい(汗
/*
int ImgHandle   : 画像ハンドル
int ImgSize     : 画像サイズ
int ImgX1       : 画像の使用する部分左上座標
int ImgY1       : 画像の使用する部分左上座標
int ImgX2       : 画像の使用する部分右下座標
int ImgY2       : 画像の使用する部分右下座標
float LargeX    : 描画する大きさ(横)
float LargeY    : 描画する大きさ(縦)
int Type        : 描画タイプ 0:画面と同じ向き 1:画面に垂直(壁) 2:画面に垂直(地面)
float FromZ     : 描画を始める奥行き
float FadeFromZ : フェードインを始める奥行き
float FadeToZ   : フェードアウトを始める奥行き
float ToZ       : 描画を終わる奥行き
float GraphX    : 描画する中心点
float GraphY    : 描画する中心点
int ObchildMax  : typeが0の場合のみ、同時にいくつ表示するか
*/


これだけ初期化に必要な情報があります。IniObj関数の引数は先頭の*Ob以外、上の順番で受け取っているので、参考にして下さい。


void IniObj(Object_t *Ob, int ImgHandle, int ImgSize, int ImgX1, int ImgY1, int ImgX2, int ImgY2, float LargeX, float LargeY,
              int Type, float FromZ, float FadeFromZ, float FadeToZ, float ToZ, float GraphX, float GraphY, int ObchildMax){
    int i,s;


沢山のテクスチャを統括する構造体Objectはサンプルでは最大3つまで登録出来るようにしてあります。
この辺は余力があれば動的確保してみて下さい


    if( ObjectNum >= OBJECT_NUM_MAX-1 ){
        printfDx("オブジェクト登録オーバー\n");
        return ;
    }
    ObjectNum++;//オブジェクトの登録数加算


後は代入ばっかりです。


    Ob->Img     = ImgHandle;//画像ハンドル
    Ob->ImgSize = ImgSize;//画像サイズ
    Ob->ImgX1   = ImgX1;
    Ob->ImgY1   = ImgY1;
    Ob->ImgX2   = ImgX2;
    Ob->ImgY2   = ImgY2;
    Ob->LargeX  = LargeX;//とりあえず描画する大きさを適当に設定。縦・横比は素材の通りにする
    Ob->LargeY  = LargeY;
    Ob->Type    = Type;//タイプを垂直に
    Ob->FromZ      =  FromZ;//描画開始地点
    Ob->FadeFromZ  =  FadeFromZ;//描画フェードイン開始地点
    Ob->FadeToZ    =  FadeToZ;//描画フェードアウト開始地点
    Ob->ToZ        =  ToZ;//描画終了地点
    Ob->ObchindMax = OBCHILD_MAX;


タイプが0ということは、画面に垂直だと言う事です。
つまりサンプルでいうとサクラにあたります。
画面に垂直な物体は描画する個数を指定出来るようにしてあります。
それ以外のタイプについては、サンプルでは定義の個数を使うようにしてあります。


    if( Ob->Type == 0 ){
        Ob->ObchindMax = ObchildMax;
    }
    if( Ob->ObchindMax - 1 <= 0 ){
        printfDx("表示数の設定が異常です\n");
        return ;
    }
        //Zの幅計算
    Ob->Zhaba = (Ob->FromZ - Ob->ToZ) / (Ob->ObchindMax-1);


ここで何故-1なのかは上で説明した通り、描画可能最大数-1枚が.FromZ〜.ToZにあるテクスチャの枚数になるからです。
Z幅を計算し、描画を始める地点から描画を終わる地点までのポリゴンの地点を自動計算してセットしていっています。


    float ou1 = (float)Ob->ImgX1 / Ob->ImgSize, ou2 = (float)(Ob->ImgX2 - Ob->ImgX1) / Ob->ImgSize;
    float ov1 = (float)Ob->ImgY1 / Ob->ImgSize, ov2 = (float)(Ob->ImgY2 - Ob->ImgY1) / Ob->ImgSize;
    for(s=0; s<Ob->ObchindMax; s++){
        Ob->ObChild[s].x = GraphX;
        Ob->ObChild[s].y = GraphY;
        Ob->ObChild[s].z = Ob->ToZ - Ob->Zhaba + Ob->Zhaba * s;;
        for(i=0; i<6; i++){
            Ob->ObChild[s].Vertex[i].r = Ob->ObChild[s].Vertex[i].g = Ob->ObChild[s].Vertex[i].b = Ob->ObChild[s].Vertex[i].a = 255;
            Ob->ObChild[s].Vertex[i].u = ou1 + ou2 * VtPm[i].u;
            Ob->ObChild[s].Vertex[i].v = ov1 + ov2 * VtPm[i].v;
        }
    }
}


初期化関数はこちらです。オブジェクトの初期化関数IniObjに必要な情報を渡すだけで、「壁」や「地面」が増えていきます。
ここで注意すべきなのは、同じ画像を何回も読み込まない事です。
3D関数では、「画像のここ〜ここを使う」という指定の仕方が出来ました。
ですから、一つの画像ファイルの中に、複数の画像が入っている場合もあります。サンプルでもそうです。
この時、画像ハンドルを作るのは一回にして下さい。2回ロードすると、2倍の容量を食います。
関数に渡す情報がかなり多いので、引数は一つ一つ改行し、注釈を書いていったほうが見易いと思います(サンプルでは行数を短くする為省いてあります)


void ini (){
    int ImgHandle;
    ObjectNum = 0;
    ImgHandle = LoadGraph( "mydat/img/tex.png" );
    IniObj(&Object[0], ImgHandle, 512,  0,  0, 256, 128, 250, 50, 2, 1000, 400, -200, -400, 320, 240-90, OBCHILD_MAX);
    IniObj(&Object[1], ImgHandle, 512, 60,270, 405, 512, 180,125, 0, 1000, 400, -200, -400, 470, 275, 6);
    ImgHandle = LoadGraph( "mydat/img/kabe.png" );
    IniObj(&Object[2], ImgHandle, 512,  0,  0, 390, 512,  73, 90, 1, 1000, 400, -200, -400, 170, 240, OBCHILD_MAX);
}


次に、オブジェクトの計算をします。
まず、タイプにわけて座標を計算します。これは前の章と似たような感じですね。


void ClacObject(){
    int t,s,i;
    for(t=0; t<ObjectNum; t++){
        for(s=0; s<Object[t].ObchindMax; s++){
            Object[t].ObChild[s].z-=3;
            for(i=0;i<6;i++){
                switch(Object[t].Type){
                    case 0://画面に平行
                        Object[t].ObChild[s].Vertex[i].pos.x = Object[t].ObChild[s].x + Object[t].LargeX * VtPm[i].x ;    
                        Object[t].ObChild[s].Vertex[i].pos.y = Object[t].ObChild[s].y + Object[t].LargeY * VtPm[i].y ;
                        Object[t].ObChild[s].Vertex[i].pos.z = Object[t].ObChild[s].z ;
                        break;
                    case 1://画面に垂直(壁)
                        Object[t].ObChild[s].Vertex[i].pos.x = Object[t].ObChild[s].x;    
                        Object[t].ObChild[s].Vertex[i].pos.y = Object[t].ObChild[s].y + Object[t].LargeY * VtPm[i].y ;
                        Object[t].ObChild[s].Vertex[i].pos.z = Object[t].ObChild[s].z + Object[t].Zhaba/2* VtPm[i].x ;
                        break;
                    case 2://画面に垂直(床)
                        Object[t].ObChild[s].Vertex[i].pos.x = Object[t].ObChild[s].x + Object[t].LargeX * VtPm[i].x;    
                        Object[t].ObChild[s].Vertex[i].pos.y = Object[t].ObChild[s].y ;
                        Object[t].ObChild[s].Vertex[i].pos.z = Object[t].ObChild[s].z + Object[t].Zhaba/2* VtPm[i].y;
                        break;
                }
            }
        }


次に、フェードアウト、フェードイン。これも前と同じです。


        if( Object[t].FromZ - Object[t].FadeFromZ <= 0 ){
            printfDx("Object[%d].Fromの設定がおかしい\n",t);
        }
        else if( Object[t].FadeToZ - Object[t].ToZ <= 0 ){
            printfDx("Object[%d].Toの設定がおかしい\n",t);
        }
        else{
            for(s=0; s<Object[t].ObchindMax; s++){
                for(i=0; i<6; i++){
                    float z = Object[t].ObChild[s].Vertex[i].pos.z;
                    //位置が描画する範囲より遠かったら透過0
                    if     (z < Object[t].ToZ){
                        Object[t].ObChild[s].Vertex[i].a = 0;
                    }
                    //(近づいている場合)フェードインする位置だったら
                    else if(Object[t].ToZ < z && z <=Object[t].FadeToZ){
                        Object[t].ObChild[s].Vertex[i].a = (unsigned char)(255.0f / (Object[t].FadeToZ - Object[t].ToZ) * (z - Object[t].ToZ)) ;
                    }
                    //通常描画する位置なら
                    else if(Object[t].FadeToZ <= z && z <= Object[t].FadeFromZ){
                        Object[t].ObChild[s].Vertex[i].a = 255;
                    }
                    //(近づいてる場合)フェードアウトする位置だったら
                    else if(Object[t].FadeFromZ <= z && z < Object[t].FromZ){
                        Object[t].ObChild[s].Vertex[i].a = (unsigned char)(255.0f / (Object[t].FromZ - Object[t].FadeFromZ) * (Object[t].FromZ - z)) ; 
                    }
                    //描画する範囲より近かったら透過0
                    else if(Object[t].FromZ < z){
                        Object[t].ObChild[s].Vertex[i].a = 0;
                    }
                }


ここでは、画像をループさせる処理をしています。
画像が一番手前まで来たら、一番奥へ移動させてループスクロールするように処理をしています。


                //近づいて見えなくなったら
                if(Object[t].ObChild[s].z < Object[t].ToZ - Object[t].Zhaba*0.5f){
                    //一番向こう側へ
                    float sub = (Object[t].ToZ - Object[t].Zhaba*0.5f)- Object[t].ObChild[s].z;
                    Object[t].ObChild[s].z = Object[t].FromZ + Object[t].Zhaba*0.5f - sub;
                }
                //遠ざかって見えなくなったら
                else if(Object[t].ObChild[s].z > Object[t].FromZ + Object[t].Zhaba*0.5f){
                    //一番こちら側へ
                    float sub = Object[t].ObChild[s].z - (Object[t].FromZ + Object[t].Zhaba*0.5f);
                    Object[t].ObChild[s].z = Object[t].ToZ - Object[t].Zhaba*0.5f + sub;
                }
            }
        }
    }
}


次に、Zでテクスチャをソートしています。ソートには解り易い単純ソートを用いました。
なんてことないただの単純ソートです。


void SwapObChild(ObChild_t *Ob1,ObChild_t *Ob2){
    ObChild_t t = *Ob1;
    *Ob1 = *Ob2;
    *Ob2 = t;
}

void SortObject(){
    int i,j,t;
    for(t=0; t<ObjectNum; t++){
        for (i = 0; i < Object[t].ObchindMax ; i++) {
            for (j = i + 1; j < Object[t].ObchindMax ; j++) {
                if ( Object[t].ObChild[i].z < Object[t].ObChild[j].z ) {
                    SwapObChild( &Object[t].ObChild[i],  &Object[t].ObChild[j] );
                }
            }
        }
    }
}


ではプログラム全体を見渡してみましょう。

--- main.cpp --- 

#include "../../../include/DxLib.h"

//少なくしすぎるとだめ。-1で使用している。
#define OBCHILD_MAX 11
#define OBJECT_NUM_MAX 10

//三角形のポリゴン2つで四角形を描画する為の値。数値固定なので、覚える必要なし
typedef struct{
    float x,y;
    float u,v;
}VtPm_t;
VtPm_t VtPm[6]={{-1,1,0,0},{1,1,1,0},{-1,-1,0,1},{1,-1,1,1},{-1,-1,0,1},{1,1,1,0}};

//一つのテクスチャーについての構造体
typedef struct{
    float x,y,z;//中心点
    VERTEX_3D Vertex[6] ;        //描画用頂点6個
} ObChild_t;

//沢山のテクスチャーが集まった一つの情報。
//例えば左にダーっと連続で表示される壁は沢山ののObChild_tをここで管理している。
//Obchild_tの集合
typedef struct{
    int Type;    // 0:画面に平行、1:画面に垂直
    int Img;    //画像
    int ImgSize;
    int ImgX1,ImgX2,ImgY1,ImgY2;
    float LargeX,LargeY;//縦横の大きさ(Typeが1の時はLargeXがLargeZの役割をする)
    float Zhaba;
    float FromZ,ToZ;    //どこからどこまで奥行きを設定するか
    float FadeFromZ,FadeToZ;    //どこからどこまでフェードを設定するか(消える瞬間フェードアウト、現れる瞬間フェードインする)
    int ObchindMax;
    ObChild_t ObChild[ OBCHILD_MAX ];
} Object_t;

int ObjectNum;
Object_t Object[OBJECT_NUM_MAX];
/*
int ImgHandle   : 画像ハンドル
int ImgSize     : 画像サイズ
int ImgX1       : 画像の使用する部分左上座標
int ImgY1       : 画像の使用する部分左上座標
int ImgX2       : 画像の使用する部分右下座標
int ImgY2       : 画像の使用する部分右下座標
float LargeX    : 描画する大きさ(横)
float LargeY    : 描画する大きさ(縦)
int Type        : 描画タイプ 0:画面と同じ向き 1:画面に垂直(壁) 2:画面に垂直(地面)
float FromZ     : 描画を始める奥行き
float FadeFromZ : フェードインを始める奥行き
float FadeToZ   : フェードアウトを始める奥行き
float ToZ       : 描画を終わる奥行き
float GraphX    : 描画する中心点
float GraphY    : 描画する中心点
int ObchildMax  : typeが0の場合のみ、同時にいくつ表示するか
*/
void IniObj(Object_t *Ob, int ImgHandle, int ImgSize, int ImgX1, int ImgY1, int ImgX2, int ImgY2, float LargeX, float LargeY,
              int Type, float FromZ, float FadeFromZ, float FadeToZ, float ToZ, float GraphX, float GraphY, int ObchildMax){
    int i,s;

    if( ObjectNum >= OBJECT_NUM_MAX-1 ){
        printfDx("オブジェクト登録オーバー\n");
        return ;
    }
    ObjectNum++;//オブジェクトの登録数加算

    Ob->Img = ImgHandle;//画像ハンドル
    Ob->ImgSize = ImgSize;//画像サイズ
    Ob->ImgX1 = ImgX1;
    Ob->ImgY1 = ImgY1;
    Ob->ImgX2 = ImgX2;
    Ob->ImgY2 = ImgY2;
    Ob->LargeX = LargeX;//とりあえず描画する大きさを適当に設定。縦・横比は素材の通りにする
    Ob->LargeY = LargeY;
    Ob->Type = Type;//タイプを垂直に
    Ob->FromZ     =  FromZ;//描画開始地点
    Ob->FadeFromZ =  FadeFromZ;//描画フェードイン開始地点
    Ob->FadeToZ   =  FadeToZ;//描画フェードアウト開始地点
    Ob->ToZ       =  ToZ;//描画終了地点
    Ob->ObchindMax = OBCHILD_MAX;
    if( Ob->Type == 0 ){
        Ob->ObchindMax = ObchildMax;
    }
    if( Ob->ObchindMax - 1 <= 0 ){
        printfDx("表示数の設定が異常です\n");
        return ;
    }
        //Zの幅計算
    Ob->Zhaba = (Ob->FromZ - Ob->ToZ) / (Ob->ObchindMax-1);

    float ou1 = (float)Ob->ImgX1 / Ob->ImgSize, ou2 = (float)(Ob->ImgX2 - Ob->ImgX1) / Ob->ImgSize;
    float ov1 = (float)Ob->ImgY1 / Ob->ImgSize, ov2 = (float)(Ob->ImgY2 - Ob->ImgY1) / Ob->ImgSize;
    for(s=0; s<Ob->ObchindMax; s++){
        Ob->ObChild[s].x = GraphX;
        Ob->ObChild[s].y = GraphY;
        Ob->ObChild[s].z = Ob->ToZ - Ob->Zhaba + Ob->Zhaba * s;;
        for(i=0; i<6; i++){
            Ob->ObChild[s].Vertex[i].r = Ob->ObChild[s].Vertex[i].g = Ob->ObChild[s].Vertex[i].b = Ob->ObChild[s].Vertex[i].a = 255;
            Ob->ObChild[s].Vertex[i].u = ou1 + ou2 * VtPm[i].u;
            Ob->ObChild[s].Vertex[i].v = ov1 + ov2 * VtPm[i].v;
        }
    }
}

void ini (){
    int ImgHandle;
    ObjectNum = 0;
    ImgHandle = LoadGraph( "mydat/img/tex.png" );
    IniObj(&Object[0], ImgHandle, 512,  0,  0, 256, 128, 250, 50, 2, 1000, 400, -200, -400, 320, 240-90, OBCHILD_MAX);
    IniObj(&Object[1], ImgHandle, 512, 60,270, 405, 512, 180,125, 0, 1000, 400, -200, -400, 470, 275, 6);
    ImgHandle = LoadGraph( "mydat/img/kabe.png" );
    IniObj(&Object[2], ImgHandle, 512,  0,  0, 390, 512,  73, 90, 1, 1000, 400, -200, -400, 170, 240, OBCHILD_MAX);
}

void ClacObject(){
    int t,s,i;
    for(t=0; t<ObjectNum; t++){
        for(s=0; s<Object[t].ObchindMax; s++){
            Object[t].ObChild[s].z-=3;
            for(i=0;i<6;i++){
                switch(Object[t].Type){
                    case 0://画面に平行
                        Object[t].ObChild[s].Vertex[i].pos.x = Object[t].ObChild[s].x + Object[t].LargeX * VtPm[i].x ;    
                        Object[t].ObChild[s].Vertex[i].pos.y = Object[t].ObChild[s].y + Object[t].LargeY * VtPm[i].y ;
                        Object[t].ObChild[s].Vertex[i].pos.z = Object[t].ObChild[s].z ;
                        break;
                    case 1://画面に垂直(壁)
                        Object[t].ObChild[s].Vertex[i].pos.x = Object[t].ObChild[s].x;    
                        Object[t].ObChild[s].Vertex[i].pos.y = Object[t].ObChild[s].y + Object[t].LargeY * VtPm[i].y ;
                        Object[t].ObChild[s].Vertex[i].pos.z = Object[t].ObChild[s].z + Object[t].Zhaba/2* VtPm[i].x ;
                        break;
                    case 2://画面に垂直(床)
                        Object[t].ObChild[s].Vertex[i].pos.x = Object[t].ObChild[s].x + Object[t].LargeX * VtPm[i].x;    
                        Object[t].ObChild[s].Vertex[i].pos.y = Object[t].ObChild[s].y ;
                        Object[t].ObChild[s].Vertex[i].pos.z = Object[t].ObChild[s].z + Object[t].Zhaba/2* VtPm[i].y;
                        break;
                }
            }
        }

        if( Object[t].FromZ - Object[t].FadeFromZ <= 0 ){
            printfDx("Object[%d].Fromの設定がおかしい\n",t);
        }
        else if( Object[t].FadeToZ - Object[t].ToZ <= 0 ){
            printfDx("Object[%d].Toの設定がおかしい\n",t);
        }
        else{
            for(s=0; s<Object[t].ObchindMax; s++){
                for(i=0; i<6; i++){
                    float z = Object[t].ObChild[s].Vertex[i].pos.z;
                    //位置が描画する範囲より遠かったら透過0
                    if     (z < Object[t].ToZ){
                        Object[t].ObChild[s].Vertex[i].a = 0;
                    }
                    //(近づいている場合)フェードインする位置だったら
                    else if(Object[t].ToZ < z && z <=Object[t].FadeToZ){
                        Object[t].ObChild[s].Vertex[i].a = (unsigned char)(255.0f / (Object[t].FadeToZ - Object[t].ToZ) * (z - Object[t].ToZ)) ;
                    }
                    //通常描画する位置なら
                    else if(Object[t].FadeToZ <= z && z <= Object[t].FadeFromZ){
                        Object[t].ObChild[s].Vertex[i].a = 255;
                    }
                    //(近づいてる場合)フェードアウトする位置だったら
                    else if(Object[t].FadeFromZ <= z && z < Object[t].FromZ){
                        Object[t].ObChild[s].Vertex[i].a = (unsigned char)(255.0f / (Object[t].FromZ - Object[t].FadeFromZ) * (Object[t].FromZ - z)) ; 
                    }
                    //描画する範囲より近かったら透過0
                    else if(Object[t].FromZ < z){
                        Object[t].ObChild[s].Vertex[i].a = 0;
                    }
                }
                //近づいて見えなくなったら
                if(Object[t].ObChild[s].z < Object[t].ToZ - Object[t].Zhaba*0.5f){
                    //一番向こう側へ
                    float sub = (Object[t].ToZ - Object[t].Zhaba*0.5f)- Object[t].ObChild[s].z;
                    Object[t].ObChild[s].z = Object[t].FromZ + Object[t].Zhaba*0.5f - sub;
                }
                //遠ざかって見えなくなったら
                else if(Object[t].ObChild[s].z > Object[t].FromZ + Object[t].Zhaba*0.5f){
                    //一番こちら側へ
                    float sub = Object[t].ObChild[s].z - (Object[t].FromZ + Object[t].Zhaba*0.5f);
                    Object[t].ObChild[s].z = Object[t].ToZ - Object[t].Zhaba*0.5f + sub;
                }
            }
        }
    }
}

void SwapObChild(ObChild_t *Ob1,ObChild_t *Ob2){
    ObChild_t t = *Ob1;
    *Ob1 = *Ob2;
    *Ob2 = t;
}

//Zでテクスチャをソート
void SortObject(){
    int i,j,t;
    for(t=0; t<ObjectNum; t++){
        for (i = 0; i < Object[t].ObchindMax ; i++) {
            for (j = i + 1; j < Object[t].ObchindMax ; j++) {
                if ( Object[t].ObChild[i].z < Object[t].ObChild[j].z ) {
                    SwapObChild( &Object[t].ObChild[i],  &Object[t].ObChild[j] );
                }
            }
        }
    }
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
    int s,t;
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

    ini();

    while(ProcessMessage()==0 && ClearDrawScreen()==0 && CheckHitKey(KEY_INPUT_ESCAPE)==0){
        ClacObject();
        SortObject();
        SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//ポリゴンが荒く見えないような描画の仕方「バイリニア法」
        for(t=0; t<ObjectNum; t++){
            for(s=0; s<Object[t].ObchindMax; s++){
                DrawPolygon3D( Object[t].ObChild[s].Vertex, 2, Object[t].Img, TRUE ) ;
            }
        }
        SetDrawMode(DX_DRAWMODE_NEAREST);//描画の仕方を元に戻す
        ScreenFlip() ;
    }
    DxLib_End() ;
    return 0 ;
}


メイン関数のループ内で「バイリニア法」なる描画の仕方をしました。

これは拡大した時にドットが目立たないようにするものです。

ドットとドットの間を補間して描画してくれるため、滑らかな描画が可能です。

これをするのとしないのとではどう違うか、実際にやってみて下さい。特に桜が拡大する時に良く解ると思います。

しかし、何となくぼやけた画像になる為、補間の必要が無い時は、標準の描画の方法で描画してあげましょう。

- Remical Soft -