您的位置:首页 > 编程语言 > C语言/C++

【VC++游戏开发#二】2D篇 —— 平滑的幻灯片放映效果

2013-10-23 18:09 253 查看
本文由BlueCoder编写   转载请说明出处:http://blog.csdn.net/crocodile__/article/details/12975077我的邮箱:bluecoder@yeah.net    欢迎大家和我交流编程心得我的微博:BlueCoder_黎小华    欢迎光临^_^  前段时间为了系统学习MFC,花了一星期的课余时间复习了c++,将<<C++ Primer>>看了一遍,感觉关于c++的见识涨了不少,毕竟看完大师级人物写的书籍确实应该有如获光明的感觉。不过由于时间的原因,有几章节没怎么祥看——当然,以后必定细细品味 
因此感叹一句:好久没写博客了啊——呵呵
 
ok,归入正题
 
今天上午看见Yorhom用HTML5实现了一个『HTML5梦幻之旅』-滚动播放的幻灯片效果,感觉不错。于是借着他给的灵感(刚好最近在学MFC),我用MFC来实现类似的效果(思想略有不同),先上一个效果gif:



 
下面我来讲解一下具体的实现
 
 
一、编译环境
VS2008企业完整版,创建一个MFC工程(项目名称为SlideBmp):



 
 
二、剖析实现思想先来看看我制作的一张示意图:
ClientWidth表示窗口客户区的宽度——这里就是View窗口



 
(1). 从左边出现的图片,预先放在横坐标为-ClientWidth的位置,然后启动计时器,增加横坐标,逐渐移动,直到横坐标为0——也就是到达了窗口客户区,就关闭计时器——这时图片刚好停留在客户区
(2). 同理,从右边出现的图片预先放在横坐标为ClientWidth处,后面的同(1)
 
这样实现的效果就是每次移动的图片会覆盖上一次的图片
怎么样,还是挺简单的吧?
 
 
 
三、剖析实现代码(1). 改变MFC默认的窗口外观——在CMainFrame::PreCreateWindow中,也就是创建框架窗口之前修改——代码如下:BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式

//更改窗口外观
CSize size;

//获取屏幕像素大小
size.cx = ::GetSystemMetrics(SM_CXSCREEN);
size.cy = ::GetSystemMetrics(SM_CYSCREEN);

//窗口风格(快捷菜单式的窗口, 无边框、标题栏)
cs.style = WS_POPUPWINDOW;
//去掉菜单
cs.hMenu = NULL;
//窗口标题名称
cs.lpszName = _T("SlideBmp");

//自定义窗口大小, 并窗口居中显示
cs.x = (size.cx - 486 ) / 2;
cs.y = (size.cy - 360) / 2;
cs.cx = 486;
cs.cy = 360;

return TRUE;

 
(2). 因为View窗口是MainFrame框架窗口的子窗口,因此应该在它上面做工作——贴图片
 
(3). 在构造函数中进行初始化工作CSlideBmpView::CSlideBmpView()
{
//初始化
m_index = 0;
m_start = 0;
m_isStart = true;
m_isLeft = false;
m_isLoad = true;
}
 
 
(4). 所需变量或成员的定义,在SlideBmpView.h头文件中
全局变量//计时器ID
#define ID_TIMER_PAINT 100

//全局变量N——表示有几张图片
const int N = 5;
//图片的名称(这里也是路径)
const LPCTSTR pszPngName[] = {_T("0.png"), _T("1.png"),
_T("2.png"), _T("3.png"), _T("4.png")}; 
CSlideBmpView类私有成员private:
CRect m_rClient;//客户区大小
CImage m_img;//用于在内存中绘图

CDC m_bufferDC;//缓冲DC
CBitmap m_bufferBmp;//缓冲Bitmap

int m_index;//标记图片索引
int m_start;//标记图片起始位置
bool m_isStart;//标记是否是开始
bool m_isLeft;//标记图片移动方向
bool m_isLoad;//标记是否加载图片 

(5). 由于我是用键盘控制图片出现的方向——方向键左键表示从左边往右出现,右键表示从右边往左边出现——添加键盘消息处理函数(WM_KEYDOWN)void CSlideBmpView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
//如果图片起始位置是起点,表示图片已经移动结束.这时才允许继续移动图片
if(!m_start)
{
//如果按下左键
if(nChar == VK_LEFT)
{
m_isLeft = true;
m_start = m_rClient.Width();
}

//如果按下右键
else if(nChar == VK_RIGHT)
{
m_isLeft = false;
m_start = -m_rClient.Width();
}

//设置定时器, 触发动画的开始
if(nChar == VK_LEFT || nChar == VK_RIGHT)
{
m_index = (m_index + 1) % N;

m_isLoad = true;
SetTimer(ID_TIMER_PAINT, 10, NULL);
InvalidateRect(NULL, false);
}
}

CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
 
(6). 响应计时器消息——WM_TIMERvoid CSlideBmpView::OnTimer(UINT_PTR nIDEvent)
{
if(m_isLeft)
{
m_start -= 8;
}
else
{
m_start += 8;
}

//如果图片刚好布满客户区, 就停止移动
if(!m_start)
{
KillTimer(ID_TIMER_PAINT);
}

//在移动图片时不需要加载图片
m_isLoad = false;

/*
重绘

因为, 每次绘制都会覆盖上一次的, 因此不需要重绘背景
否则它会使用默认的白色画刷重绘背景, 闪屏会很厉害
*/
InvalidateRect(NULL, false);

CView::OnTimer(nIDEvent);
}
 
(7). 在CSlideView::OnDraw函数中绘图——响应Win32的WM_PAINTvoid CSlideBmpView::OnDraw(CDC* pDC)
{
CSlideBmpDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;

//如果是窗口建立之初
if(m_isStart)
{
m_isStart = false;

GetClientRect(&m_rClient);

//创建缓冲DC
m_bufferDC.CreateCompatibleDC(NULL);
//创建缓冲Bitmap
m_bufferBmp.CreateCompatibleBitmap(pDC,
800, 600);
//将缓冲Bitmap选入缓冲DC中
m_bufferDC.SelectObject(m_bufferBmp);
}

//如果需要加载图片
if(m_isLoad)
{
//加载图片
m_img.Load(pszPngName[m_index]);
//在内存中绘图(缓冲DC)
m_img.Draw(m_bufferDC, 0, 0);
//取消图片与m_img对象的关联, 以使下一次顺利关联下一个图片
m_img.Detach();
}

//贴图
pDC->SetStretchBltMode(COLORONCOLOR);
pDC->StretchBlt(m_start, 0, m_rClient.Width(), m_rClient.Height(),
&m_bufferDC, 0, 0, 800, 600, SRCCOPY);
}
 
(8). 记得回收内存资源——在析构函数中处理CSlideBmpView::~CSlideBmpView()
{
//在析构中回收内存资源
m_bufferBmp.DeleteObject();
m_bufferDC.DeleteDC();
m_img.~CImage();

 
四、免费资源下载点击下载项目工程及源代码  欢迎对MFC感兴趣的朋友和我交流,结识志同道合的朋友是我的荣幸(^_^)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐