2012-03-01 186 views
2

我使用D和SDL創建一個簡單的遊戲。我正在嘗試創建一個SDL封裝器,以便我不直接使用它。現在我試圖創建自己的Input類,儘可能遠離SDL的輸入。不過,我在爲鍵盤鍵分配正確的枚舉值時遇到了一些麻煩。將枚舉賦值給其他枚舉值

到目前爲止,我已經嘗試過,爲鍵盤按鍵分配SDL的枚舉,因爲這似乎是最簡單的,但它似乎沒有工作,沒有打印到控制檯。

--SDLInput--

import derelict.sdl.sdl; 
import SDLApp; 

class SDLInput 
{ 
private: 
    SDLApp sdlapp; 
    SDL_Event event; 
public: 
    this() 
    { 
     event = sdlapp.event; 
    } 

    bool KeyPressed(SDLKey key) 
    { 
     if(event.type == SDL_KEYDOWN && event.key.keysym.sym == key) 
      return true; 
     else 
      return false; 
    } 

    bool KeyReleased(SDLKey key) 
    { 
     if(event.type == SDL_KEYUP && event.key.keysym.sym == key) 
      return true; 
     else 
      return false; 
    } 
} 

--DPInput--

import SDLInput; 
import derelict.sdl.sdl; //Eventually I'd get rid of this, only here for testing 

class DPInput 
{ 
private: 
    SDLInput sdlinput; 

public: 
    enum DPKey 
    { 
     DPK_SPACE = SDLK_SPACE 
    } 

    this() 
    { 
     sdlinput = new SDLInput; 
    } 

    bool KeyPressed(DPKey key) 
    { 
     return sdlinput.KeyPressed(key); 
    } 
} 

--DPApp--

import SDLApp; 
import DPInput; 
import DPTime; 
import std.stdio; 

class DPApp 
{ 
    //... 
    void Run() 
    { 
     Init(); 
     Loop(); 
     Cleanup(); 
    } 


    void Loop() 
    { 
     dptime.InitNextTime(); 

     while(gameRunning) 
     { 
      if(sdlapp.PollQuit()) 
       gameRunning = false; 

      UpdateGame(); 
      Render(); 

      dptime.DPDelay(dptime.TimeLeft()); 
      dptime.UpdateNextTime(); 
     } 
    } 

    void UpdateGame() 
    { 
     if(dpinput.KeyPressed(dpinput.DPKey.DPK_SPACE)) 
      writeln("DPAPP: SPACE PRESSED"); 
    } 

} 

//..main這裏調用的run()

回答

0

我根本不知道SDL,但我看到一些可能的問題w ο此代碼:

1)eventSDLInput獲取更新?它看起來像你假設SDL_Event將始終自動包含最新的「狀態」?我有一種感覺,它不會。

注意SDL_Event可能是一個結構(?),做this.event = app.event;將事件在確切點複製,你現在有兩個不同的地方兩個不同的事件對象和更新一個不會更新等。 (如果SDL_Event是一類,然而,然後this.event將指向同一個對象app.event

2)雖然這是很難說,因爲代碼是不完整的,我認爲這個代碼是困惑事件如何運作。從我所能看到的這種設計中,意味着您只能在每一幀中處理一個事件,而任何其他事件只會被丟棄。

想象一下,用戶同時按下兩個按鈕。這可能會在一幀中生成兩個按鍵事件,但您有一個事件對象,我認爲您會覆蓋所有傳入事件,然後讀取此對象。您有可能在此過程中丟棄事件。此外,只有通過僅查看最後一個事件才能知道某個特定按鍵是否被按下。如果兩個鍵被按下,你只看最後一個事件,你不可能知道第一個鍵是否關閉,那麼這些信息將永遠丟失。

傳統的方法是讓事件調度程序調用某些函數,並將事件對象與某些有關該事件的額外信息一起傳遞,然後保留自己的輸入狀態。這會在您的update()功能之外發生,並且在update()之前可能會發生多次。例如,你可以有這樣的:

// Pseudo code 
bool keys[256]; 

void keyDown(Event e){ 
    keys[e.keyCode] = true; 
} 

void keyUp(Event e){ 
    keys[e.keyCode] = false; 
} 

void update(){ 
    if(keys[KEY_W]) 
     movePlayerForward(); 
    if(keys[KEY_SPACE]) 
     jumpPlayer(); 
} 

void loop(){ 
    while(true){ 
     fireAllQueuedEvents(); // Could call keyUp/Down several times 
     update(); 
     render(); 
    } 
} 

fireAllQueuedEvents()可以發射一個以上的事件,它會正常工作。這裏W和空格鍵可以同時按下,玩家可以跳躍和移動。現在,我不知道如何在SDL中執行此操作,或者如何處理輸入「SDL方式」,除非知道,否則請輸入docs-mobile!我猜..

一般而言,在事件處理中,需要在某處存在事件隊列。我懷疑SDL有一個或依賴於底層操作系統:es事件隊列。在某個時候,這個隊列需要發送等待事件,我懷疑SDL在那個時候有攔截這些事件的函數。這就是您需要在系統中掛鉤的位置,您需要響應事件發生時的狀態,然後更新自己的數據結構以獲取稍後在update()中使用的密鑰上/下狀態等。將事件對象存儲起來並在稍後查看它們以檢查是否按下某個鍵並沒有什麼意義,因爲在最壞的情況下,您必須按順序存儲至少一打事件對象,然後按通過他們所有隻是爲了弄清楚,如果一個關鍵是上升或下降。事件對象沒有描述事物的「大國」,他們只描述了一個單一變化。看起來你只是在檢查最新的變化。這不適用於多個按鍵/事件。

至於枚舉賦值:看起來是正確的。

(祝遊戲:)

+0

感謝您的回覆。你說得對,這個事件並不包含當前的最新事件。這是我第一次嘗試自己構建遊戲(我在書籍或教程的幫助下完成了其他遊戲),因此我希望代碼在很多錯誤的情況下都很糟糕。我編輯了我如何處理事件,現在我得到輸出到控制檯。我將返回並實現您的事件處理結構,它看起來更乾淨。 – RedShft 2012-03-02 18:50:44

+0

酷!保持樂趣:) – kraybit 2012-03-03 08:36:36

1

不要誤會我的意思,我不是反對DIY的方式,但如果你想使你的項目去,儘量在不重新發明輪子早期階段 - 使用已經存在的工具,由數百個開發人員完成(並測試)。

這就是說,我竭誠推薦您使用優秀的Derelict2 - http://www.dsource.org/projects/derelict。它已包含您上面所寫的所有內容以及更多(幾乎所有核心​​SDL庫)。

+0

感謝您的迴應。我是D的新手,並且是一個新的程序員(大概有6個月的經驗),所以我還有很多東西還沒有學到。就我對廢棄2的理解而言,它只是加載了sdl庫。我如何使用derelict2來正確地讓我的項目進行? – RedShft 2012-03-02 18:54:24

+0

從最簡單的例子開始,玩得越多,您就越容易按照自己的想法制作遊戲。 – DejanLekic 2012-03-07 19:17:04