第四十四章 制作支持DEBUG的函数吧

>>点此回到教程目录

接下来,随着处理的增加,我们发现渐渐地当错误出现的时候,我们已经很难弄清楚到底原因何在呢。

另外,我想也很难找出到底哪一块的代码是无用的。

因此,我们试着让在主循环中调用的每一个自定义函数都显示出各自在处理上消耗了多少时间吧。

这样一来,假设我们有大量的无用处理,或者在哪个地方混杂着奇怪的程序的话,那么肯定会在某个特定的地方有长时间的处理,那么我们就可以直接去看有问题的地方并进行修正就行了。

即便没有特别错误的地方,如果存在在没有充分考虑过的处理中耗时的函数的话,也很有必要去检查这个函数是否能够被优化,这么一来显示出各个函数的处理时间是很有作用的。

作为实现的方法,

时间测定函数(); 自定义函数(); 时间测定函数(); 像这样,将自定义函数用时间测定函数夹在中间,那么就能够获得处理时间了。

试着实现这个方法吧。

其次,本章中也试着对文字的绘制使用字体数据。

先定义保存字体句柄的font变量,然后我们在读取函数中把字体数据构建好。

—- 新增加check_time.cpp 文件,在其中进行以下追加—-

#include "../include/GV.h"
//名称的最大字数
#define STR_MAX 64
//可以检查的函数的最大数
#define FUNC_MAX 30
//计数当前是第几个
int func_count;
//保存上一次测定的时间
LONGLONG lt;
//保存测定数据用的变量
typedef struct{
        int tm;
        char str[STR_MAX];
}func_tm_t;
func_tm_t func_tm[FUNC_MAX];

//登录在st变量中接受到的数据。如果flag为1的话就重置
void enter_func_tm(char st[], int flag){
        int i;
        LONGLONG nowtm;
        if(func_count>=FUNC_MAX){
                printfDx("func_count的值%d异常\n",func_count);
                return ;
        }
        nowtm=GetNowHiPerformanceCount() ;
        if(nowtm-lt<INT_MAX){//如果在int可以表示的范围内的话
                func_tm[func_count].tm=(int)(nowtm-lt);//保存处理时间
                memcpy(func_tm[func_count].str,st,STR_MAX-1);//复制字符串
                func_tm[func_count].str[STR_MAX-1]=0;//放入终止符(\0)
        }
        else//如果超出的话
                func_tm[func_count].tm=-1;//错误

        lt=nowtm ;//保存上一次记录的时刻

        if(flag==1){//重置
                for(i=func_count+1;i<FUNC_MAX;i++)
                        func_tm[i].str[0]=0;
                func_count=0;
        }
        else
                func_count++;
}

//绘制数据
void draw_func_tm(int x, int y){
        int i;
        unsigned int total=0;
        for(i=0;i<FUNC_MAX;i++){
                if(func_tm[i].str[0]==0)break;
                DrawFormatStringToHandle(x,y+14*i,color[0],font[0],"%05.2f:%s",func_tm[i].tm/1000.0,func_tm[i].str );
                total+=func_tm[i].tm;
        }
        DrawFormatStringToHandle(x,y+14*i,color[0],font[0],"合計:%05.2f",total/1000.0);
}

现在我们为了进行精确的时间测定,试着使用了100万分之1秒(微秒)精度的GetNowHiPerformanceCount()函数。

既然有100万分之1秒的测定精度,那么1000秒钟就有10亿微秒,很快就会超过int类型的上限了。因此,返回值使用的是LONGLONG型,这一点请注意。

不过,1个函数的处理时间不可能有几千秒以上,因此我们还是将保存时间差的变量用int类型定义。

其次这个enter_func_tm以字符串作为参数。

我们把作为参数的字符串和测定了的时间放到一起在后面来显示。

为此我们定义把设置名称和测定时间放到一起func_tm_t类型。

函数的调用的情况,我们还是在其它地方一起来进行观察吧。

啊,由于另外还有一点就是在上一章中介绍了的draw_fps函数也放到绘制函数中了,请参照下面的介绍来确认这一点。

—-在 GV.h 中进行以下追加 —-

//其它变量
GLOBAL int font[20];

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

//check_time.cpp
        GLOBAL void enter_func_tm(char st[], int flag = 0);
        GLOBAL void draw_func_tm(int x, int y);

—-在 load.cpp 的 load() 中进行以下追加 —-

font[0] = CreateFontToHandle( "HGPゴシックE" , 15 , 2 , DX_FONTTYPE_ANTIALIASING_EDGE);

—-在 graph.cpp 的头部进行以下追加 —-

extern void draw_fps(int,int);
extern void draw_func_tm(int,int);

—-在 graph.cpp 的 graph_main() 函数中进行以下变更 —-

void graph_main(){

        if(bright_set.brt!=255)SetDrawBright(bright_set.brt,bright_set.brt,bright_set.brt);

        graph_back_main();//背景绘制main
        graph_effect(0);//敌人的消灭特效

        if(bright_set.brt!=255)SetDrawBright(255,255,255);

        graph_effect(4);//决死特效

        if(bright_set.brt!=255)SetDrawBright(bright_set.brt,bright_set.brt,bright_set.brt);

        graph_child();
        graph_item();//绘制道具
        graph_boss();
        graph_enemy();//敌人的绘制
        graph_cshot();//自机射击的绘制

        if(bright_set.brt!=255)SetDrawBright(255,255,255);

        graph_ch();//自机的绘制

        if(bright_set.brt!=255)SetDrawBright(bright_set.brt,bright_set.brt,bright_set.brt);

        graph_lazer();//激光的绘制
        graph_bullet();//子弹的绘制

        if(bright_set.brt!=255)SetDrawBright(255,255,255);

        graph_effect(1);//Boom的特效
        graph_effect(2);//Boom线的特效
        graph_effect(3);//Boom角色的特效
        graph_stage_title();//Title的显示
        graph_board();//面板的绘制
        graph_flash();//闪屏的绘制

        graph_develop();

        /***修改请注意***/
        draw_fps(0,465);//fps绘制
        draw_func_tm(450,250);//处理时间绘制
        /***修改请注意***/
}

—-在 main.cpp 的main函数中如下述注释那样变更—- —- 在enter_func_tm函数中进行变更追加 —-

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
        ChangeWindowMode(TRUE);//窗口模式
        if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

        while(ProcessLoop()==0){//主循环
                music_ini();
                switch(func_state){
                        case 0://游戏启动时的处理
                                load();         //读入数据
                                first_ini();//最开始的初始化
                                func_state=99;
                                break;
                        case 99://STG开始前的初始化
                                ini();
                                load_story();
                                func_state=100;
                                break;
                        case 100://通常处理
                                                 enter_func_tm("最初");
                                calc_ch();       enter_func_tm("角色計算");
                                ch_move();       enter_func_tm("角色移动");
                                cshot_main();    enter_func_tm("自机射击main");
                                enemy_main();    enter_func_tm("敌人处理main");
                                boss_shot_main();enter_func_tm("Boss射击main");
                                shot_main();     enter_func_tm("射击main");
                                out_main();      enter_func_tm("碰撞判定");
                                effect_main();   enter_func_tm("特效main");
                                calc_main();     enter_func_tm("计算main");
                                graph_main();    enter_func_tm("绘制main");
                                if(boss.flag==0)
                                        stage_count++;
                                break;
                        default:
                                printfDx("错误的func_state\n");
                                break;
                }
                music_play();                    enter_func_tm("音乐播放");
                fps_wait();                      enter_func_tm("待机的时间",1);
                if(CheckStateKey(KEY_INPUT_ESCAPE)==1)break;//按下ESC键则跳出循环
                ScreenFlip();//里外画面翻转
                count++;
        }
        DxLib_End();//DX Library终止处理
        return 0;
}

我们大可不必关注“最初”和“待机时间”这两项。

因为这两个分别是调整FPS的待机时间和与垂直同步配合的待机时间,因此值肯定会变大。

虽然这个和电脑的配置有关,不过各个自定义函数的处理时间尽量能在1ms以内就很不错了。

如果全部时间合计超过16.6ms的话,就是“丢帧(处理滞后)”的状态了。

请尽量不要变成这样。


运行结果


>>点此回到教程目录

results matching ""

    No results matching ""