2011-04-04 40 views
12

我目前正在建立一個小型實時戰略二維引擎。並且我想知道如何處理許多不斷變化的精靈,這些精靈最終會隱藏我的屏幕。我只是想實現一些機器學習方法。我只是想實現一些機器學習方法。因此,我選擇了魔獸爭霸II棄用軟件ISO,無恥地使用了一些圖形,並在第一個問題上大跌眼鏡。Qt:有效地處理「很多像素圖」的QGraphicsItems? (RTS)

http://img263.imageshack.us/img263/1480/footman.png

正如你可以在上面看到,即使是魔獸爭霸II的簡單男僕已經得到了其動漫周邊50精靈。這是很多。它會經常改變精靈。 (黑線只是檢查我的alpha通道是否正確)

因此,最後的問題:如何有效地實現一個不斷變化的QGraphicsObject?我如何有效地實現一個反覆改變外觀的QGraphicsItem?

我是否簡單地重載了QGraphicsPixmapItem的paint()方法並繼續更改屏幕上使用的Pixmap?它會導致一些「口吃」? 我聽說有時候,創建一個所有像素圖是明智的/可能的,將它們全部隱藏起來,並在需要時複製它們。 (複製比其他操作更便宜) 還有其他智能的想法嗎?

感謝您的任何意見! (教程RTS引擎,複雜的東西,等...)

+0

我會建議使用Qt不是你可以選擇開發遊戲的最好的庫。你有沒有探索一些其他的選擇?當然,qt爲你做了很多,比如剪輯,精靈的簡單轉換等等,但是它同時也做了很多你不需要的東西......在我找到一些google搜索後這:http://www.libsdl.org/它可能比qgraphics更適合你的需求 – Tom 2011-04-05 10:17:45

+0

@Tom:感謝輸入,事實上,SDL確實是2D應用程序的優秀C庫。然而,你說得對,因爲我沒有說明,我對機器學習和RTS架構比對開發應用程序本身更感興趣。你可以在下面重新描述我的問題:好的圖書館如何處理一個擁有許多精靈的對象? (因此,我應該如何使用Qt實現它,這是本項目絕對需要的庫) – Fezvez 2011-04-05 10:55:34

+1

如果您將視口設置爲QGLWidget並自己手動繪製()已經在內存中緩存的pixmaps,則應該可以性能明智。 – Chris 2011-04-14 04:36:51

回答

15

(我會的總體思路先開始,一個可能的Qt的實施將遵循)

我不知道如何保存WCII精靈,但你應該使用精靈表(如果需要,可以自己構建它)。與此工作表相關的是,您將對包含至少動畫列表的精靈進行一些描述,並且對於每個動畫,它都是標識符/名稱以及幀列表。

您在描述這些動畫幀時所放置的詳細程度取決於您,但必須至少包含要顯示的精靈表的矩形。作爲一個例子,看一下this sprite sheet(顯然不是最優化的,但是對於一個例子來說,沒關係:))。以下是相關的animations descriptions(第12至39行)。所有動畫都不包括在內,但你會明白。

您可以看到「空閒」動畫是由3個幀組成的,子幀與精靈表中的前3幀相匹配。與此子樣相關聯,此樣本中還有2個信息:

  • 持續時間:在移動到下一個幀之前應該顯示幀多長時間?
  • 來源:框架的錨點是什麼?

現在,你將如何在Qt中實現它?

動畫的描述文件格式完全取決於你,但我建議一些層次結構文件格式。由於Qt提供了XML解析器,它可以是完美的。如果您習慣於提升並選擇像JSon這樣的輕量級格式,則可以使用boost。ptree來解析XML/JSon文件,並有一個通用接口來從中提取數據。

的圖形表示,你將不得不使用一些類:

  • 的QPixmap:從中我們可以繪製子矩形匹配動畫框架,
  • 一個QTimer到更新你的精靈,
  • 你自己的顯示類,說AnimatedSprite(從派生的QGraphicsObject,你需要的信號/槽s支持),
  • 和一個支持類,說TimerProxy(從QObject派生)。

我會通過描述TimerProxy角色開始。它的作用是發送時間更新消息。這是因爲Qt Graphics對象不提供任何類型的「定時」更新(例如,update(float dt),其中dt給出是您最喜歡的時間單位)。您可能想知道爲什麼我們使用代理類來處理時間。這是爲了限制活動的數量QTimer;如果你有其中的一個,那麼你最終可能會擁有大量計時器,這顯然是一個很大的禁忌。

所以它滿足了兩個角色:

  • 在現場的施工時間:所有AnimatedSprite將自己註冊到它提供了一個信號,讓我們將其命名爲錄入(INT毫秒),在現場運行
  • ,它會啓動一個QTimer,將超時設置爲您需要的粒度(您可以繼續以16ms的速度進行約60 fps的處理)。 QTimer的信號timeout()將關聯到一個專用插槽,它將觸發updateTime(int msecs)其中msecs設置爲您之前設置的計時器粒度。

現在,對於解決方案的核心:AnimatedSprite。此類具有以下作用:

  • 閱讀&存儲動畫說明它會需要,
  • 開始,更新&停止動畫
  • 繪製活躍精靈的上QGraphicScene
框架

初始化時,您應該給它以下信息:

  • TimerProxy(由您的場景擁有,或擁有該場景的班級)的實例。當提供的這種情況下,您只需連接TimerProxy ::錄入(INT)信號到私有槽將更新當前動畫,
  • 的QPixmap抱着spritesheet,
  • 和動畫描述

在運行期間,更新方法將看起來像:

  • 私人timeUpdated(INT)插槽,將檢查當前動畫的幀應是更新的,並相應地更新它,
  • 公共動畫的方法,像startAnim(常量的QString & animName),這將改變當前動畫,復位經過時間計數器,並更新當前子矩形繪製以匹配新動畫的第一幀。

timeUpdated(INT)插槽,你要更新經過的時間,並檢查它是否應該讓動畫前進到下一幀。如果是這樣,只需將當前幀指針更新爲新幀。

最後,渲染,你只是重新實現的QGraphicsItem ::塗料(...)方法繪製當前subrect,這可能看起來像:

void AnimatedSprite::paint(QPainter *painter, 
          const QStyleOptionGraphicsItem * /*option*/, 
          QWidget * /*widget*/) 
{ 
    painter->drawImage(mCurrentAnim.mCurrentFrame->mOrigin, 
         mSpriteSheet, 
         mCurrentAnim.mCurrentFrame->mSubRect); 
} 

希望幫助(而不是太大了,哇:s)

+3

哇!謝謝!這就是我想要的框架! – Fezvez 2011-04-23 09:38:52