您的位置广东网盟 > 文章资讯 > 软件应用 > 编程开发 > VC/VC++ > 文章内容

基于Nokia S60的游戏开发(4)

作者:佚名  来源:不详  发布时间:2008-7-30 21:39:51

  应用程序在屏幕上的描画一般是使用CWsScreenDevice图形设备来完成,与CWindowGc图形上下文相关联。CONE提供了一个CWindowGc实例作为描画控件的标准图形上下文。它被CCoeEnv创建并且可以使用CCoeControls::SystemGc方法访问。CWindowGc的描画方法在客户端窗口服务器缓冲区上进行缓冲。

  描画要么是一个系统初始事务要么是一个应用程序初始事务。系统初始描画在窗口创建的时候被触发,或者当窗口内容因为窗口重叠而失效的时候被触发。对于后一种情况,窗口服务器为每个窗口保持一个无效的区域。如果一个窗口需要重画,窗口服务器发送一个重画事件到拥有无效窗口的应用程序中。CONE然后使用无效区域来建立需要被重画的控件,并且调用它们的Draw方法。这就是为什么每个控件都应该实现Draw方法来重画它们自己。CCoeControl中的Draw的默认为控件为空。下面的代码说明了Draw方法的示例:

void CExampleControl::Draw( const TRect& /*aRect*/ ) const
{
 // Get the system graphics context
 CWindowGc& gc = SystemGc();
 // Set drawing settings
 gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
 gc.SetBrushColor( KRgbRed );
 // Draw
 gc.DrawLine( TPoint(10,10), TPoint(30,10) );

  Draw方法的TRect参数指明了需要重画的无效区域。然而大多数控件忽略矩形,由于它非常简单并且重新描画整个控件也不是非常慢。

  当一个应用程序的数据或者状态改变的时候,需要应用程序初始化描画,并且屏幕需要更新。CCoeControl提供非虚拟DrawNow方法,指明控件将要描画的窗口服务器,调用控件的Draw方法,最后指明完成描画的窗口服务器。CCoeControl还提供了DrawDeferred方法,使窗口无效并且在窗口服务器中触发一个新的重画事件。这两个方法之间的差异是DrawNow强制控件立即重画自己,而DrawDeferred导致一个重画事件将使用低优先级操作。由于CONE使用比重画事件更优先的级别处理用户输入事件,所以任何未定的用户输入事件都将首先处理。但由于需要重画整个控件,故都是很繁重的操作,通常只有改变的部分需要重画,这可以使用下面的代码做到:

void CExampleControl::DrawBitmap( const TPoint& aPoint,
const CFbsBitmap* aBitmap )
{
 // Get the system graphics context and control rectangle
 CWindowGc& gc = SystemGc();
 // Establish drawing rectangle
 TRect rect = TRect( aPoint,
 TSize( aBitmap.iWidth, aBitmap.iHeight ) );
 // Activate graphics context
 ActivateGc();
 // Invalidate window
 Window().Invalidate( rect );
 Window().BeginRedraw( rect );
 // Draw a bitmap
 gc.DrawBitmap( aPoint, aBitmap );
 Window().EndRedraw();
 // Deactivate graphics context
 DeactivateGc();

  上面的示例代码在aPoint参数定义的位置画一个CFbsBitmap。示例中值得注意的是图形上下文在使用之前需要激活,在描画完成之后失活。还有窗口服务器需要取得客户端即将启动重画的信息,这使用BeginRedraw方法来完成。由于窗口服务器只允许一个应用程序在无效区域中描画,所以需要Invalidate方法。在一个系统初始重画中,CONE激活图形上下文并且调用用于应用程序的BeginRedraw方法。如果窗口已经无效了,那么Invalidate方法就不必被调用了--这就是为什么系统初始需要被首先描画。
  子图形(精灵)

  子图形是一个经过蒙板化(Mask)的位图,可以在应用程序不重画底层窗口的情况下移动。如果游戏不需要经常更新背景,那么使用子图形就再好不过了。例如类似于PacMan这样的游戏,在这种游戏中动画在一个不能卷轴并且固定的背景上移动。重画是靠窗口服务器来执行的,替代一个较高优先性的任务。这种游戏要考虑的是平滑的动画和子图形的运动。Symbian OS提供两种不同的子图形:指针和动画位图。图1说明子图形类的层次。
 

图1说明子图形类的层次

  RWsSpriteBase是一个用于子图形的抽象基本类。它拥有一个或多个包含子图形的位图数据的TSpriteMembers。通过指定带有不同的位图的多个成员,子图形就可以活动起来了。TSpriteMember还定义了位图的蒙板,子图形中位图的位置和位图显示的时间间隔。RWsSprite是一个用于子图形的具体的类。除了构造器之外,它只提供一个方法SetPosition,可用于移动子图形。下面的代码说明了使用从MBM文件中装载的位图创建子图形的示例。

RWsSprite sprite = RWsSprite( iEikonEnv->WsSession() );
User::LeaveIfError( sprite.Construct( Window(), TPoint(0,0), 0 );
for ( TInt i=0; i < 8; i += 2 )
{
 iMember[i/2].iBitmap = new ( ELeave ) CFbsBitmap();
 User::LeaveIfError( member.iBitmap->Load( KBitmapFile, i, EFalse ) );
 iMember[i/2].iBitmap = new ( ELeave ) CFbsBitmap();
 User::LeaveIfError( member.iMaskBitmap->Load( KBitmapFile, i+1, EFalse ) );
 iMember[i/2].iInvertMask = EFalse;
 iMember[i/2].iOffset = TPoint(0,0);
 iMember[i/2].iInterval = TTimeIntervalMicrosecond32(100000);
 User::LeaveIfError( sprite.AppendMember( iMember[i/2] ) );

  在子图形成员已经更新并且附加到RWsSprite类之后,子图形可以通过调用RWsSpriteBase::Activate来激活。在此之后,这个子图形显示在屏幕上,并且准备移动。子图形的内容可以使用RWsSpriteBase:UpdateMember方法来变化。因为CFbsBitmaps还可访问窗口服务器,所以只有子图形的位图句柄被发送到窗口服务器。这使子图形的位图的更新相当迅速。当子图形不再需要的时候,窗口服务器需要调用RWsSpriteBase::Close来释放资源。但不释放需要被删除的客户端成员数据。RWsPointerCursor是一个用于应用程序创建光标的类。

  双缓冲

  如果一个游戏的图形由多个需要被经常更新的运动对象组成,窗口服务器的客户端缓冲可能被充满并且可能会在所有对象都更新的时候溢出。用户可能会发现屏幕出现闪烁。如果一个视图仍然在更新的时候,可能会出现闪烁或者其他不希望的效果。这些问题的解决方案是双缓冲,图形先被画在一个屏外位图上,然后被画到屏幕上作为一个单一窗口服

[1] [2]  下一页

Tags:广东网盟  
  •         用户名: 验证码: 验证码,看不清楚请点击刷新验证码 (注“”为必填内容。)


    文章评论: [ 查看全部 ] 网友评论
    关于网盟 | 网站帮助 | 广告合作 | 下载声明 | 友情连接 | 联系方式

    Copyright © 2003-2008 Gdwg.Net. All Rights Reserved .
    中国广东网管联盟设计维护.网站备案:粤ICP备08020875号