第六十章 在游戏中试着使用3D背景吧

>>点此回到教程目录

在这一章中,我们把在第59章中完成的3D背景给适用到我们的游戏中吧。

源代码基本上没有必要改变。

只需要改变初始化函数的名字、改变main函数的名字,然后稍微变更一下main循环的处理即可。

这次将这个59章中的main.cpp文件以3Dbackground.cpp的名字追加到我们的游戏中吧。

在解决方案管理器的“graph”文件夹上右键→“添加”→“新项目”,然后追加3Dbackground.cppp。

复制粘贴到那里就行了。

ini()变更为ini3Dbackground()这个函数名。

main函数变更为Main3Dbackground()这个函数名,其内部的处理稍微进行了变更,请您确认。

具体修改的位置用水色标识出来了。

dat/img/back/3D/

另外,这一次追加了的图像都放在上面那个文件夹中。如果您是自己建立项目的话,请确认一下。

—在 3Dbackground.cpp 进行以下追加 —

/***修改请注意***/
#include "../include/GV.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;    //是否设定从哪儿到哪儿z深度上的移动
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("Object登录溢出\n");
        return ;
    }
    ObjectNum++;//Object登录数量增加

    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;//将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 Ini3Dbackground(){
    int ImgHandle;
    ObjectNum = 0;
    ImgHandle = LoadGraph( "../dat/img/back/3D/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( "../dat/img/back/3D/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] );
                }
            }
        }
    }
}

/***修改请注意***/
void Main3Dbackground(){//(60)
    int t,s;
    ClacObject();
    SortObject();
    SetDrawArea(FX,FY,FX+FMX,FY+FMY);//设定允许绘制的区域 
    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);//还原绘制方式
    SetDrawArea(0,0,640,480);//还原允许绘制的区域
}
/***修改请注意***/

—在 func.h 中把下面这些注释掉—

//      boss_shot_bulletH014,//漢字弾幕(56)
//      boss_shot_bulletH012,//漢字弾幕(53)
//      boss_shot_bulletH013,//漢字弾幕(53)

—在 ini.cpp 中进行红字部分追加—

//游戏初始化
void ini(){

        /***修改请注意***/
        Ini3Dbackground();//(60)
        /***修改请注意***/

        stage_count=1;
        memset(&ch,0,sizeof(ch_t));

—在 function.h 中进行以下追加 —

//3Dbackground.cpp//(60)
    GLOBAL void Ini3Dbackground();
    GLOBAL void Main3Dbackground();

—在 function.h 中进行以下追加—

        //读入AA弹幕的子弹坐标数据(56)
        GLOBAL int load_AA_dat(char name[64], BlAAPoint_t *Bp);

—在 graph_back.cpp 中进行以下修正 —

void graph_back_main(){
        //Boss为有效且为SC
        if(boss.flag==1 && boss.back_knd[boss.knd]==1)
                graph_back01();
        else//除此之外

        /***修改请注意***/
                Main3Dbackground();//(60)
//              graph_back00();

       /***修改请注意***/
}

运行结果


另外,如果我们载入的图像为kabe2.png的话就会是这个样子。

这个纹理要怎样贴上去我想是很容易理解的吧。

>>点此回到教程目录

results matching ""

    No results matching ""