More cleanup!

Now that Christmas is over with I can get back to some work (play?) on my SDL experience, todays order of business is splitting the code from the main.cpp file into several header and source files to help make everything more tidy and to also remind myself how this all works.

 

First a few introductions:

Header files declare classes and functions without defining them and are suffixed with .h, for example: header.h.

Source files define classes and functions and include header files with the #include directive, they are suffixed with .cpp, for example: source.cpp

Include Guards are used in header files to prevent the accidental inclusion of a header file twice, which will cause errors. Include guards look like this:

[pastacode lang=”cpp” manual=”%23ifndef%20HEADER_H%0A%23define%20HEADER_H%0A%0A%3Cdeclarations%20goes%20here%3E%0A%0A%23endif” message=”” highlight=”” provider=”manual”/]

If we break that down, all it’s saying is “If HEADER_H has been defined, ignore this file, otherwise define it and include all this code”. It effectively prevents us from including something multiple times.

This brings us to the #include directive. When performing an include with the #include directive we are literally asking the compiler to insert the contents of the file specified at that point in the code during compilation, with that in mind cutting out our vector class is pretty straight forward.


Getting Ahead(er)

First we take the declaration and put it into a header file:

[pastacode lang=”cpp” manual=”%23ifndef%20VEC2_H%0A%23define%20VEC2_H%0A%0A%23include%20%3Cmath.h%3E%0A%0Aclass%20vec2%0A%7B%0A%20%20%20%20float%20x%3B%0A%20%20%20%20float%20y%3B%0A%0Apublic%3A%0A%20%20%20%20float%20getX()%20%7Breturn%20x%3B%7D%3B%0A%20%20%20%20float%20getY()%20%7Breturn%20y%3B%7D%3B%0A%20%20%20%20void%20setX(float%20i)%20%7Bx%20%3D%20i%20%3B%7D%3B%0A%20%20%20%20void%20setY(float%20i)%20%7By%20%3D%20i%20%3B%7D%3B%0A%0A%20%20%20%20void%20add(vec2%20vec)%3B%0A%20%20%20%20void%20mult(int%20scaler)%3B%0A%20%20%20%20void%20sub(vec2%20vec)%3B%0A%20%20%20%20float%20getMag()%20%7Breturn%20sqrt(%20(x*x)%20%2B%20(y*y)%20)%3B%7D%3B%0A%20%20%20%20void%20setMag(float%20mag)%3B%0A%20%20%20%20void%20normalize()%3B%0A%7D%3B%0A%0A%23endif” message=”vec2.h” highlight=”” provider=”manual”/]

Note that we included the math.h library into this header file, this is because, while we don’t normally define things in header files, GetMag() returns a simple square root that is coded directly into it’s declaration.

 

Now we take the definition and put that into a .cpp file and include the vec2.h file:

[pastacode lang=”cpp” manual=”%23include%20%22vec2.h%22%0A%0Avoid%20vec2%3A%3Aadd(vec2%20vec)%0A%7B%0A%20%20%20%20this-%3Ex%20%2B%3D%20vec.x%3B%0A%20%20%20%20this-%3Ey%20%2B%3D%20vec.y%3B%0A%0A%7D%0A%0Avoid%20vec2%3A%3Amult(int%20scaler)%0A%7B%0A%20%20%20%20this-%3Ex%20*%3D%20scaler%3B%0A%20%20%20%20this-%3Ey%20*%3D%20scaler%3B%0A%7D%0A%0Avoid%20vec2%3A%3Asub(vec2%20vec)%0A%7B%0A%20%20%20%20this-%3Ex%20-%3D%20vec.x%3B%0A%20%20%20%20this-%3Ey%20-%3D%20vec.y%3B%0A%7D%0A%0Avoid%20vec2%3A%3Anormalize()%0A%7B%0A%20%20%20%20float%20mag%20%3D%20this-%3EgetMag()%3B%0A%20%20%20%20this-%3Ex%20%3D%20this-%3Ex%20%2F%20mag%3B%0A%20%20%20%20this-%3Ey%20%3D%20this-%3Ey%20%2F%20mag%3B%0A%7D%0A%0Avoid%20vec2%3A%3AsetMag(float%20mag)%0A%7B%0A%20%20%20%20this-%3Enormalize()%3B%0A%20%20%20%20this-%3Emult(mag)%3B%0A%7D%0A” message=”vec2.cpp” highlight=”” provider=”manual”/]

 

Finally we modify our main.cpp file to include the new header and remove the old implementation:

[pastacode lang=”cpp” manual=”%23include%20%3CSDL2%2FSDL.h%3E%0A%23include%20%3CSDL2%2FSDL_image.h%3E%0A%23include%20%3Ciostream%3E%0A%23include%20%3Cstring%3E%0A%23include%20%22vec2.h%22″ message=”main.cpp” highlight=”” provider=”manual”/]

Note that here we have omitted the math.h library, as it is included in the vec2.h header and is only required there so far.

A quick recompile and we can see that out code is still working as it was before, except now the main.cpp file is a little more straightforward to read and understand. You should always strive for readable, comprehensible code, your code should not need extensive commenting to be readable, if it does, it may be time for a refactor! To make this process easier, it’s generally good practice to create multiple files immediately and work that way, rather than writing everything into main and then trying to sort it out later on, a time will come when separating the code is virtually impossible!


Even More Cleanup!

Now we can remove some of the helper functions that we created to make working with SDL easier and put them into their own files.

[pastacode lang=”cpp” manual=”%23ifndef%20SDL_HELPERS_H%0A%23define%20SDL_HELPERS_H%0A%0A%23include%20%3CSDL2%2FSDL.h%3E%0A%23include%20%3CSDL2%2FSDL_image.h%3E%0A%23include%20%3Ciostream%3E%0A%0Avoid%20logSDLError(std%3A%3Aostream%20%26os%2C%20const%20std%3A%3Astring%20%26msg)%3B%0A%0Avoid%20renderTexture(SDL_Texture%20*texture%2C%20SDL_Renderer%20*renderer%2C%20int%20x%2C%20int%20y)%3B%0Avoid%20renderTexture(SDL_Texture%20*texture%2C%20SDL_Renderer%20*renderer%2C%20int%20x%2C%20int%20y%2C%20int%20w%2C%20int%20h)%3B%0A%0A%23endif%20%2F%2F%20SDL_HELPERS_H” message=”sdl_helpers.h” highlight=”” provider=”manual”/]

We had to include iostream here as it is used in the declaration of logSDLError and because these helper functions are for SDL, it makes sense that we need to include the headers here.

 

And the declarations:

[pastacode lang=”cpp” manual=”%23include%20%22sdl_helpers.h%22%0A%0Avoid%20logSDLError(std%3A%3Aostream%20%26os%2C%20const%20std%3A%3Astring%20%26msg)%0A%7B%0A%20%20%20%20os%20%3C%3C%20msg%20%3C%3C%20%22%20Error%3A%20%22%20%3C%3C%20SDL_GetError()%20%3C%3C%20std%3A%3Aendl%3B%0A%7D%0A%0ASDL_Texture*%20loadTexture(const%20std%3A%3Astring%20%26path%2C%20SDL_Renderer%20*renderer)%0A%7B%0A%20%20%20%20SDL_Texture%20*texture%20%3D%20IMG_LoadTexture(renderer%2C%20path.c_str())%3B%0A%20%20%20%20if%20(texture%20%3D%3D%20nullptr)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20logSDLError(std%3A%3Acout%2C%20%22IMG_LoadTexture%22)%3B%0A%20%20%20%20%7D%0A%20%20%20%20return%20texture%3B%0A%7D%0A%0Avoid%20renderTexture(SDL_Texture%20*texture%2C%20SDL_Renderer%20*renderer%2C%20int%20x%2C%20int%20y)%0A%7B%0A%20%20%20%20int%20w%2C%20h%3B%0A%20%20%20%20SDL_QueryTexture(texture%2C%20NULL%2C%20NULL%2C%20%26w%2C%20%26h)%3B%0A%20%20%20%20renderTexture(texture%2C%20renderer%2C%20x%2C%20y%2C%20w%2C%20h)%3B%0A%7D%0A%0Avoid%20renderTexture(SDL_Texture%20*texture%2C%20SDL_Renderer%20*renderer%2C%20int%20x%2C%20int%20y%2C%20int%20w%2C%20int%20h)%0A%7B%0A%20%20%20%20SDL_Rect%20dst%3B%0A%20%20%20%20dst.x%20%3D%20x%3B%0A%20%20%20%20dst.y%20%3D%20y%3B%0A%20%20%20%20dst.w%20%3D%20w%3B%0A%20%20%20%20dst.h%20%3D%20h%3B%0A%0A%20%20%20%20SDL_RenderCopy(renderer%2C%20texture%2C%20NULL%2C%20%26dst)%3B%0A%7D%0A” message=”sdl_helpers.cpp” highlight=”” provider=”manual”/]

 

We include the new header in main and clear out the old functions:

[pastacode lang=”cpp” manual=”%23include%20%3CSDL2%2FSDL.h%3E%0A%23include%20%3CSDL2%2FSDL_image.h%3E%0A%23include%20%3Ciostream%3E%0A%23include%20%3Cstring%3E%0A%23include%20%22sdl_helpers.h%22%0A%23include%20%22vec2.h%22%0A%0Aconst%20int%20SCREEN_WIDTH%20%3D%20640%3B%0Aconst%20int%20SCREEN_HEIGHT%20%3D%20480%3B%0A%0A%0ASDL_Texture*%20loadTexture(const%20std%3A%3Astring%20%26path%2C%20SDL_Renderer%20*renderer)%3B%0A%0A%0Aint%20main(int%20argc%2C%20char%20**argv)%0A%7B%0A%20%20%20%20if%20(SDL_Init(SDL_INIT_VIDEO)%20!%3D0)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20logSDLError(std%3A%3Acout%2C%20%22SDL%20Init%22)%3B%0A%20%20%20%20%20%20%20%20return%201%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20SDL_Window%20*window%20%3D%20SDL_CreateWindow(%22Hello%20World%22%2C%20100%2C%20100%2C%20640%2C%20480%2C%20SDL_WINDOW_SHOWN)%3B%0A%20%20%20%20if%20(window%20%3D%3D%20nullptr)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20logSDLError(std%3A%3Acout%2C%20%22SDL_CreateWindow%22)%3B%0A%20%20%20%20%20%20%20%20SDL_Quit()%3B%0A%20%20%20%20%20%20%20%20return%201%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20SDL_Renderer%20*renderer%20%3D%20SDL_CreateRenderer(window%2C%20-1%2C%20SDL_RENDERER_ACCELERATED%20%7C%20SDL_RENDERER_PRESENTVSYNC)%3B%0A%20%20%20%20if%20(renderer%20%3D%3D%20nullptr)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20SDL_DestroyWindow(window)%3B%0A%20%20%20%20%20%20%20%20logSDLError(std%3A%3Acout%2C%20%22SDL_CreateRenderer%22)%3B%0A%20%20%20%20%20%20%20%20SDL_Quit()%3B%0A%20%20%20%20%20%20%20%20return%201%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(%20(IMG_Init(IMG_INIT_PNG)%20%26%20IMG_INIT_PNG)%20!%3D%20IMG_INIT_PNG)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20logSDLError(std%3A%3Acout%2C%20%22IMG_init%22)%3B%0A%20%20%20%20%20%20%20%20SDL_Quit()%3B%0A%20%20%20%20%20%20%20%20return%201%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20SDL_Texture%20*background%20%3D%20loadTexture(%22Images%2Fbackground.png%22%2C%20renderer)%3B%0A%20%20%20%20SDL_Texture%20*image%20%3D%20loadTexture(%22Images%2Fimage.png%22%2Crenderer)%3B%0A%20%20%20%20if(background%20%3D%3D%20nullptr%20%7C%7C%20image%20%3D%3D%20nullptr)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20logSDLError(std%3A%3Acout%2C%20%22loadTexture%22)%3B%0A%20%20%20%20%20%20%20%20SDL_DestroyTexture(background)%3B%0A%20%20%20%20%20%20%20%20SDL_DestroyTexture(image)%3B%0A%20%20%20%20%20%20%20%20SDL_DestroyRenderer(renderer)%3B%0A%20%20%20%20%20%20%20%20SDL_DestroyWindow(window)%3B%0A%20%20%20%20%20%20%20%20SDL_Quit()%3B%0A%20%20%20%20%20%20%20%20return%201%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20SDL_RenderClear(renderer)%3B%0A%0A%20%20%20%20int%20scaler%20%3D%203%3B%0A%0A%20%20%20%20int%20bW%2C%20bH%3B%0A%20%20%20%20SDL_QueryTexture(background%2CNULL%2CNULL%2C%26bW%2C%20%26bH)%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20SCREEN_HEIGHT%3B%20i%20%3D%20i%20%2B%20bH%20%2F%20scaler)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20for%20(int%20j%20%3D%200%3B%20j%20%3C%20SCREEN_WIDTH%3B%20j%20%3D%20j%20%2B%20bW%20%2F%20scaler)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20renderTexture(background%2C%20renderer%2C%20j%2C%20i%2C%20bW%20%2F%20scaler%2C%20bH%20%2F%20scaler)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20int%20iW%2C%20iH%3B%0A%20%20%20%20SDL_QueryTexture(image%2C%20NULL%2C%20NULL%2C%20%26iW%2C%20%26iH)%3B%0A%20%20%20%20renderTexture(image%2C%20renderer%2C%20SCREEN_WIDTH%2F2%20-%20iW%2F2%2C%20SCREEN_HEIGHT%2F2%20-%20iH%2F2)%3B%0A%0A%20%20%20%20SDL_RenderPresent(renderer)%3B%0A%20%20%20%20SDL_Delay(2000)%3B%0A%0A%20%20%20%20SDL_DestroyTexture(background)%3B%0A%20%20%20%20SDL_DestroyTexture(image)%3B%0A%20%20%20%20SDL_DestroyRenderer(renderer)%3B%0A%20%20%20%20SDL_DestroyWindow(window)%3B%0A%20%20%20%20SDL_Quit()%3B%0A%0A%20%20%20%20return%200%3B%0A%7D%0A” message=”main.cpp” highlight=”” provider=”manual”/]

And now our main.cpp is down to 85 lines, much more manageable than what we had before, and if we need to make changes to a function, we can easily tell where to find it!

 

In the next installment we will be setting up an event handler and a game loop which will pave the way to getting some items moving around on the screen!

Leave a Reply

Your email address will not be published.