动画,并且支持透明色(如果你不知道这个名字,稍后有讲解)哦!
void CMyView::RenderView()
{
CclientDC dc(this);
Static int curframe=0;
m_myimglist.Draw(&dc,curframe,Cpoint(0,0),ILD_TRANSPARENT);
curframe++;
If(curframe > m_myimglist.GetImageCount())
Curframe=0;
}
上面这个代码没有写擦除的操作,因为这根据具体需要有较大不同。如果你只有一个精灵动画的话,你可以用一个Bitmap对象保存精灵所占矩形区域的图像。你也可能需要有一个大的背景图每帧都要更新(这里我不讨论象dirty rect这样的优化方法),所以你只要每次都画背景,然后画精灵就好了。
怎么样?你已经实现了基本的动画系统,就是这么简单。
消除闪烁
如果你真正实现上面的代码的话,你会发现画面一闪一闪的,十分的不爽。L 很多人都会怪到GDI头上,他们又会骂MS,说GDI太慢了。其实非也(不是指MS不该骂,呵呵),任何直接写屏幕的操作都会产生闪烁,在DOS下直接写显存或者用DirectDraw API直接写Primary Surface都会闪烁,因为你每个更新显示的操作都会被用户马上看到(因为垂直回扫的原因, 或许会有延迟)。
消除闪烁最简单也是最经典的方法就是双缓冲(Double buffer)。所谓的双缓冲其实道理非常简单,就是说我们在其它地方(简单的说就是不针对屏幕,不显示出来的地方)开辟一个存储空间,我们把所有的动画都要渲染到这个地方,而不是直接渲染到屏幕上(针对屏幕的存储区域)。在GDI中,直接针对屏幕就是窗口DC,”不可见的地方”一般可以用Memory DC。在把所有动画渲染到后台缓冲之后,再一下次整体拷贝到屏幕缓冲区!
在纯软件2D图形引擎中,双缓冲一般意味着在内存中开辟一个区域用来存储像素数据。而在DirectDraw中可以创建Back Surface,在把所有动画渲染到Back Suface上之后,然后使用Flip操作使其可见,Flip操作因为只是设置可见surface的地址,所以非常快速。
让我们重写一下void CMyView::RenderView()函数,来用GDI实现双缓冲:
void CMyView::RenderView()
{
CClientDC dc(this);
CRect rc;
GetClientRect(rc);
CDC memdc;
memdc.CreateCompatibleDC(&dc);
CBitmap bmp;
Bmp. CreateCompatibleBitmap (&dc,rc.Width(),rc.Height());
CBitmap *oldbmp=memdc.SelectObject(&bmp);
Static int curframe=0;
m_myimglist.Draw(&memdc,curframe,Cpoint(0,0),ILD_TRANSPARENT);
curframe++;
If(curframe > m_myimglist.GetImageCount())
Curframe=0;
if(oldbmp)
memdc.SelectObject(oldbmp);
&nbs