1. 程式人生 > >《第一章》SFML 入門

《第一章》SFML 入門

 


建立視窗


 

建立視窗的只需要一行程式碼:

#include <SFML/Graphics.hpp>

int main()
{
    sf::Window window(sf::VideoMode(200, 200), "HUANGCHENGTAO!");  //建立視窗程式碼
    sf::sleep(sf::seconds(3)); //新增此程式碼 這樣我們就可以建立視窗之後,執行程式碼可以看到視窗,否則不可以
  
    return 0;
}

● main函式唯一做的是通過呼叫sf :: Window建構函式初始化視窗變數,之後程式退出。 還有一種方法可以使用預設建構函式開啟一個視窗,然後呼叫Window :: create()。 這個函式的引數與建構函式完全相同,我們剛剛講過。 如果在已經開啟的視窗上調 Window :: create(),它將關閉視窗並使用新的引數集重新初始化它 。

● 請注意 Window 和VideoMode 都在sf名稱空間中。 SFML中的每個類都在該名稱空間下,該名稱空間將SFML中的所有類與其他庫中的類分開。

● 我們可以在建立視窗時,視窗的大小、標題、樣式和圖形設定時指定各種配置。您可能已經注意到我們將兩個引數傳遞 給 Window建構函式 - 一個VideoMode例項和一個字串(標題)。 建構函式實際上最多可以使用四個引數,最後兩個是可選的 -  Style和ContextSettings。


VideoMode
 


●  VideoMode類包含顯示一個視窗的資訊,例如寬度、高度和每個畫素的位元數。最後一個引數是表示單個畫素顏色的位數。它的預設值為32,

如果我們想要建立一個全屏視窗,所提供的值必須由機器的顯示器和顯示卡支援。如果我們為全屏視窗選擇無效的引數,視窗建立將會失敗的。可以使用 VideoMode::isValid()  方法檢 查VideoMode   類的有效性,結果返回一個布林值。

●  如果我們需要根據PC端桌面版的大小(或畫素深度)建立視窗,VideoMode::getDesktopMode()是一個靜態方法。另一方面,如果我們要在全屏模式下建立一個視窗,我們可能需要使用  VideoMode::getFullScreenModes() 檢查可用的解析度。這將返回顯示模式的std::vector,我們可以自己選擇其中一種模式,或者讓使用者決定哪種模式最適合他們。

然而,僅僅指定全屏視訊模式還不足以建立全屏視窗。我們也需要設定一個視窗的樣式。

 


Style
 


●  Style引數是一個位掩碼。掩碼是標誌的組合,其中每個標誌代表掩碼的一個特定位。在本例中flags儲存在 sf::Style 名稱空間中的enum中。我們可以使用flags 的組合來建立所需的標誌掩碼。以下是SFML提供的風格:

Enum value 描述
sf::Style ::None 這個窗戶沒有任何裝飾,也不能與任何其他風格相結合
sf::Style ::Titlebar 新增一個標題欄
sf::Style ::Resize 這增加了一個最大化按鈕。還允許手動調整視窗的大小
sf::Style ::Close 新增一個關閉按鈕
sf::Style ::Fullscreen 這將以全屏模式開啟視窗。注意,這不能與任何其他樣式組合,需要有效的顯示模式。
sf::Style ::Default 這將標題欄、大小調整和關閉組合在一起。這是預設樣式。

可以通過使用位運算子來組合不同的樣式。如果我們想要一個帶有標題欄和關閉按鈕的視窗,我們可以這樣寫:

sf::Uint32 style = sf::Style::Titlebar | sf::Style::Close;

這裡要做的唯一一件事就是將該樣式作為Window建構函式的第三個引數傳遞。


ContextSettings
 


● 最後一個引數是ContextSettings的一個例項。 此結構是一組設定的集合,描述了所需的渲染上下文。 SFML使用OpenGL進行渲染,因此這些設定與它直接相關。 可用的上下文設定如下:

depthBits ——這指的是深度緩衝區位數。

stencilBits —— 這指的是模板緩衝區的位數。

antialiasingLevel: —— This refers to the requested number of multisampling levels

majorVersion and minorVersion: —— 這些是指所要求的OpenGL版本

這些設定中的每一個都將在第5章(操作2D攝像機)中得到更詳細的解釋,您將學習如何使用OpenGL直接渲染物體。


Disabling the mouse cursor (禁用滑鼠游標)
 


●  Window類有一個方法,可以在視窗上設定游標的可見性 —— Window :: setMouseCursorVisible()。 對於不使用游標的遊戲,或者當我們想要將游標的影象更改為與預設情況不同的內容時,這是非常有用的。


The game loop 


下面是一個典型的遊戲迴圈:

#include <SFML/Graphics.hpp>

int main()
{
  
    sf::RenderWindow window(sf::VideoMode(200, 200), "HUANGCHENGTAO!");  //建立視窗程式碼
    sf::sleep(sf::seconds(3)); //這樣我們就可以建立視窗之後,執行程式碼可以看到視窗,否則不可以
    while (window.isOpen()) //遊戲迴圈
    {
        /*
        處理輸入——處理來自輸入裝置和視窗的事件。
        更新框架——更新場景中的物件
        渲染框架 —— 將場景中的物件渲染到視窗上
         */
    }
  
    return 0;
}

典型的遊戲迴圈有三個主要階段:

        處理輸入——處理來自輸入裝置和視窗的事件。
        更新框架——更新場景中的物件
        渲染框架 —— 將場景中的物件渲染到視窗上

SFML中的輸入處理可以通過捕獲事件(由視窗分配)或直接查詢輸入裝置的當前狀態來完成。這兩種方法有不同的用途。例如,我們可能想關閉按鈕按下事件上的視窗,或者只要按下某個鍵,我們的主角就會向右移動。

 

● 在捕獲和使用事件後,我們到達更新框架階段。在這個階段,我們想要推進我們的遊戲邏輯,更新我們的世界狀態

 

●在我們完成物件更新後,迴圈的最後階段就會出現。 在這裡,我們清除從上次繪製的所有內容,並再次渲染螢幕上的每個物件。


Event handling (處理事件)
 


可以通過  bool Window :: pollEvent(sf :: Event&event) 從視窗查詢事件。 如果有一個事件等待處理,該函式將返回true,並且事件變數將被事件資料填充。 如果不是,則該函式返回false。 同樣重要的是要注意,一次可能有多個事件;因此我們必須確保捕獲每個可能的事件。 以下是典型的事件迴圈:

  while (window.isOpen()) //遊戲迴圈
    {
        sf::Event event;
        while (window.pollEvent(event))
        {

        }
    }

請務必注意C ++中的Event類包含一個union。 這意味著其中只有一個有效成員。 訪問任何其他成員將導致未定義的行為。 我們可以通過檢視事件型別來獲取有效成員。

事件型別在邏輯上可以分為四個部分,具體取決於它們與什麼有關:

  • Window
  • Keyboard
  • Mouse
  • Joystick

Window related events


Enum value Member associated Description
Event::Closed None 當作業系統檢測到使用者想要關閉視窗時觸發此事件——關閉按鈕、組合鍵等等。
Event::Resized Event::size holds the new size
of the window
當作業系統檢測到視窗已手動調整大小或已使用Window :: setSize()時,將觸發此事件。

Event::LostFocus


Event::GainedFocus

None This event is triggered when the window loses or gains focus. Windows which are out of focus don't receive keyboard events.

Keyboard related events


Enum value Member associated Description

Event::KeyPressed


Event::KeyReleased

Event :: key儲存 按下/鬆開 的鍵 當按下或鬆開焦點視窗上的單個按鈕時,將觸發此事件。
Event::TextEntered Event :: text儲存 UTF-32 unicode 的字元值 每次輸入字元時都會觸發此事件。這將從使用者輸入中生成可列印的字元,對於文字欄位非常有用。

 


Mouse related events
 


Enum value Member associated Description

Event::MouseMoved

Event::mouseMove holds the new mouse position 當滑鼠在視窗內更改其位置時會觸發此事件。

Event::MouseButtonPressed


Event::MouseButtonReleased

Event::mouseButton   holds the pressed / released button and the mouse position 在視窗內按下滑鼠按鈕時會觸發此事件。 目前支援五個按鈕 - 左,右,中,其它按鈕1和其它按鈕2。
Event::MouseWheelMoved Event::mouseWheel  儲存了滑鼠的滾輪移動了多少時間以及滑鼠位置 當滾動輪在視窗內移動時觸發此事件

joystick related events
 


Enum value Member associated Description

Event::JoystickConnected


Event::JoystickDisconnected

Event :: joystickConnect 儲存剛才連線 / 斷開的操縱桿的ID 當操縱桿連線或斷開時觸發此事件。

Event::JoystickButtonPressed


Event::JoystickButtonReleased

Event :: joystickButton 儲存按下的按鈕次數和操縱桿ID 按下操縱桿上的按鈕時會觸發此操作。 SFML最多支援8個操縱桿,每個操縱桿最多32個按鈕。
Event::JoystickMoved Event :: joystickMove儲存移動的坐軸,新的座標軸位置和操縱桿ID
當操縱桿的軸線移動時觸發。可以通過Window::setJoystick threshold()設定移動閾值。SFML最多支援8個軸

Using events
 


通過呼叫Window :: pollEvent()獲取事件後,我們可以通過檢視Event :: type來檢查它的型別。 該事件的型別為Event :: EventType,它是Event類中的列舉。 以下是典型的關閉事件的實現方式:

 while (window.isOpen()) //遊戲迴圈
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }
    }

這裡,Window :: close()函式將負責關閉視窗。 如果視窗變數超出範圍,則呼叫解構函式,並且關閉視窗。

 

如果我們想處理多個事件,那麼使用Switch語句是有意義的,因為它提高了可讀性。讓我們看看鍵盤鍵是如何按下和釋放的:

#include <SFML/Graphics.hpp>
int main()
{
   
    sf::RenderWindow window(sf::VideoMode(200, 200), "HUANGCHENGTAO!");  //建立視窗程式碼
    sf::sleep(sf::seconds(3)); //這樣我們就可以建立視窗之後,執行程式碼可以看到視窗,否則不可以
    sf::CircleShape shape(100.f); //建立圖形物件
    shape.setFillColor(sf::Color::Red); //改shape的填充顏色
    while (window.isOpen()) //遊戲迴圈
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::EventType::Closed:
                window.close();
                break;
            case sf::Event::EventType::KeyPressed:
                //如果按下空格鍵,請更改標題
                if (event.key.code == sf::Keyboard::Key::Space) //鍵盤按下事件
                {
                    window.setTitle("Space pressed");
                }
                break;

            case sf::Event::EventType::KeyReleased:  //鍵盤松開事件
                //如果空格鍵又被鬆開,則改變標題
                if (event.key.code == sf::Keyboard::Key::Space)
                {
                    window.setTitle("Space released");
                }//如果鬆開了Escape鍵,則關閉視窗
                else if (event.key.code == sf::Keyboard::Key::Escape)
                {
                    window.close();
                }
                break;
            default:
                break;
            }
        }
        window.clear();
        window.draw(shape);
        window.display();
    }
  
    return 0;
}

上面的程式碼演示瞭如何捕獲事件,以便在每次按下和鬆開空格鍵時更改視窗的標題。除此之外,當Escape鍵被鬆開時,視窗就會關閉。

Event :: key包含一個名為code的成員,code是Keyboard :: Key型別的列舉。

但是,Event :: EventType :: TextEntered 更好。 可以以相對簡單的方式檢測和處理單鍵被按下 和 鬆開。

但是,當涉及到特定的字元時,事情開始變得有點複雜。例如,如果我們想檢測時!符號已經輸入,我們必須檢視是否同時按下了兩個單獨的鍵。

在這種情況下,SFML通過提供簡單易用的TextEntered事件為我們節省了大量工作。 僅當按下表示字元的鍵組合時才會觸發該事件; 意味著單個鍵(例如,只有Shift)可能不會觸發事件。 當然,如果單獨按下K,事件將被正常觸發,並將包含該字元。


檢視這個示例,其中使用 TextEntered 事件將使用的字串是由字元組裝而成的,當按下Enter(或Reach)按鈕時,文字設定為標題:

 sf::String buffer;
    while (window.isOpen()) //遊戲迴圈
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::EventType::Closed:
                window.close();
                break;
            case sf::Event::EventType::TextEntered:
               //將字元直接新增到字串中
                buffer += event.text.unicode;
                break;

            case sf::Event::EventType::KeyReleased: 
               //將標題更改為當前緩衝區並清除緩衝區
                if (event.key.code == sf::Keyboard::Key::Return)
                {
                    window.setTitle(buffer);
                    buffer.clear();
                }
                break;
            default:
                break;
            }
        }
       
    }
    return 0;

注意,我們使用的字串緩衝區的型別是sf:string,而不是std:string。建立sf:string類是為了自動處理字串型別和編碼之間的轉換。