现在的位置: 首页 > 综合 > 正文

直接写屏和特殊系统事件

2013年08月04日 ⁄ 综合 ⁄ 共 2209字 ⁄ 字号 评论关闭

 游戏软件一般用CDirectScreenAccess进行直接写屏。大家都知道,WindowServer会在需要停止直接写屏时回调MDirectScreenAccess::AbortNow接口函数,在可以重新启动时回调MDirectScreenAccess::Restart接口函数。可是具体在这两个函数中做什么,SDK没有过多的介绍。我在此说一下我的做法。如果你合理的处理了这两个函数,就可以轻松应对来电、屏保、程序切换等事件。
我们先说AbortNow,它的处理比较简单。你之需在其中停止驱动游戏逻辑的计时器(一般是个CPeriodic对象),停止声音模块(一般是一个CActive任务)就可以了。
值得费些力气的是Restart函数,它并不是在应用程序回到前台,并且可以进行全屏直接写屏时才被回调。所以不能在此时武断的恢复游戏逻辑,开始游戏。
首先,你要调用CDirectScreenAccess::StartL( )恢复直接写屏。但是必须给这个函数加上TRAP保护。因为它很可能抛出KErrNotReady异常。如果遇到这个异常,那你就直接返回好了,因为直接写屏此时并不能开始。接下来你需要检查一下绘图区域,看是否整个屏幕都可以被使用。如果不是,那也无需启动游戏逻辑,只需要用最后保留的后台缓冲区的内容更新直接写屏区域即可。第三种情况,如果直接写屏成功启动,并且整个屏幕都可以被绘制,才启动游戏逻辑,启动声音等其它模块。
完整的代码如下:
void CEngine::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/)
{
 // Cancel timer and display
 if (iGameTimer->IsActive())
  iGameTimer->CancelTimer();
 if (!iGameWorldPaused)
 {
  iGameWorldPaused = ETrue;
  iGameWorld->PauseGame(); // Pause audio stream etc.
 }
 iPaused = ETrue;
}

void CEngine::Restart(RDirectScreenAccess::TTerminationReasons /*aReason*/)
{
 TRAPD(error, SetupDirectScreenAccessL());
 switch(error)
 {
 case KErrNone:
  break;
 case KErrNotReady:
  if (iDirectScreenAccess->IsActive())
   iDirectScreenAccess->Cancel();
  if (iGameTimer->IsActive())
   iGameTimer->CancelTimer();
  if (!iGameWorldPaused)
  {
   iGameWorldPaused = ETrue;
   iGameWorld->PauseGame();
  }
  return;
 default:
  User::Panic(_L("Setup DSA Error"), error);
 }
 
 if(iPaused)
 {
  if(iGameDawingArea == iRegion->BoundingRect())
  {
   iPaused = EFalse; 
   if(!iGameTimer->IsActive())
   {
    iGameWorldPaused = EFalse;
    iGameWorld->ResumeGame();
    iGameTimer->Restart();
   }
  }
  else
  {
   PauseFrame();
  }
 }
 else
 {
  if(!iGameTimer->IsActive())
  {
   iGameTimer->Restart();
  }
 }
}

void CEngine::SetupDirectScreenAccessL()
{
 // Initialise DSA
 iDirectScreenAccess->StartL();

 // Get graphics context for it
 iGc = iDirectScreenAccess->Gc();
 
 // Get region that DSA can draw in
 iRegion = iDirectScreenAccess->DrawingRegion();
 
 // Set the display to clip to this region
 iGc->SetClippingRegion(iRegion);
}

void CEngine::PauseFrame()
{
 // Force screen update: this is required for WINS, but may
 // not be for all hardware:
 iDirectScreenAccess->ScreenDevice()->Update();
 
 // and draw from unchanged offscreen bitmap
 iGc->BitBlt(TPoint(0,0), &(iDoubleBufferedArea->GetDoubleBufferedAreaBitmap()));
 
 iClient.Flush();
}
};

抱歉!评论已关闭.