麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

基于Nokia S60的游戲開發之四

2019-11-17 05:50:00
字體:
來源:轉載
供稿:網友
  應用程序在屏幕上的描畫一般是使用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是一個用于應用程序創建光標的類?! ‰p緩沖  假如一個游戲的圖形由多個需要被經常更新的運動對象組成,窗口服務器的客戶端緩沖可能被布滿并且可能會在所有對象都更新的時候溢出。用戶可能會發現屏幕出現閃爍。假如一個視圖仍然在更新的時候,可能會出現閃爍或者其他不希望的效果。這些問題的解決方案是雙緩沖,圖形先被畫在一個屏外位圖上,然后被畫到屏幕上作為一個單一窗口服務器操作。尤其是對于那種在一秒鐘內重畫幾次屏幕的游戲,使用屏外位圖可以改善它們的性能?! ∫粋€屏外位圖可以使用位圖化的圖形上下文和圖形設備類來創建:CFbsBitGc和CFbsBitmapDevice。它們使用其他的上下文和設備類來創建和使用。為了獲得額外的性能,位圖自己就應該是一個CWsBitmap位圖。在屏外位圖更新之后,它可以使用正常的窗口服務器的描畫方法畫在窗口中?! ‘斠粋€應用程序在一個窗口畫位圖時,它轉化為和窗口相同的顯示模式。這是一個很消耗時間的操作,實質上可能降低描畫的速度。因此把位圖用于動畫的游戲應該在動畫開始之前就完成轉化。轉化可以通過使用一個屏外位圖來執行,如下面的示例方法演示:CFbsBitmap* CExampleControl::LoadAndConvertBitmapL(
Const TDesC& aFileName, TInt aBitmapId )
{
 // Load the bitmap
 CFbsBitmap* originalBitmap = new ( ELeave ) CFbsBitmap();
 CleanupStack::PushL( originalBitmap );
 User::LeaveIfError( originalBitmap->Load( aFileName, aBitmapId, EFalse ) );
 // Create a new bitmap, graphics device and context
 CFbsBitmap* newBitmap = new ( ELeave ) CFbsBitmap();
 CleanupStack::PushL( newBitmap );
 newBitmap->Create( originalBitmap->SizeInPixels(), Window()->DisplayMode() );
 CFbsBitmapDevice* graphicsDevice = CFbsBitmapDevice::NewL(bitmapConverted );
 CleanupStack::PushL( graphicsDevice );
 CFbsBitGc* graphicsContext;
 User::LeaveIfError( graphicsDevice->CreateContext( graphicsContext ) );
 TPoint zero(0,0);  // Blit the loaded bitmap to the new bitmap

 bitmapContext->BitBlt( zero, originalBitmap );
 CleanupStack::Pop(3);
 delete bitmapContext;
 delete bitmapDevice;
 delete originalBitmap;
 return newBitmap;
}    示例方法使用一個文件名和位圖ID作為參數,并且從一個MBM文件中裝載相應的位圖。假如一個游戲有許多位圖應該轉化,那么應該在游戲或者等級的初始化階段轉化。因此用戶就不會看到這個操作了。
  直接描畫  使用窗口服務器在屏幕上描畫需要一個上下文轉換,這會減慢描畫速度。為了繞過窗口服務器省去繁瑣的上下文轉換,可以直接訪問屏幕。這被稱作直接描畫。在Symbian OS中有兩種方法來直接在屏幕上描畫。  CFbsScreenDevice是一個可以被發送到屏幕驅動程序SCDV.DLL的圖形設備。在創建一個CFbsBitGc圖形上下文之后,它能像任何其他的圖形設備一樣使用。然而,可以直接在屏幕上描畫,而不需要使用窗口服務器。直接在屏幕上描畫的另一種方法是從系統中查詢屏幕內存地址。這可以使用UserSrv類來實現:TPckgBuf<TScreenInfoV01> infoPckg;
TScreenInfoV01& screenInfo = infoPckg();
UserSvr::ScreenInfo(infoPckg);
TUint16* screenMemory = screenInfo.iScreenAddress + 16;   屏幕內存有一個32字節的頭?! 〖词乖谄聊粌却鎯葘憯祿菴FbsScreenDevice稍微快一點,但是功能可能根據硬件和屏幕的設備驅動程序的不同而有差異。在一些基于Symbian OS的終端中,屏幕在內存變化的時候自動從屏幕內存中更新,而在其他的終端中描畫需要明確的激活。屏幕內存地址只對目標硬件有效,因此描畫代碼需要分為硬件和模擬器兩部分。在模擬器環境中,可以描畫到一個屏外位圖中,而不是屏幕內存中,然后使用正常的窗口服務器描畫方法位塊傳送到屏幕上。環境可以通過使用__WINS__定義來檢測出來。 #ifdef __WINS__ // Emulator environment
// Draw to an off-screen bitmap
#else // Hardware environment
// Draw directly to the screen memory
#endif    這兩種直接描畫方法的一個共同的問題是窗口服務器不了解描畫,因此它不能通知應用程序是否出現另一個窗口或者窗口組。 即使當應用程序失去焦點的時候得到一個事件,它們也不能停止直接描畫,因為直接描畫實在太快了,并且屏幕內容有可能被弄亂。 這可能發生在玩游戲的時候,忽然有電話打進來的情況下。
新近的GT 6.1版本提供了一個應用編程接口用于直接描畫,將能解決前面提到的問題。 這個應用編程接口由兩個類組成:一個MDirectScreenaccess類,提供用于應用程序的回調方法,還有一個CDirectScreenAccess類處理與窗口服務器的通訊。 下面的代碼說明CDirectScreenAccess實例是如何構造的,以及直接描畫支持是如何激活的。 iDrawer = CDirectScreenAccess::NewL(iEikonEnv->WsSession(), *iEikonEnv->ScreenDevice(), Window(), *this);
iEikonEnv->WsSession().Flush();
iDrawer->StartL();
iDrawer->ScreenDevice()->SetAutoUpdate(ETrue);    CDirectScreenAccess的NewL方法獲得一個窗口服務器會話、CONE的圖形設備、應用程序窗口和一個到MDirectedScreenAccess導出類的指針作為參數。 在CDirectScreenAccess::StartL被調用來激活直接描畫支持之前,客戶端窗口服務器緩沖應該溢出。 為了能自動更新屏幕,屏幕設備的SetAutoUpdate方法需要使用ETrue參數。 當直接描畫支持激活的時候,CDirectScreenAccess產生一個CFbsBitGc圖形上下文,可以被應用程序用來在屏幕上繪畫。 iDrawer->Gc()->BitBlt( TPoint(0,0), iBitmap );    當另一個窗口出現在應用程序窗口上時,CDirectScreenAccess從窗口服務器取得一個事件來中斷描畫。 CDirectScreenAccess然后調用MDirectScreenAccess派生類的AbortNow方法,這個方法必須被應用程序重載以便中斷描畫。 為了防止屏幕被弄亂,窗口服務器直到中斷描畫事件被處理的時候才畫重疊窗口



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 久久新网址 | 精品一区二区亚洲 | 91av久久| 精品亚洲视频在线观看 | 国产免费人做人爱午夜视频 | 国产一国产精品一级毛片 | 日本一道aⅴ不卡免费播放 久久久久久久高清 | 国产美女精品视频 | 日韩视频一区二区三区四区 | 久久精品一二三区 | 午夜视频色 | 麻豆91精品91久久久 | 久久老司机精品视频 | 精品国产一区二区亚洲人成毛片 | 国产精品午夜在线 | 国产在线精品一区二区三区 | 最近国产中文字幕 | 成人三级黄色片 | 国产91久久久久久 | aa国产视频一区二区 | 亚洲尻逼视频 | 亚洲精品在线观看免费 | 轻点插视频 | 国产免费www | 欧美一级高清免费 | 免费看一级视频 | 精品国产91久久久久久浪潮蜜月 | 色屁屁xxxxⅹ免费视频 | 亚洲午夜久久久精品一区二区三区 | 91精品国产99久久久久久 | 色视频在线观看 | www.国产一区.com | 在线天堂资源 | 日本成年网 | 中文字幕在线观看日韩 | av电影免费在线看 | 欧美成人小视频 | 日韩.www| 香蕉秀 | 久久精品视频在线 | 成人精品一区二区 |