bada 2D遊戲編程之六——一個基於線程的遊戲循環

 

bada 2D 遊戲編程之六——一個基於線程的遊戲循環
 
上篇文章中用 定時器實現了一個「 基於時間的固定間隔遊戲循環」,這篇文章仍是在上篇文章的基礎上,用 bada 平臺提供的線程機制來實現這麼一個遊戲循環。這中實現方式的主要特色是採用了多線程編程的機制,用單獨的一個線程來實現遊戲循環,在這個線程當中進行 HandleEvent(),UpdateLogic() Draw() 的處理。
 
1, bada 平臺線程機制
bada 平臺的線程功能是由 Osp::Base::Runtime::Thread 類來提供的。在 bada 平臺上存在 2 種類型的線程,

一種是事件驅動(Event-driven)線程,這種類型的線程運行起來以後,它的Run()函數一直運行着,直到中止線程運行纔會從Run()函數返回退出,同時它在Run()函數中進行事件監聽,當其它運行的線程經過調用Thread:: SendUserEvent()來向它發送事件通知後,它在Thread:: OnUserEventReceivedN ()函數對接收到的事件進行處理。html

 
還有一種是工做者( Worker )線程,這種線程須要和 Osp::Base::Runtime::IRunnable 結合使用,工做者線程在執行時會調用 IRunnable::Run() 函數,這樣將須要運行的代碼放到 IRunnable::Run() 函數中就能夠了,在這裏 Run() 函數中的代碼是按照線性的方式被執行一次,執行完成後線程也就結束了。
 
在這裏咱們選擇工做者線程來實現遊戲循環,由於事件驅動線程與其它線程之間採用的是異步的通訊方式,沒法與基於定時器的實現接口保持一致;而採用工做者線程,能夠在 Run() 函數中加入一個 While() 死循環,再加入線程的 Sleep() 功能就可以實現定時循環了,實現方式上能夠和基於定時器的方式保持一致。
 
2, 線程的使用方法
在實現循環時用到的 Osp::Base::Runtime::Thread 的主要方法 :

函數
功能描述
Thread(void)
默認構造函數
Construct(IRunnable& targe, long stackSize, ThreadPriority priority)
初始化函數,傳入 IRunnable
Start(void)
開始線程
Sleep(long milliSeconds)
暫停線程執行

 
IRunnable 提供的方法 :

函數
功能描述
Run(void)
經過被線程回調來執行函數中的代碼

 
這樣將須要被線程執行的代碼塊放到 IRunable::Run() 函數中,線程開始執行後就會調用 IRunable::Run() 方法,執行其中的代碼,因此遊戲循環的實現代碼都是放在了 IRunable::Run() 函數中。
 
3 ,類圖
下圖是遊戲循環涉及到的各種之間的關係。

4 ,相關的類和接口
下面對實現遊戲循環的一些基本的接口和類進行介紹:
1 TGThreadLoop 類,這是遊戲循環對應的一個具體的類,它繼承了 TGLoopBase ,並使用 Osp::Base::Runtime::Thread 來實現循環功能。
 
class TGThreadLoop : public TGLoopBase ,
                    public Osp::Base::Runtime:: IRunnable
{
public :
    TGThreadLoop();
    virtual ~TGThreadLoop();
    result Construct( void );
public :
    virtual Osp::Base:: Object * Run( void );
public :
    void Start();
    void Pause();
    void Stop();
private :
    Osp::Base::Runtime:: Thread * __pThread ;
    bool __isRunning ;
    bool __isPaused ;
};
 
5 ,循環實現
遊戲循環是在 TGThreadLoop 中實現的,主要在 Run() 函數中完成循環邏輯,其它的像 Start(),Pause(),Stop() 等函數對循環進行控制。
 
TGThreadLoop::TGThreadLoop () : __pThread (NULL), __isRunning ( true ), __isPaused ( false )
{
}
 
TGThreadLoop::~TGThreadLoop ()
{
    if ( __pThread )
    {
       delete __pThread ;
       __pThread = NULL;
    }
}
 
result
TGThreadLoop::Construct ( void )
{
    result r = E_SUCCESS;
 
    __pThread = new Thread ();
    __pThread -> Construct (* this , THREAD_PRIORITY_HIGH );
 
    return r;
}
 
Osp::Base:: Object *
TGThreadLoop::Run ( void )
{
    while ( __isRunning )
    {
       long long startTime = 0;
       Osp::System:: SystemTime :: GetTicks (startTime);
 
       if ( __pStatusListener && ! __isPaused )
       {
           __pStatusListener ->HandleEvent();
           __pStatusListener ->UpdateLogic( __frameInterval );
           __pStatusListener ->Draw();
       }
       long long endTime = 0;
       Osp::System:: SystemTime :: GetTicks (endTime);
 
       long long deltaTime = endTime - startTime;
 
       int leftTime = __frameInterval - deltaTime;
       if (leftTime > 0)
       {
           __pThread -> Sleep (leftTime);
       }
       else
       {
           //Do Nothing
       }
    }
    return NULL;
 
}
 
void
TGThreadLoop::Start ()
{
    __isPaused = false ;
    __pThread -> Start ();
}
 
void
TGThreadLoop::Pause ()
{
    __isPaused = true ;
}
 
void
TGThreadLoop::Stop ()
{
    __isRunning = false ;
}
 
TGThreadLoop 類中經過引發了 __isPaused __isRunning 這兩個標誌位來對線程的狀態進行標識,從而實現對遊戲循環的控制。
 
6 ,總結
下面前面的兩種實現方式之間的類圖關係,

能夠看出這兩種實現方式在接口上保持了徹底一致,僅僅是實現的方式不同,這樣即便在開發過程當中將這兩種遊戲循環進行相互替換也不須要改變任何接口,很是的方便。
 
下面是這兩種實現方式之間的一個簡單比較:
基於定時器的遊戲循環,按照這種機制開發的遊戲是運行在單線程環境之中,全部的任務都是交給程序的主線程來處理。這種方式的好處是實現簡單,不須要考慮多線程編程;但也可能存在主線程處理任務過多而形成遊戲阻塞的狀況。
基於線程的遊戲循環,採用的是多線程編程,主線程用於相應用戶的輸入事件,而循環線程則負責遊戲的運行,能夠避免主線程阻塞的狀況;可是引入的這個線程一直運行着,很是的消耗系統資源,最直接的表現就是遊戲比較耗電。
 
你們能夠根據本身的須要來選擇合適的實現方式。
相關文章
相關標籤/搜索