# 2020q3 Homework5 (render) contributed by < `blueskyson` > ###### tags: `linux2020` ## 目錄 [TOC] ## Trace Code 在 `main.cpp` 的 `main` 中,首先使用 `SDL_Init(SDL_INIT_VIDEO)` 初始化視訊媒體 ```cpp=1 int main(int argc, char *args[]) { if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError()); } else { ``` 接下來初始化遊戲視窗 `SDL_Window` ,以下是 `SDL_CreateWindow` 的參數說明: - **title** The title of the window, in UTF-8 encoding. - **x** The x position of the window, `::SDL_WINDOWPOS_CENTERED`, or `::SDL_WINDOWPOS_UNDEFINED`. - **y** The y position of the window, `::SDL_WINDOWPOS_CENTERED`, or `::SDL_WINDOWPOS_UNDEFINED`. - **w** The width of the window, in screen coordinates. - **h** The height of the window, in screen coordinates. - **flags** The flags for the window, a mask of any of the following: `::SDL_WINDOW_FULLSCREEN`, `::SDL_WINDOW_OPENGL`, `::SDL_WINDOW_HIDDEN`, `::SDL_WINDOW_BORDERLESS`, `::SDL_WINDOW_RESIZABLE`, `::SDL_WINDOW_MAXIMIZED`, `::SDL_WINDOW_MINIMIZED`,`::SDL_WINDOW_INPUT_GRABBED`, `::SDL_WINDOW_ALLOW_HIGHDPI`, `::SDL_WINDOW_VULKAN` ```cpp=6 /* 在 raycaster.h 中有宣告要傳入 SDL_CreateWindow 的參數 * #define SCREEN_WIDTH (uint16_t) 320 * #define SCREEN_HEIGHT (uint16_t) 256 * #define SCREEN_SCALE 2 */ SDL_Window *sdlWindow = SDL_CreateWindow("RayCaster [fixed-point vs. floating-point]", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_SCALE * (SCREEN_WIDTH * 2 + 1), SCREEN_SCALE * SCREEN_HEIGHT, SDL_WINDOW_SHOWN); ``` 確認 `SDL_Window` 是否成功初始化 ```cpp=16 if (sdlWindow == NULL) { printf("Window could not be created! SDL_Error: %s\n", SDL_GetError()); } else { ``` 接下來初始化遊戲中會用到的物件,首先初始化 `Game` 物件, `Game` 物件中包含 - `float playerX, playerY, playerA;` 代表玩家的位置和視角 - `void Move(int m, int r, float seconds);` 用來控制玩家移動 ```cpp=20 Game game; ``` 初始化 `RayCasterFloat` , `RayCasterFloat` 物件有計算光線投射的方法 初始化 `RayCasterFloat` 物件,搭配 `RayCasterFloat` 可以完成浮點數算繪 目前還不知道 `floatBuffer` 的用途 ```cpp=21 RayCasterFloat floatCaster; Renderer floatRenderer(&floatCaster); uint32_t floatBuffer[SCREEN_WIDTH * SCREEN_HEIGHT]; ``` 跟 21 到 23 行類似,初始化定點數的算繪 ```cpp=24 RayCasterFixed fixedCaster; Renderer fixedRenderer(&fixedCaster); uint32_t fixedBuffer[SCREEN_WIDTH * SCREEN_HEIGHT]; ``` 初始化以下變數 ```cpp=27 int moveDirection = 0; // 玩家的移動方向 int rotateDirection = 0; // 玩家的轉動方向 bool isExiting = false; // 是否已離開遊戲 /* 根據 SDL 解析度所得到的刷新頻率 */ const static auto tickFrequency = SDL_GetPerformanceFrequency(); /* 獲得目前 SDL Counter 的值 */ auto tickCounter = SDL_GetPerformanceCounter(); SDL_Event event; // 儲存目前的 key code /* 用來接收 fixedTexture 和 floatTexture 的值 * 並且暫存下一個 frame 要繪製的資訊 */ SDL_Renderer *sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED); /* 用來接收 fixedBuffer 的值,以 SDL_Texture 型態表示 */ SDL_Texture *fixedTexture = SDL_CreateTexture( sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); /* 用來接收 floatBuffer 的值,以 SDL_Texture 型態表示 */ SDL_Texture *floatTexture = SDL_CreateTexture( sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT); ``` 接下來進入 while 迴圈,玩家按下 Esc 或關閉遊戲視窗才會跳出迴圈 ```cpp=50 while (!isExiting) { floatRenderer.TraceFrame(&game, floatBuffer); fixedRenderer.TraceFrame(&game, fixedBuffer); DrawBuffer(sdlRenderer, fixedTexture, fixedBuffer, 0); DrawBuffer(sdlRenderer, floatTexture, floatBuffer, SCREEN_WIDTH + 1); SDL_RenderPresent(sdlRenderer); if (SDL_PollEvent(&event)) { isExiting = ProcessEvent(event, &moveDirection, &rotateDirection); } const auto nextCounter = SDL_GetPerformanceCounter(); const auto seconds = (nextCounter - tickCounter) / static_cast<float>(tickFrequency); tickCounter = nextCounter; game.Move(moveDirection, rotateDirection, seconds); } SDL_DestroyTexture(floatTexture); SDL_DestroyTexture(fixedTexture); SDL_DestroyRenderer(sdlRenderer); SDL_DestroyWindow(sdlWindow); } } SDL_Quit(); return 0; } ``` ## 待續