⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 base7.htm

📁 C++Builder教学大全
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>动画技术</title>
<meta name="Microsoft Border" content="none">
</head>

<body>

<h1 style="margin-top: 0; margin-bottom: 0" align="left">&nbsp;&nbsp;&nbsp;      
动画技术</h1>  
<p style="margin-top: 0; margin-bottom: 0"></p>   
<p style="margin-top: 0; margin-bottom: 0"><a href="index.htm">[ 主页 ]</a>&nbsp;&nbsp; 
<a href="base.htm">[上一层]</a></p>   
<hr> 
<p>所谓动画也就使一幅图像“活”起来的过程。使用动画可以清楚的表现出一个事件的过程,或是展现一个活灵活现的画面。如今电脑动画的应用十分广泛,无论是让应用程序更加生动,增添多媒体的感官效果;还应用于游戏的开发,电视动画制作,创作吸引人的广告,电影特技制作,生产过程及科研的模拟等等。<br> 
从某种极端的意义上说,产生动画的最好方法并不是编程,而是……放电影。大概你还记得童年时在课本每页右下角画上做不同连续动作的小人再快速翻阅产生的“原始动画”。我们在常识课上就知道利用人类视觉暂留的原理快速连续显示一系列静止画面可以产生动画。每秒播映24张胶片的电影和每秒显示30帧画面的电视(NTSC制)足以蒙骗我们可怜、不灵敏的眼睛。计算机动画(Computer        
Animation)也不例外,应用程序以一定的规律快速连续绘制并显示一系列有关联的静止图像就产生了电脑动画。<br>      
根据计算机动画绘制和显示的原理,根据动画的交互程度我们可以将计算机动画分为非交互动画和交互动画两大类。而交互动画又可进一步被区分为非即时计算交互动画和即时计算交互动画两种。<br>      
在本章里,我们将简单介绍一些动画制作的基本概念,并结合几个简单的程序来说明如何荣编程的方法来实现动画过程。<br>      
<br>      
动画过程的实现有很多种方法,下面我们简单介绍其中的几种:<br>      
子图形动画&nbsp;<br>      
子图形(sprite)在交互式电子游戏中是用来表示各个角色以及不动的背景。当游戏者移动输入设备如游戏杆、跟踪球或者鼠标时,子图形就在背景上移动。玩电子游戏的游戏者实际上是在操作子图形。Uideo游戏机通常都带有图形硬件,内部支持子图形。而IBM兼容pc机内的显示硬设备并不支持子图形,所以必须依靠软件技术实现。<br>      
擦除和重画技术<br>      
在旧位置擦除图像并在新位置重新绘出,这显然是移动图像的一种方法,在Windows程序中,可以通过调用BitBlt函数实现这个方法,如果反复不断地擦除和重绘,图像看起来就会像是在屏幕上穿越移动。但是,这种方法的主要缺点是在擦除和重绘图像时会发生显示闪烁现象。<br>      
有一个办法可以避免擦除-重绘动画时产生的闪烁现象,那就是采用视频页切换,只要显示硬设备支持一个以上的视频页。使用多个视频页,就可以在显示活动页的同时在隐藏的视频页上绘制整个屏幕以显示更新后的图形。要继续显示动画,只需用一个循环重复这一过程。许多高级图形工作站(例如,        
Silicon Graphics 工作站) 支持通过页的切换来实现动画——用工作站界的行话来说是“缓冲区交换”技术。<br>       
不巧的是,绝大多数PC显示适配器在高分辨率视频方式下并不支持多视频页。更重要的是,Microsoft        
Windows也不支持多视频页。所以必须想其他办法在Windows中创建不闪烁的动画。<br>      
<br>      
擦除和重绘动画伴随着屏幕闪烁,其原因是屏幕绘制操作都是可见的,当图像被擦除,它就从屏幕上消失了,然后这个图像又出现在一个新的位置上。如果使用两个视频页,闪烁现象将不复存在,因为屏幕的更新是在隐藏页上完成的,视频页交换的同时就显现整个已更新的屏幕。按照这个逻辑,只要图像准备好,并且更新的屏幕能迅速重绘,就可以避免闪烁。<br>      
好在Windows支持在离屏位图上绘图,这样离屏位图就可以作为准备显示屏幕的理想的“画布”,简单调用BitBlt函数,更新后的图像就会迅速地传输到显示屏幕上,当然,还得注意众多细节,以能够在离屏位图上正确地绘制图像,不过这个基本思想倒是很适用于在Windows下的图像动画。<br>      
<br>      
调用SetBackground函数,其参数是一个指向新的被用作背景图像的DIB指针。这个调用的结果是文档拥有这个DIB,当文档被破坏或背景DIB被新的替代时,此DIB将被消除。显然,改变背景图像将涉及到一些重画操作,但稍后用户才能碰到这些问题,以下是SetBackground函数的程序代码:<br>      
BOOL CAnimDoc::SetBackground(CDIB* pDIB)<br>       
{kk1}<br>      
// Delete any existing background DIB and set the new one.<br>       
if (m_pBkgndDIB) delete m_pBkgndDIB;<br>       
m_pBkgndDIB = pDIB;<br>       
<br>      
// Note that the document has changed.<br>       
SetModifiedFlag(TRUE);<br>      
<br>      
// Tell the view that it needs to create a new buffer<br>       
// and palette.<br>       
CAnimView* pView = GetAnimView( );<br>       
ASSERT(pView);<br>      
return pView-&gt;NewBackground(m_pBkgndDIB);<br>       
}<br>      
清除现存的背景图像,并用新的背景代替。注意:传送空指针给SetBackground将导致那根本没有背景图像,然后文档也标明已发生改变。<br>      
我们再来看一下CanimView::NEW Background函数上来,首先,添加一个装入新背景图像的菜单选项。用App        
Studio在File菜单中添加一个Load Background选项,然后在CanimDoc类中用ClassWizard为该命令建立一个处理函数。一下是处理程序代码:<br>       
void CAnimDoc::OnFileLoadBkgnd()<br>       
{kk1}<br>      
// Create a DIB to hold the image.<br>       
CDIB* pDIB = new CDIB;<br>       
// Show the file open dialog for a DIB.<br>       
if (!pDIB-&gt;Load()) {kk1}<br>       
delete pDIB;<br>       
return;<br>      
}<br>      
// Make sure this is an 8-bpp DIB<br>       
BITMAPINFO* pBMI = pDIB-&gt;GetBitmapInfoAddress();<br>       
ASSERT(pBMI);<br>      
if (pBMI-&gt;bmiHeader.biBitCount != 8) {kk1}<br>       
AfxMessageBox(&quot;Only 8-bpp DIBs are supported&quot;);<br>       
delete pDIB;<br>       
return;<br>      
}<br>      
// Replace any existing background DIB with the new one.<br>       
if (!SetBackground(pDIB)) {kk1}<br>       
delete pDIB;<br>       
}<br>      
}<br>      
OnFileLoadBkgnd使用CDIB类中的新Load函数显示一个允许用户选择并装入背景图像DIB的对话框。如果成功,则SetBackground函数把新装入的DIB用作当前的背景图像。对于CDIB::Load函数,它带有一个文件名参数活不带参数,读者可以参照例程。<br>      
现在已有装入新背景图像DIB的菜单选项及将该图像附给文档的程序代码。下面我们只需作两件事:<br>      
传建一个新的屏幕缓冲区<br>      
创建一个新的待用体调色板,把创建的屏幕缓冲区画到视图窗口的设备上下文(DC)。还可以调整父画面的大小从而使视图窗口正好适合背景图像。<br>      
这里我们看一下获取视图指针后,如何调用视图的公共成员函数。以下是CAnimView::NewBackground的功能:<br>      
BOOL CAnimView::NewBackground(CDIB* pDIB)<br>       
{kk1}<br>      
// Create a new buffer and palette.<br>       
if (!Create(pDIB)) {kk1}<br>       
return FALSE;<br>       
}<br>      
<br>      
// Map the colors of the background DIB to<br>       
// the identity palette we just created for the background.<br>       
pDIB-&gt;MapColorsToPalette(GetPalette());<br>      
<br>      
// Resize the main frame window to fit the background image.<br>       
GetParentFrame()-&gt;RecalcLayout();<br>      
ResizeParentToFit(FALSE);<br>      
// Try shrinking first.<br>       
ResizeParentToFit(TRUE);&nbsp;<br>      
// Let's be daring.<br>       
// Render the entire scene to the off-screen buffer.<br>       
Render();<br>      
<br>      
// Paint the off-screen buffer to the window.<br>       
Draw();<br>      
<br>      
return TRUE;<br>       
}<br>      
重画视图<br>      
将背景DIB画到缓冲区并更新屏幕到视图窗口。这时构图(Render)函数将背景DIB拷贝到屏幕缓冲区,画图(Draw)函数把屏幕缓冲区画到视图窗口。画图(Draw)实在COSBView基类中实现的,读者可参见例程。下面是构图(Render)函数:<br>      
void CAnimView::Render(CRect* pClipRect)<br>       
{kk1}<br>      
CAnimDoc* pDoc = GetDocument();<br>       
CRect rcDraw;<br>       
<br>      
// Get the background DIB and render it.<br>       
CDIB* pDIB = pDoc-&gt;GetBackground();<br>       
if (pDIB) {kk1}<br>       
pDIB-&gt;GetRect(&amp;rcDraw);<br>      
// If a clipping rectangle was supplied, use it.<br>       
if (pClipRect) {kk1}<br>       
rcDraw.IntersectRect(pClipRect, &amp;rcDraw);<br>       
}<br>      
// Draw the image of the DIB to the off-screen buffer.<br>       
ASSERT(m_pDIB);<br>      
pDIB-&gt;CopyBits(m_pDIB,&nbsp;<br>      
rcDraw.left,<br>      
rcDraw.top,&nbsp;<br>      
rcDraw.right - rcDraw.left,<br>       
rcDraw.bottom - rcDraw.top,<br>       
rcDraw.left,&nbsp;<br>      
rcDraw.top);<br>      
以上就是创建背景图像的基本过程。<br>      
<br>      
在Windows应用程序中,如果想使用离屏位图制作子图形动画,就需要C++类来表示子图形和便于图形动起来。动画包含一个固定的背景图像,零个或多个能在背景上四处移动的子图形。下面各节定义了        
Sprite 类用以构造子图形的模型,还定义了 SpriteAnimation        
类来维护子图形和背景图像。<br>      
Sprite类<br>      
Sprite有两个Image对象:<br>      
·黑色背景上的Sprite图像<br>      
·白色背景上的Sprite图像的黑色轮廓像(掩膜)<br>      
animate 函数是 SpriteAnimation        
类不可少的函数,由这个函数可知,要做到绘制 Sprite        
轮廓时丝毫不影响其背景图像和掩膜是必不可少的。除开图像和掩膜,Sprite        
类还包括x,y位置,以及其他一些记录它在背景上的运行轨迹的变量。<br>      
一个Sprite对象还有它自己的显示优先级。显示优先级用整型量表示,存储在成员变量disp_        
priority中,它决定了绘制重叠子图形的次序——优先级高的子图形被绘制到优先级低的子图形的上面。<br>      
另一个成员变量,DRAWPROC类型的dproc很有意思,它由下面的typedef语句声明:<br>      
typedef void (_FAR PASCAL *DRAWPROC) (HDC hdc,short x,short y,LFVOID        
data)<br>      
可见,dproc 是指向函数的指针。在需要绘制 Sprite        
图像的任何时候都会调用dproc指定的函数。您可以绘制对象——例如直线、矩形、椭圆或文本——这样一个子图形就可以有多个位图式图像,例如应用程序        
ANIMATE 显示移动文本,就用到了 Sprite 的这个特性。<br>       
<br>      
Sprite类继承了Borland类库(CLASSLIB)中的Sortable类,由于只有Sortable        
对象才可以放在SortedArray(Borland CLASSLIB        
的另一个类)中,继承后就可以把Sprite 对象存储在SortedArray        
中。由于继承了Sortable ,Sprite 类必须定义以下的成员函数:<br>       
classType isA ( ) const ;<br>       
char_FAR * nameof( ) const ;<br>       
hashValueType hash Value( ) const ;<br>       
void printOn (ostream_FAR&amp; os) ;<br>       
这四个函数的定义都很简单。函数的isA返回唯一的整型标识符,表示Sprite类,函数nameOf返回类名,即字符串“Sprite”。<br>      
此外,为了Sprite对象能够正确地排序,Sprite类必须包括下面的函数:<br>      
int isLessThan (const Object_FAR&amp; ob ) const ;<br>       
int isEqual(const Object_FAR&amp; ob ) const ;<br>       
函数isLessThan用来检验某个Sprite是否“小于”另一个。正如程序所定义的那样,isLessThan通过比较子图形的是显示优先级来决定哪个子图形“小些”。<br>      
初始化 Sprite<br>       
创建和初始化Sprite的典型方法是使用构造函数,它以图像文件名和掩膜文件名为多数。<br>      
Sprite::sprite (HDC hdc,LPSTR imagefilename<br>       
,LPSTR maskfilename,short priority)<br>       
该构造函数调用init_image函数装入相应的图像位图和掩膜位图。构造函数还要求有设备场景的句柄。这是因为图像位图和掩膜位图要转换为设备无关格式,这一步骤需要一个DC。<br>      

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -