|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 新手学习中 于 2013-9-28 13:48 编辑
动画效果:动画就是多个图片连续的更新窗口。我们这里,就是让它在规定时间内更新窗口,去发送wm_paint消息,最后执行具体更新内容的函数。
1、人物行走的图片共有16幅,我们需要把这16幅图片都载入内存中
这里,当然就用for循环来完成16幅图片的载入。我们需要把图片文件按一定数学规律命名,因为这样才能用一定规律调用for循环。
这里我们需要16个指针来指向不同的图片。就需要创建一个数组指针。
2、使用定时器,让函数按照一定时间发出WM_PAINT重绘消息。
这一步,只需要使用SetTimer函数即可
3、在绘制的函数中,让其显示的图片在最后按一定规则变化
变化后,下一次重绘就会显示不同的图片
在函数中,我们让它每一次更新,都按照一定的规律变化更新的内容。这里自然就要用到for循环了。
我们用for循环,让每一次更新,都替换掉图片。图片读取自然需要图片名,所以这里的图片名我们要用一定规律命名。
比如1.1 1.2 1.3..... 2.1 2.2 ....一共16个图片,前面一位表示四种方向,后面一位表示前进的四种姿态,以递增形式。
这16种状态不是完全独立的,它是有方向的对应联系,所以需要一个二维数组指针来表示这16种状态。
CBitmap*bitmap[4][4]; //创建一个二维数组,有每维有4个元素,是0~3,用这个来代替之前的bitmap指针,把之前的这个指针变量给去掉。在类中添加这个数组指针
然后就是初始化数组指针,让每个元素都指向对应的CBitmap类对象,对象中放着对应的图片。这里就需要用for循环来实现。
GameWnd::GameWnd()
{
Create(NULL,"创建窗口");
mdc=new CDC;
CClientDC dc(this);
mdc->CreateCompatibleDC(&dc);
//我们要在前面先增加成员变量int i,j ;
char ch[8]; //这个数组用来储存文件名,文件名7字节最后还有个/0
for(i =0,i<4,i++)
{
for(j=0,j<4,j++)
{
sprintf(ch,"%d.%d.bmp",i+1,j+1); //这一步是给字符串变量赋值,字符串变量赋值一般是:ch = "m.n.bmp" 但这里m,n就是纯字符而不是变量了,我们是需要把变量转换成字符,再赋值给字符串变量,这里就需要sprintf函数
后面是变量,前面的%d是把后面的变量以十进制转换,当然最后因为引号,里面的内容都是字符串。
bitmap[j]=new CBitmap;
bitmap[j]->m_hObject = LoadImage(NULL,ch,IMAGE_BITMAP,93,100,LR_LOADFROMFILE);//这一步,我们用ch表示图片名,把图片读入了内存中,注意,第二个参数是ch而不是"ch",如果加了引号那就变成读取ch文件名的图片了。到这一步,16幅载入内存完成
}
}
}
SetTimer函数设置发出重绘消息
我们需要在类中增加 wm_create 跟wm_timer 。对应生成oncreate函数跟ontimer函数。
在oncreate函数中,添加SetTimer(1,100,NULL); 1表示定时器的序号,我们这里只有一个定时器所以写1.
100是毫秒,表示调用的间隔,NULL表示调用默认的回调函数。这里的回调函数就是自动生成的ontimer函数。
Settimer是设置定时器的,Ontimer是响应Settimer消息的。当Settimer设置的时间到了,就会自动调动Ontimer()函数。
在Ontimer()函数中,我们设置具体的图片显示代码,跟最后图片的变化规律。
注意:我们在Ontimer()函数中,使用的是CClientDC而不是CPaintDC ,如果是CPaintDC结果显示就是一副静止的画面,这原因比较复杂,定时器和界面刷新机制不同,不能相互替代。
在一个定时器周期里面,可能需要一次或者多次刷新界面,而触发时间也不一致,这种情况下,CPaintDC的机制不能满足需要。另外,其实还有其它问题,但记住,OnPaint之外,最好避免使用CPaintDC.
在Ontimer()函数中,我们让SelectObject载入兼容dc的图片,其图片名后面加上一个变量。
前面还需要一个总体的判断。因为我们需要让动画走完往前的四个图片,再去走向左的四个图片。。。。。直到16图走完,再重新开始。最后我们使用dc.BitBlt 载入 图片。
OnTimer函数具体代码如下:
void GameWnd::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
if (j<4)
{
mdc->SelectObject(bitmap[j]);
dc.BitBlt(0,0,93,100,mdc,0,0,SRCCOPY);
j++;
}
else
{
j = 0;
i++;
if(i<4)
{
mdc->SelectObject(bitmap[j]);
dc.BitBlt(0,0,93,100,mdc,0,0,SRCCOPY);
j++;
}
else
{
i = 0;
mdc->SelectObject(bitmap[j]);
dc.BitBlt(0,0,93,100,mdc,0,0,SRCCOPY);
j++;
}
}
CFrameWnd::OnTimer(nIDEvent);
}
运行后,窗口中就出现了人物不断的朝着四面原地行走。
用键盘控制人物行走
我们需要的是用键盘控制人物行走,而非自动行走,所以我们把SetTimer函数取消掉,这样ontimer函数的内容也就失效了。
接受键盘信息,需要用到WM_KEYDOWN 添加后,会自动生成OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)函数。
我们按下键,其信息会存入VK_DOWN 上键 VK_UP 左键 VK_LEFT 右键VK_RIGHT
第一个参数nChar的数据类型,就与VK类型相同,这里我们可用于判断。
代码如下:
void GameWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
if (nChar == VK_DOWN)
{
dc.BitBlt(m,n,93,100,mdc,0,0,WHITENESS);//重绘图片时先用白色填充上一张图片,为了消除行走时的残影
n = n+20;
if (i ==0)
{
j++;
if(j<4)
{
mdc->SelectObject(bitmap[j]);
dc.BitBlt(m,n,93,100,mdc,0,0,SRCCOPY);
}
else
{
j = 0;
mdc->SelectObject(bitmap[j]);
dc.BitBlt(m,n,93,100,mdc,0,0,SRCCOPY);
}
}
else
{
i = 0;
j = 0;
mdc->SelectObject(bitmap[j]);
dc.BitBlt(m,n,93,100,mdc,0,0,SRCCOPY);
}
}
CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
运行后,如图:
我们可以通过下键控制人物移动。但这个窗口一开始是空白的,我们按下后才有人,需要一开始就有人的话,要在onpaint函数里放绘制函数。因为流程中,就是先在onpaint这里绘制第一次的。
我们设置其他方向,只需要复制一下,再修改个别的量,这里就不多说了,设置好四个方向后,运行如下:
这是为了在图片中看出行走效果,把//dc.BitBlt(m,n,93,100,mdc,0,0,WHITENESS);注释了起来。实际上这行是不能注释的,有了这个填充空白后,人物走起来就不会有残影了。
绘制整体布局————迷宫图
迷宫是由一块块蓝色小方块组成的。(准备好小方块图片)
迷宫横着有八块,竖着也有八块,第一步就是要让其绘制迷宫。
int maze[8][8]=
{
1,1,1,1,1,1,2,1, //第1行,值为2的元素代表入口
3,0,0,1,0,0,0,1, //第2行,值为3的元素代表出口
1,1,0,0,0,1,1,1, //第3行
1,0,0,1,0,0,0,1, //第4行
1,1,1,1,0,1,1,1, //第5行
1,0,0,0,0,0,0,1, //第6行
1,0,1,0,1,0,0,1, //第7行
1,1,1,1,1,1,1,1 //第8行
};
我们把图划分成8行8列(以方块为单位),属于蓝色墙壁的,写上1 ,入口2,出口3,空白0
然后我就用for循环,对每个数组元素进行判断,如果是1,那就填上蓝色方块。
要填上方块,就必须知道其坐标。那么这个坐标就是数组序号* 方块长宽
如 maze[4][1]; 他所表示的方块,其坐标就是 1*93,4*100 注意这里4是行,表示是纵向 。1是列,表示的是横向。
我们在ontimer函数中添加如下代码:
CClientDC dc(this);
for(a=0;a<8;a++)
{
for (b=0;b<8;b++)
{
if (maze[a][b]==1)
{
mdc->SelectObject(wall);
dc.BitBlt(b*93,a*100,93,100,mdc,0,0,SRCCOPY);
}
}
}
这样,运行后,就完成了迷宫的绘制:
这里有两个缺陷:
一、此程序是每隔0.1秒就重绘迷宫,其实我们只需要绘制一次就够了。
二、人物没有出现在入口,而且我们按移动键盘时,人物在另一端出现并移动。
解决第一个问题,只需要把以上代码前加入一个判断,把判断值初始化设为true,在最后又把它赋值为false就行,这样重绘就只执行一次。
第二个问题,人物出现在入口,我们只需要再加入一句BitBlt就行。然后再键盘控制代码中,用原始坐标+每次按键偏移量即可。
if (begin)
{
CClientDC dc(this);
for (int a=0;a<8;a++)
{
for (int b=0;b<8;b++)
{
if (maze[a][b]==1)
{
mdc->SelectObject(wall);
dc.BitBlt(b*93,a*100,93,100,mdc,0,0,SRCCOPY);
}
if(maze[a]==2)
{
mdc->SelectObject(bitmap[0][0]);
dc.BitBlt(b*93,a*100,93,100,mdc,0,0,SRCCOPY);
x =b*93; //这里是为了把人物初始坐标给记录下来,然后在键盘控制代码里添加即可
y =a*100;
}
}
}
begin=false;
}
在人物键盘控制代码中,凡是出现dc.BitBlt 的,全部把其坐标m,n改为x+m,y+n,这样就完成了!运行后如图:
但是这个程序还有问题,那就是碰到墙壁会穿墙而过,墙壁没有起到阻挡的效果,如图:
[/b][/b]
|
|