《MFC Windows 程序设计》实验报告
2011 至 20## 学年第二学期
实验完成情况:完成 基本完成 未完成
第一章 游戏基础
一 动画
游戏是动画的延伸,只要知道了动画的原理,在动画变化时,使它根据键盘或鼠标的输入操作而变化,就是游戏了。
所以在介绍游戏编程之前,先讲讲动画。
动画一般分三种形式:形变、位变、色变。如下:
1. 1. 形变
即几种形状的图形或位图依次转变而成。(图1-1) 图1-1
先看一个简单的实例:
a. a. 新建工程1_1,选择单文档,完成。 b. b. 在view类加变量int ituxing,并在构造函数里赋值为ituxing=0; c. c. 在OnDraw(CDC* pDC)函数上添上以下语句: void CMy1_1View::OnDraw(CDC* pDC)
{
CMy1_1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here //清除当前图形
CBrush mybrush1;
mybrush1.CreateSolidBrush(RGB(255,255,255)); CRect myrect1(0,0,1024,768);
pDC->FillRect(myrect1,&mybrush1);
//判断当前图形ituxing
if(ituxing==1)
//ituxing=1,画矩形
pDC->Rectangle(20,20,89,89);
else if(ituxing==2)
//ituxing=2,画圆
pDC->Ellipse(20,20,89,89);
else
//否则,画三角形
{
pDC->MoveTo(20,20);
pDC->LineTo(89,45);
pDC->LineTo(20,89);
pDC->LineTo(20,20);
}
}
d. d. 添加OnTimer(UINT nIDEvent)和OnCreate(LPCREATESTRUCT
lpCreateStruct),并加上语句如下:
void CMy1_1View::OnTimer(UINT nIDEvent)
{
} // TODO: Add your message handler code here and/or call default //获取指针pdc CDC *pDC=GetDC(); //调用OnDraw(pDC)重画 OnDraw(pDC); //使ituxing循环 ituxing=(ituxing+1)%3; CView::OnTimer(nIDEvent);
int CMy1_1View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
//设置更新时间
SetTimer(1, 750, NULL);
return 0;
}
e. e. 完成。
2. 2. 位变
即同一个图形或位图依次在不同的位置上出现而形成动画。(图1-2)
图 1-2
见实例1_2:
a. a. 复制实例1_1文件夹,改名为1_2。
把void CMy1_1View::OnTimer(UINT nIDEvent)中的ituxing=(ituxing+1)%3;改为ituxing=(ituxing+1)%10;
b. b. 把OnDraw(CDC* pDC)函数改为:
void CMy1_1View::OnDraw(CDC* pDC)
{
CMy1_1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//清除当前图形
CBrush mybrush1;
mybrush1.CreateSolidBrush(RGB(255,255,255));
CRect myrect1(0,0,1024,768);
pDC->FillRect(myrect1,&mybrush1);
//用当前图形位置ituxing
//画圆
pDC->Ellipse(30*ituxing,30*ituxing,30*ituxing+50,30*ituxing+50); }
c. c. 执行,OK!
3. 3. 色变
即利用不同颜色的转变而形成有动感的图画。(图1-3)
图1-3
实例1_3:
a. a. 新建单文档工程1_3。
b. b. 添加参数int icolor并赋值为0。
c. c. 添加函数OnTimer(UINT nIDEvent)和OnCreate(LPCREATESTRUCT
lpCreateStruct),并添加语句如下:
void CMy1_3View::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default icolor+=1;
//此函数使客户区失效,以致重画
Invalidate();
CView::OnTimer(nIDEvent);
}
int CMy1_3View::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here SetTimer(1,750,NULL);
return 0;
}
d. d. 最后在OnDraw(CDC* pDC)加上画圆语句:
void CMy1_3View::OnDraw(CDC* pDC)
{
CMy1_3Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//获取icolor值
int i=icolor;
//在不同位置画四个不同颜色的圆
CBrush brush1(RGB(20+(64*i)%255,140+(64*i)%255,210*(64+i)%255));
CBrush*pOldBrush1=pDC->SelectObject(&brush1);
pDC->Ellipse(300,200,350,250);
pDC->SelectObject(pOldBrush1);
CBrush brush2(RGB(84+(64*i)%255,204+(64*i)%255,24+(64*i)%255));
CBrush*pOldBrush2=pDC->SelectObject(&brush2);
pDC->Ellipse(350,200,400,250);
pDC->SelectObject(pOldBrush2);
CBrush brush3(RGB(148+(64*i)%255,14+(64*i)%255,88+(64*i)%255));
CBrush*pOldBrush3=pDC->SelectObject(&brush3);
pDC->Ellipse(300,250,350,300);
pDC->SelectObject(pOldBrush3);
CBrush brush4(RGB(212+(64*i)%255,78+(64*i)%255,152+(64*i)%255));
CBrush*pOldBrush4=pDC->SelectObject(&brush4);
pDC->Ellipse(350,250,400,300);
pDC->SelectObject(pOldBrush4);
}
e. e. 完成。
以上是三种最基本的动画。当然,具体情况不会这么简单,而往往的其中二或三种的复杂的结合。
而作为游戏,它的关键在:在动画的基础上加一些主观的操作。如先画一个球,然后用方向键或鼠标移动。如实例1_4:
a. a. 新建单文档工程1_4。
b. b. 添加半径和圆心
int ir;//半径
CPoint center;//圆心
在CMy1_4View()中赋值如下:
CMy1_4View::CMy1_4View()
{
// TODO: add construction code here
center.x=400;
center.y=200;
ir=50;
}
c. c. 在OnDraw(CDC* pDC)函数中画圆
void CMy1_4View::OnDraw(CDC* pDC)
{
CMy1_4Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//画圆
pDC->Ellipse(center.x-ir,center.y-ir,center.x+ir,center.y+ir);
}
d. d. 添加OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags),使它按照键盘方
向键的操作而移动圆的位置。如下:
void CMy1_4View::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
//利用方向键左右上下移动20
switch(nChar)
{
case VK_LEFT:
center.x-=20;
break;
case VK_RIGHT:
center.x+=20;
break;
case VK_UP:
center.y-=20;
break;
case VK_DOWN:
center.y+=20;
break;
}
//重画
Invalidate();
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
e. e. 执行,看看效果,你就可以操纵了。
f. f. 那么,利用鼠标又是怎样操作呢?添加OnLButtonDown(UINT nFlags, CPoint
point)如下:
void CMy1_4View::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
//把圆移动鼠标指定位置
//圆心赋值为point
center=point;
//重画
Invalidate();
CView::OnLButtonDown(nFlags, point);
}
g. g. 再执行,你现在键盘鼠标都可以操作了。
真正的游戏,也就是以上简单的图形或位图的复杂化和简单操作的复杂化而已。
二 部分图更新
既然游戏是动画,就离不开“动”,而所谓“动”,就是利用画面的刷新,用新的要求的图画或位置去代替原先的图画或位置。
图画储存在哪里?内存。
画图需要什么?系统资源。
而它们有什么关系?成正比。
为什么说这些呢?因为这关系到游戏编程一个极大的问题:速度!上面那些简单的例子,我们是怎样实现的呢?不就是利用一个控制时间的函数定期地对画面进行重画吗?它们的速度快吗?快。是的,但如果你编一个大屏幕的画面,并在上面画上几十种图形,添上几十种颜色,然后再利用上面的方法试试,速度还快吗?
慢了。为什么?因为这个图画太占用内存,需要太多的系统资源,我们的机器满足不了要求,变慢了。
怎样解决呢?一切的计算机图形都是利用部分图形重画的原理!一种是:只保存要改变的那部分图形,然后把要改变的新图接在已保存过画面的范围内,形成新的图。接着把刚才保存的图画还原,变成原先的图画。再保存另一个地方,贴上新图,变成新图画,再还原。反复进行(如下图1-4)。一种是:不重画,直接在要变化的位置变化。
图1-4
实例1_5:一个正方形在复杂的画面上移动。
要求:先用全部重画做一次,再用部分重画做一次,对比一下。
a. a. 新建单文档工程,添加两个变量:
int ixunhuan;
CBitmap m_Bitmap;
b. b. 添加位图 IDB_BITMAP1,即狮子图象。
图1-5
c. c. 在构造函数里面添加两个语句:
CMy1_5View::CMy1_5View()
{
// TODO: add construction code here
//获得位图
m_Bitmap.LoadBitmap(IDB_BITMAP1);
ixunhuan=0;
}
d. d. 添加虚函数OnInitialUpdate() ,初始化位图变量
e. e. 添加OnCreate(LPCREATESTRUCT lpCreateStruct)和OnTimer(UINT
nIDEvent)函数如下:
int CMy1_5View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
SetTimer(1,1200,NULL);
return 0;
}
void CMy1_5View::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
// TODO: Add your message handler code here and/or call default
//即大于400后变小
ixunhuan=(ixunhuan+30)%400;
Invalidate();
CView::OnTimer(nIDEvent);
}
f. f. 在OnDraw(CDC* pDC)函数中添加画多图形多颜色的语句,并加上狮子位图
如下:
void CMy1_5View::OnDraw(CDC* pDC)
{
CMy1_5Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CDC Dc;
if(Dc.CreateCompatibleDC(pDC)==FALSE)
AfxMessageBox("Can't create DC");
//画复杂图形,有多种颜色
for(int j=0;j<25;j++)
for(int i=0;i<44;i++)
{
CBrush mybrush1;
mybrush1.CreateSolidBrush(RGB((i*20)%255,(j*20)%255,(i+j+20)%255)); //正方形
CRect myrect1(20*i,20*j,20*i+20,20*j+20);
pDC->FillRect(myrect1,&mybrush1);
//圆
pDC->Ellipse(20*i,20*j,20*i+20,20*j+20);
//小正方形
CRect myrect2(20*i+4,20*j+4,20*i+16,20*j+16);
pDC->FillRect(myrect2,&mybrush1);
//小圆
pDC->Ellipse(20*i+4,20*j+4,20*i+16,20*j+16);
//更小正方形
CRect myrect3(20*i+7,20*j+7,20*i+13,20*j+13);
pDC->FillRect(myrect3,&mybrush1);
//更小圆
pDC->Ellipse(20*i+7,20*j+7,20*i+13,20*j+13);
//最小正方形
CRect myrect4(20*i+9,20*j+9,20*i+11,20*j+11);
pDC->FillRect(myrect4,&mybrush1);
}
//在不同位置显示位图
Dc.SelectObject(m_Bitmap);
pDC->StretchBlt(70+ixunhuan,70,160,160,&Dc,0,0,71,71,SRCCOPY);
}
g. g. 执行,你就可以看到它重画时有多慢了。
h. h. 现在,再用部分重画做:
把OnTimer(UINT nIDEvent)函数改为如下:
void CMy1_5View::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
// TODO: Add your message handler code here and/or call default
ixunhuan=(ixunhuan+30)%400;
//如果图象回到开头,全部重画
if(ixunhuan<40)
Invalidate();
//设置部分更新区域
CRect r;
r.left=70+ixunhuan-40;
r.top=70;
r.bottom=r.top+160;
r.right=r.left+200;
//部分更新函数
InvalidateRect(r,TRUE);
CView::OnTimer(nIDEvent);
}
i. i. 执行,现在感觉怎样,是不是变快了。看看图象在头尾交换时的对比就知道
了。
当然,上面的程序并不是很好。例如,如此复杂的背景大可用一张图代替,而那狮子也不行,它覆盖了背景,怎么办呢?下面就谈消去狮子位图的白色(或其它颜色)背景的方法。
三 设置透明背景
游戏,无非就是由核心操作和界面组成。界面一般都有前景背景,背景一般是显示一张大的位图,前景一般是被人操作(或计算机模拟人操作)的那部分。背景位图一般都是覆盖了整个界面,它周围整洁,只要你把它画好了,加上去就行;而前景位图不同,它一般是不规矩的,如飞机、动物、人物等。而像上例,狮子位图的周围是原位图的颜色,而不是背景的颜色,不好看。
那么,怎样把前景位图的背景颜色去掉,而使背景位图能看到呢?就是本节的内容。实现的原理是:指定一种颜色,然后对这种颜色进行处理,使它的色素不画出来。如上面的
狮子,指定白色RGB(255,255,255)为透明色,就行了。
下面就介绍一个函数TransparentBitmap():
//本函数把一种指定的颜色变成透明色,并可改变大小
// hdc 显示句柄
// hBitmap要显示的位图
// xStart,xStart显示的位置
// xadd,yadd显示的位图的大小变化:放大缩小
// 如:xadd=3表示位图宽度加3
// cTransparentColor变成透明的那种颜色
void CMy1_6View::TransparentBitmap(HDC hdc, HBITMAP hBitmap,short xStart,
short yStart, short xadd,short yadd, COLORREF cTransparentColor)
{
BITMAP m_bm;
COLORREF cColor;
// 创建临时DC
HDC hMem, hBack, hObject, hTemp, hSave;
hBack = CreateCompatibleDC(hdc);
hObject = CreateCompatibleDC(hdc);
hMem = CreateCompatibleDC(hdc);
hSave = CreateCompatibleDC(hdc);
hTemp = CreateCompatibleDC(hdc);
// 选入位图
SelectObject(hTemp, hBitmap);
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&m_bm);
//显示位图宽高
POINT ptSize;
// 取得位图的宽度
ptSize.x = m_bm.bmWidth;
// 取得位图的该度
ptSize.y = m_bm.bmHeight;
// 转换为逻辑点值
DPtoLP(hTemp, &ptSize, 1);
// 创建临时位图
HBITMAP bmBack, bmObject, bmMem, bmSave;
// 单色位图
bmBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
bmObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
// 与设备兼容位图
bmMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
// 将创建的临时位图选入临时DC中
HBITMAP OldbmBack, OldbmObject, OldbmMem, OldbmSave;
OldbmBack = (HBITMAP)SelectObject(hBack, bmBack);
OldbmObject = (HBITMAP)SelectObject(hObject, bmObject);
OldbmMem = (HBITMAP)SelectObject(hMem, bmMem);
OldbmSave = (HBITMAP)SelectObject(hSave, bmSave);
// 设置映射模式
SetMapMode(hTemp, GetMapMode(hdc));
// 先保留原始位图
BitBlt(hSave, 0, 0, ptSize.x, ptSize.y, hTemp, 0, 0, SRCCOPY);
// 将背景颜色设置为需透明的颜色
cColor = SetBkColor(hTemp, cTransparentColor);
// 创建目标屏蔽码
BitBlt(hObject, 0, 0, ptSize.x, ptSize.y, hTemp, 0, 0, SRCCOPY);
// 恢复源DC的原始背景色
SetBkColor(hTemp, cColor);
// 创建反转的目标屏蔽码
BitBlt(hBack, 0, 0, ptSize.x, ptSize.y, hObject, 0, 0, NOTSRCCOPY);
// 拷贝主DC的背景到目标DC
BitBlt(hMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart, SRCCOPY);
// 屏蔽位图的显示区
BitBlt(hMem, 0, 0, ptSize.x, ptSize.y, hObject, 0, 0, SRCAND);
// 屏蔽位图中的透明色
BitBlt(hTemp, 0, 0, ptSize.x, ptSize.y, hBack, 0, 0, SRCAND);
// 将位图与目标DC的背景左异或操作
BitBlt(hMem, 0, 0, ptSize.x, ptSize.y, hTemp, 0, 0, SRCPAINT);
// 拷贝目标到屏幕上
StretchBlt(hdc, xStart, yStart, ptSize.x+xadd, ptSize.y+yadd, hMem, 0, 0, ptSize.x, ptSize.y,SRCCOPY);
// 恢复原始位图
BitBlt(hTemp, 0, 0, ptSize.x, ptSize.y, hSave, 0, 0, SRCCOPY);
// 删除临时内存位图
DeleteObject(SelectObject(hBack, OldbmBack));
DeleteObject(SelectObject(hObject, OldbmObject));
DeleteObject(SelectObject(hMem, OldbmMem));
DeleteObject(SelectObject(hSave, OldbmSave));
// 删除临时内存DC
DeleteDC(hMem);
DeleteDC(hBack);
DeleteDC(hObject);
DeleteDC(hSave);
DeleteDC(hTemp);
}
注释已经写得很清楚了,用时只要按照要求在函数括号里加上各个值就行了。下面用实例1_6演示一下:
a. a. 新建单文档工程1_6,加上变量如下:(注释已在上面)
short xStart;
short yStart;
short xadd;
short yadd;
CBitmap m_Bitmap;
COLORREF cTransparentColor;
b. b. 在函数CMy1_6View()加上以下语句:
CMy1_6View::CMy1_6View()
{
// TODO: add construction code here
xStart=30;
yStart=30;
xadd=0;
yadd=0;
m_Bitmap.LoadBitmap(IDB_BITMAP1);
cTransparentColor=RGB(255,255,255);
}
c. c. 添加上面的狮子位图。
d. d. 加上OnCreate(LPCREATESTRUCT lpCreateStruct)和OnTimer(UINT nIDEvent)
函数如下:
int CMy1_6View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
SetTimer(1,150,NULL);
return 0;
}
void CMy1_6View::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
//获取指针pdc
CDC *pDC=GetDC();
//调用OnDraw(pDC)重画
OnDraw(pDC);
CClientDC dc(this);
//向右向下移动
xStart+=5;
yStart+=5;
//位图宽高加2
xadd+=2;
yadd+=2;
//显示
TransparentBitmap(dc.GetSafeHdc(), m_Bitmap, xStart, yStart, xadd,yadd, cTransparentColor);
CView::OnTimer(nIDEvent);
}
e. e. 上面的“透明位图”函数还没有定义,必须把开头的函数添加进来。把函数整
个拷贝到1_6View.cpp,然后在1_6View.h中加上:
void TransparentBitmap(HDC hdc, HBITMAP hBitmap, short xStart,
short yStart, short xadd,short yadd, COLORREF cTransparentColor);
f. f. 最后,在函数OnDraw(CDC* pDC)加上背景:
void CMy1_6View::OnDraw(CDC* pDC)
{
CMy1_6Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//画红色背景
CBrush mybrush1;
mybrush1.CreateSolidBrush(RGB(255,0,0));
CRect myrect1(0,0,1200,800);
pDC->FillRect(myrect1,&mybrush1);
}
g. g. 运行,怎么样?图象还会变大呢!
四 显示对称图像
上面既然谈到了位图的透明显示,那么,我们经常用到的另外一种显示方式:对称,也就该接着说明一下。毕竟,无论是人,或是景,我们都讲究对称,特别是中国人;无论你向左,还是向右,它的图像一般也是讲究对称的。
既然对称在我们的社会里,在我们的文化中是多么地受到人们的追求,人们是非常强烈地以对称为美,我们就必须学会怎样用程序来实现它。这也就是我把它放在前面讲的原因。
下面,我们就来说明对称位图的实现。
我们的程序语言里面有许多关于位图的操作,包括位图的复制,放大缩小,位图的反转甚至布尔运算。但是,我们找不到对称的操作。开始,我也不知道该怎么办,难道一边看着位图,一边对称地画另一张位图吗?
事实上,我差一点就这么做了。但是,我突然发现,我可以一行一行地利用复制的方法,在原来的位图上面复制一行或一列,然后粘贴到另一张位图上面对称的地方去。我是这么做了,并且由于我的这个实践,我发现,我根本就可以利用程序的for循环来帮助我完成这一件事。甚至,让它能够按照我们的意愿放大缩小,按照我们的意愿在我们希望的位置显示。
实例如下:
添加单文档工程1_7,添加一个位图,改变如下函数:
由于下面说明清楚,不再细说。
void CMy1_7View::OnDraw(CDC* pDC)
{
CMy1_7Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
int x,y,width,height,i;
//设置反面显示位图的起点和大小
//可以在别的地方设置,赋值
x=350;
y=30;
width=240;
height=200;
BITMAP m_bm;
CDC Dc;
if(Dc.CreateCompatibleDC(pDC)==FALSE)
AfxMessageBox("Can't create DC");
// 选入位图
Dc.SelectObject(bitmap);
GetObject(bitmap, sizeof(BITMAP), (LPSTR)&m_bm);
//显示位图宽高
POINT ptSize;
// 取得位图的宽度
ptSize.x = m_bm.bmWidth;
// 取得位图的该度
ptSize.y = m_bm.bmHeight;
//显示正面位图
pDC->StretchBlt(10,30,240,200,&Dc,0,0,ptSize.x,ptSize.y,SRCCOPY);
//显示反面位图
//以下参数的说明:
//x+(i*width/ptSize.x)表示每个循环的起点位置,
//其中width/ptSize.x表示每次移动的大小
//y为显示的top
//height为显示位图的高度
//ptSize.x-i为每次SRCCOPY的起点x
//在不同位置显示位图
for( i=0;i<ptSize.x;i++)
pDC->StretchBlt(x+(i*width/ptSize.x),y,width/ptSize.x,height,&Dc,ptSize.x-i,0,1,ptSize.y,SRCCOPY);
}
运行,效果就在第一页。
五 游戏的内核
上面所说的,并不是游戏,它只能算是游戏中的一些元素。一个游戏,不可能只是表面图形这么简单,我们还没有谈到它的实质的东西——内核。
我们后面将讲到的挖雷游戏、俄罗斯方块等,都是一些简单的游戏,可是,第一次接触时,你能说出它的原理吗?它是怎么实现的吗?
游戏的核心并不是我们所看到的图形,反而是我们所看不到的,游戏的算法。那么,游戏的图形和核心之间是怎么联系的呢?例如我们怎么利用键盘的方向键来控制俄罗斯方块的移动和转变呢?我们又如何利用鼠标来对挖雷游戏进行操作呢?
游戏的图形和核心的联系是必然的。但我之所以要说,是因为我想告诉你:正是这个联系障碍了人们编程的思路!其实,它们的联系就像两个城市之间的那条公路一样连接着,它们事实上是两个整体,是分离的。
为什么?
什么是游戏?游戏本来就是一种变化过程,它是无形的,是不依奈图形而存在的。我们可以举一个例子,先编好一个游戏(如俄罗斯方块),运行它,你可以高兴地玩了。然后你再修改一下,把它的左(或右)半边用一张鲜花美女图象盖上去,然后再一次运行游戏,虽然你只能到一半游戏界面,但你依然可以玩游戏。或许说游戏依然正常运行。那么,我们把整个界面都盖上,不难想象,游戏还是会正常运行的。由此可见,游戏本来就是存在的,它是无形的,是不依奈于图形界面的。即使你编一个没有界面的俄罗斯方块游戏,它也能运行,它是一个我们只知道开始和结束的游戏,是不为人们所喜欢的。
游戏可以说是不依奈于图形而存在的,如果你不想让别人玩的话。而图形的存在,就是为了别人可以玩。它是作用就是让你看清楚游戏的进程,让你更好地把握你所玩的游戏罢了。用上面的城市来说,核心城市并不依奈于图形城市,不与图形城市交流,核心城市依然能发展下去,如没有界面的俄罗斯方块游戏;而图形城市也不依奈于核心城市,如上面的鲜花美女图象。但是,我们编程,并不希望它们各自独立,我们要利用它们的联系来展开我们的游戏。于是,我们就朝着文明发展的方向为它们建了高速公路。
我们究竟是怎样联系它们的呢?我们怎样把它们同步实现呢?
事实上,我们所看到的同步,并不是真的!只是一种错觉!核心城市每时每刻都在发展,而图形城市并不是每时每刻都知道核心城市的发展情况的,它只是每隔一段时间才去了解一下情况,或许核心城市有情况传来时,图形城市才知道的,这时图形界面才改变给人看。
游戏编程,就是你把实质的东西全部用算法在核心城市表现出来,然后再依照你的要求把那些要让人看的东西让图形城市知道,让图形城市帮你公布到界面上。
Windows编程实验报告1GDI图形程序设计姓名专业学号框架窗口程序和20xx3241Windows编程实验报告1Windows…
院系计算机科学学院专业网络工程年级20xx级课程名称Windows编程学号10066070姓名王彦廷指导教师熊志勇20xx年1月6…
Windows程序设计实验报告实验室S306308学院计算机科学与技术专业计算机科学与技术目录实验一熟悉visualc的编程环境3…
Windows程序设计实验报告河南理工大学测绘学院Windows程序设计实验报告班级地信101姓名薛山学号311005030124…
Windows程序设计实践总结报告班级姓名学号任课教师一功能介绍1用户验证用户通过系统登陆窗体输入相应的账户和密码通过验证的用户可…
Windows体系及编程实验指导书实验一类Windows进程任务管理器实验实验名称进程管理实验实验类型设计性实验学时4适用对象软件…
附件3科技学院课程设计综合实验报告2020年度第学期名称Windows体系编程题目院系信息工程系班级软件09k2学号学生姓名闫雪峰…
Windows编程实验报告1GDI图形程序设计姓名专业学号框架窗口程序和20xx3241Windows编程实验报告1Windows…
Windows程序设计实验报告实验一绘图和绘钟实验二简易扫雷程序班级姓名学号班内序号时间20xx54实验一绘图和绘钟一实验要求利用…