# SDL2: 基礎架構 ###### tags: `SDL` ## 前言 恭喜你已經度過SDL2的第一個(也是最大的一個)難關: 安裝。現在我將先介紹SDL2是怎麼建構的? 我將在這裡講解一些基本的名詞解釋和概念。這裡的知識會比較瑣碎和無趣,如果你已經對SDL有一些概念可以先跳過一下。 ## 結構 **SDL2是基於C語言編寫的**。不是C++。任何有上過C/C++課程的人都應該知道兩件事: - C是函數導向,C++ 是物件導向,C++相容C,C沒有物件。 - 去他媽的指標(pointer)。 好那麼你已經了解SDL2的結構了。SDL2裡面的所有東西都是struct+pointer實現的。這造成它非常難以理解,很多函數的實現是搭在另一個函數之上,而且**不是成員函數,是一堆名字超長的函數**,所以想了解它的全貌,省省吧,你的程式課只有2~3學分。 那我們該如何使用它們呢? 幸好SDL教學大佬: LazyFoo幫我們解決很多問題。他的範例程式碼裡會把物件們都包成Class,方便各位使用。以下教學有時候也會幫忙建立幾個常用Class。 除了struct+pointer以外,SDL還提供很多旗標(flags),大部分是Uint32的enum(這部份看不懂就算了)。對於不知道旗標是什麼的人,簡單來說就是一種參數,用以傳入函數,但是被包裝成有名字而不是0、1、2這種方式傳入。 ## SDL的錯誤訊息 程式是30% coding+70% debug。所以必須了解SDL的錯誤訊息機制。欲取得SDL的錯誤訊息,請呼叫: ```cpp SDL_GetError(); ``` 函數回傳**最近一次發生的錯誤,而不是一個Stack (LIFO)的結構。**所以要在每個可能出錯的環節及時印出! 此外,函數回傳**C風格的字串(const char*)。**所以**請不要用cout去印**,使用方式可以看下一小節的程式。 ## SDL的座標系統 實際上,SDL2使用的座標系統與其他電腦程式相似,若你有使用過Photoshop、Illustrator等軟體,應該不會對座標系統太陌生。 定義: **原點是螢幕的左上角,橫向向右是x軸正向,縱向向下是y軸正向。單位皆為像素(px)。** :::info ❓ 像素是螢幕的基本長度單位。從顯示設定中可以找出電腦的解析度,解析度1920x1080代表電腦橫向被切成1920等分,即1920像素。要注意顯示比例若不是100%,則實際比例的計算方式是: **實際解析度 = 解析度/顯示比例。** ::: ## SDL的命名規律 以下的字首常見於SDL的函數,可以方便你記憶一些常用函數的功能和變數型態。 - Create: 物件的創造,傳入所需參數回傳物件指標。 - Destroy: 物件的消滅,傳入物件指標,void。 - Get: 取得某值,傳入物件指標回傳指定值。 - Set: 設定某值,傳入物件指標和參數,回傳0為正常,負數為錯誤,或是void函數。 - Is/Was/Has: 確認有無…,傳入物件指標,回傳bool。 ## SDL的眉角 1. **所有的東西都需要初始化!** 有一個函數負責初始化,我們不要管它怎麼運作,只要記得將這行放在所有SDL之前。 ```cpp //Initialize SDL if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) { printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() ); } ``` 各個library還有自己的初始化語法,我統一整理在這裡。使用時,若有未安裝的程式庫,記得把它的初始化從這裡刪掉,不然會有”呼叫未知函數”的問題。 :::warning ❓ 出現”…” was not declared in this scope就可能是呼叫了未知函數。 ::: </aside> ```cpp void InitializeSDL(){ //Initialize SDL if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 ) { printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() ); } //Initialize SDL_ttf if( TTF_Init() == -1 ) { printf( "SDL_ttf could not initialize! SDL_ttf Error: %s\n", TTF_GetError() ); } //Initialize SDL_image int imgFlags = IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF | IMG_INIT_WEBP | IMG_INIT_JXL | IMG_INIT_AVIF; if( !( IMG_Init( imgFlags ) & imgFlags )) { printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() ); } //Initialize SDL_mixer int mixFlags = MIX_INIT_FLAC | MIX_INIT_MOD | MIX_INIT_MP3 | MIX_INIT_OGG | MIX_INIT_MID | MIX_INIT_OPUS | MIX_INIT_WAVPACK; if( !( Mix_Init( mixFlags ) & mixFlags )) { printf("SDL_mix could not initialize! SDL_mixer Error: %s\n", Mix_GetError()); } //open audio devices if( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, 2048 ) < 0 ) { printf( "SDL_mixer could not initialize! SDL_mixer Error: %s\n", Mix_GetError() ); } //Initialize SDL_net if( SDLNet_Init() == -1 ) { printf( "SDL_net could not initialize! SDL_net Error: %s\n", SDLNet_GetError() ); } return; } ``` 2. 因為SDL是基於pointer去配置記憶體。**每個物件的創造都需要有對應的消滅(memory deallocate)**。使用上要注意document所寫的對應函數,否則會有很嚴重的memory leak。 :::warning ❓ 程式的記憶體在執行時不斷上升,很可能是因為某些用後即丟的物件沒有被消滅。 ::: 3. SDL的main()一定要用這個方式寫: ```cpp int main(int argc, char *argv[]){ return 0; } ``` 其他方式都不行!! 它的意義是可以接受console中輸入的指令,但用不到也得寫。 --- 了解基礎的運作模式以後,就可以開始學習創造與運用各種功能了!
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up