zoukankan      html  css  js  c++  java
  • C++游戏界面不流畅的问题

    或许是我游戏玩多了,我突然发现,我的C++程序画面画面一顿一顿的,不流畅.肯定哪里不正确,要改.

    奇怪啊,为什么我曾经,在我电脑上就不这么卡,就看不出画面一顿一顿的呢?

    百度了,狗狗了,必应了,然而,并没有什么卵用.

    扭头问老大,老大一声令下:不许问别人,这个问题单独解决,顺便提交个解决方式我.

    的确,人须要有解决这个问题的能力,这一点非常重要.事实上,最重要的是记性,<<最强大脑>>没记性再好的分析能力都没用.

    真羡慕你们的好记性...

    羡慕虽好,然而,并没有什么卵用.还得靠自己多锻炼.


    好了,開始分析问题:

    问题:我程序里,用w,s,a,d按键控制摄像机的前进,后退,左移,右移.但是,比方,我一直按着w,前进,前进的公式为:

            w = 10像素/秒 * 时间长度.

    现象:一段时间不动,然后突然跳到前面,就像我按着前进按键,它不动,然后过会儿突然闪现到前面...一直这样,画面一愣一愣的...

    猜想:是不是我近期改了什么代码所致?

    对,我近期是加入了着色器程序,那我执行没有着色器的程序试试看

             结果:一样,一愣一愣的,并且别的项目也一样.

             结论:跟新改动的代码有关系可能性不大.

    继续猜想:可能 win32程序中消息循环那儿 timedelta有问题

        代码例如以下所看到的:

    void Application::Run()
    {
    	MSG msg;
    	static float lastTime = (float)timeGetTime();//上一次的时间
    	ZeroMemory(&msg, sizeof(MSG));
    	while (msg.message != WM_QUIT)
    	{
    		if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
    		{
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    		else
    		{
    			float currTime = (float)timeGetTime();//当前的时间
    			float timedelta = (currTime - lastTime)*0.001f;	//时间间隔
    			//世界更新
    			m_GameWorld->Update((float)timedelta);
    			//更新fps
    			UpdateFPS();
    			//画一帧
    			DrawOneFrame();
    
    			lastTime = currTime;
    		}
    	}
    }

    下断点观察 timedelta 变量是不切实际的,由于消息循环速度很很快,仅仅有几毫秒甚至仅仅有几微秒!!!

    那怎么观察timedelta变量的变化呢?老大说用控制台来输出这个变量.没搞错吧...win32  MFC窗体怎么用控制台,特么逗我么.

    没文化真可怕.

    一搜,果然有win32上附加生成一个控制台的方法,

    步骤:1.加头文件:#include <conio.h>

         2.程序的开头加函数:AllocConsole();

         3.在要输出变量的地方加:_cprintf("timedelta = %f ", timedelta);

         4.程序的最后释放分配的控制台:FreeConsole();

    ok,配置完成,赶紧看下输出数据吧:

        结果:

        

         一大堆的0.000000,然后突然0.128000

        结论:罪魁祸首原来在这里,这就是导致不孕不...不是,呸,导致画面不平滑,一愣一愣的根本原因.

    其它时候都是0,突然0.128大动一下,问题的根本原因已经找到.这就是导致显示不连续的原因.

    疑惑:消息循环run函数为什么数据会不连续?

    更新,渲染,一圈下来时间竟然为0?

    怎么可能...

    猜想:我用的数据类型是float,精度难道不够用吗?粗略预计下,画面fps在2000左右.也就是0.5毫秒一帧,

              也就是0.0005秒应该没超过float的精度范围啊...

              出于好奇,还是换了双精度的double试了一下,

             然而,并没有什么卵用.

              说明不是精度的缘故.

    继续猜想:或许跟timeGetTime这个获取时间的函数有关系,吾查询了网上大量的文献资料,发现它获取的时间精度也不高

    误差几十,甚至几百毫秒,我就说嘛,远远达不到这台电脑的fps需求嘛(公司电脑配置太好,fps能上万,也就是误差要在0.1毫秒之内)

    我明确了...这也是为什么在我自己垃圾电脑上发觉不出来一愣一愣的原因了,由于我电脑配置太低,效果不明显...

    附公司电脑配置图:

    (装B,莫打我...)

    所以寻找高精度的计时函数QueryPerformanceFrequency()QueryPerformanceCounter()

    这两函数牛逼啊,根硬件时钟的晶振是一个级别的,资料上说,精确到了千分之中的一个毫秒,也就是微秒级别的...

    好啊,要的就是你啊....


    下面便是改动的消息循环run的代码:

    void Application::Run()
    {
    	MSG msg;
    
    	LARGE_INTEGER nFreq;
    	LARGE_INTEGER nBeginTime, nEndTime;
    	QueryPerformanceFrequency(&nFreq);//获得时钟频率
    	QueryPerformanceCounter(&nBeginTime);//開始的时间
    	
    	ZeroMemory(&msg, sizeof(MSG));
    	while (msg.message != WM_QUIT)
    	{
    		if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
    		{
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    		else
    		{
    			QueryPerformanceCounter(&nEndTime);//结束的时间		 
    			float timedelta = (float)(nEndTime.QuadPart - nBeginTime.QuadPart) / (float)nFreq.QuadPart;
    
    			_cprintf("timedelta = %f
    ", timedelta);//控制台输出结果
    
    			//世界更新
    			m_GameWorld->Update((float)timedelta);	
    			//d3d设备指针一个项目里仅仅能有唯一一个
    			UpdateFPS();
    			//画一帧
    			DrawOneFrame();
    
    			nBeginTime = nEndTime;
    		}		
    	}	
    }
    结果:

         

    唉,整个人心情都好了,摄像机移动,画面流畅得一笔啊...

    另外,说到时间,我就想到了晶振,说到晶振,我就想到了15万元一仅仅的万国牌手表,心想,贵有什么用,准么?

    说到准,我想起了世界上最准的钟---原子钟:有铯原子钟,氢原子钟,铷原子钟,CPT原子钟,

    呀的,这玩意50亿年误差只是1秒...唉,人类真聪明,真可怕,说到聪明可怕...

    然而,并没有什么卵用,不能再说了,扯太远了,到此为止~!


    
  • 相关阅读:
    springmvc到底怎么工作的
    (netty专题)初步认识BIO、NIO、AIO
    dubbo基本使用理解
    warning: ignoring option PermSize=512m; support was removed in 8.0解决
    面试都看那些
    MySQL——通过EXPLAIN分析SQL的执行计划
    springboot中的json、gson、fastjson如何使用与日期格式转换
    如何生成一个不重复的四位数
    深入理解SpringCloud之Gateway 接上篇Webflux快速入门
    Layui 手册2
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6782506.html
Copyright © 2011-2022 走看看