- 전체
- C/C++ 일반
- C/C++ 수학
- C/C++ 그래픽
- C/C++ 자료구조
- C/C++ 인공지능
- C/C++ 인터넷
- wxWidget
- GTK+
- UNIX or LINUX programming
- 리눅스 마스터 - 국가공인자격
- VC++/ MFC
- C#/CLI/.NET
- QT/기타UI
- Boost lib
- 오픈소스 C 분석자료
- MSA (마이크로서비스), Docker, kubernetes
- WSL(windows subsystem linux)
C/C++ 그래픽 [C/C++, graphics] SDL Tutorial Basics
2021.05.15 22:40
[C/C++, graphics] SDL Tutorial Basics
These tutorials are meant to teach someone with some experience using C++, or perhaps another programming language. If you have a hard time following certain ideas related to the code itself and not conceptual ideas (those relating to games), then I urge you to first read our tutorials that explain the C++ programming language. It's not vital to understand everything about C++, but every little bit will help later on.
In these tutorials we will be referncing to CodeBlocks as our IDE of choice, with gcc and mingw for compilation. If you wish to use another IDE and compiler that is up to you, but it may be harder to follow along if you have limited experience with linking libraries. If you wish to download CodeBlocks, you can do so for free at http://www.codeblocks.org (download the one including the mingw package). We recommend you use the stable version, unless you want to spend the extra time and use the nightly builds.
These tutorials will be heavily centered around SDL (Simple DirectMedia Layer), a 2D cross-platform graphics library. This library is going to allow us to draw fancy graphics to the screen, and do all sorts of fun stuff that allows us to make a game. You're going to need to download this library at http://www.libsdl.org; be sure to download the Mingw32 tar file under "Development Libraries" and "Win32" and the zip file under "Runtime Libraries" and "Win32." If you are using Visual Studio download the appropriate version instead of the Mingw32 file. Once downloaded, we recommend you put the .dll found in the zip in your system32 folder. This way whenever we open an SDL application it can find the dll file it needs.
Open the tar file now (the one that was listed under "Development Libraries") and decompress the contents to a folder (such as C:\SDL). Now, open up CodeBlocks so we can change some settings. Click "Settings" on the menu bar, and then click "Search Directories" tab. You'll need to add C:\SDL\include to the "Compiler" tab, and C:\SDL\lib to the "Linker" tab (change C:\SDL to wherever you decompressed the files to). Once done, click Okay.
Start a new "blank" project, calling it whatever you want. Save it some place. Click on "Project" on the menu bar, and then click on "Properties." A dialog will open; click on the "Project's build options..." button on the bottom right. Click on the "Linker Settings" tab and add the following to the list under "Link libraries":
mingw32
SDLmain
SDL
The order is important, so use the arrows to rearrange the list until it matches what is shown above. If you are having a little trouble figuring out what we are doing, we're simply "linking" code together, or, in other words, we're taking the SDL code and combining it with our own. We do this by using the include files to compile, and the lib files to link. And once done, our code is put together to make one application.
Click Ok twice, and you should be all set to go!
Let's create two new files called CApp.h, and CApp.cpp; these will serve as the core for our program. First, open CApp.h and add the following code, in here is where our tutorial will really begin:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#ifndef _CAPP_H_ #define _CAPP_H_ #include <SDL.h> class CApp { public : CApp(); int OnExecute(); }; #endif |
Now, open up CApp.cpp and add the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include "CApp.h" CApp::CApp() { } int CApp::OnExecute() { return 0; } int main( int argc, char * argv[]) { CApp theApp; return theApp.OnExecute(); } |
The CApp class is setting the stage for our entire program. Let me step aside to take special note of how games are typically setup. Most games consist of 5 functions that handle how the game processes. These processes are typically:
Initialize
This function handles all the loading of data, whether it be textures, maps, NPCs, or whatever.
Event
This function handles all input events from the mouse, keyboard, joysticks, or other devices.
Loop
This function handles all the data updates, such as a NPCs moving across the screen, decreasing your health bar, or whatever
Render
This function handles all the rendering of anything that shows up on the screen. It does NOT handle data manipulation, as this is what the Loop function is supposed to handle.
Cleanup
This function simply cleans up any resources loaded, and insures a peaceful quitting of the game.
It's important to understand that games are one gigantic loop. Within this loop we find events, update data, and render pictures. Thus, the basic structure could be thought of as:
1
2
3
4
5
6
7
8
9
|
Initialize(); while ( true ) { Events(); Loop(); Render(); } Cleanup(); |
Each iteration of the loop we do something with data, and render accordingly. Events are extra, as a means for the user to manipulate data as well. In that sense, Events aren't required to make a game, but are needed when you want the user to be able to manipulate data (such as move a NPC to the left).
Let's clarify this idea with an example. Say we have our Knight, the hero of the game. All we want to do is simply have him move around. If I press left, he goes left. We need to figure out how to do this within a loop. Firstly, we know we want to check for events (keyboard events). Since Events are a means to manipulate data, we also know we'll need some sort of variables to modify. Then we can use these variables to render our Knight appropriatly on the screen. We could have:
1
2
3
4
5
6
|
if (Key == LEFT) X--; if (Key == RIGHT) X++; if (Key == UP) Y--; if (Key == DOWN) Y++; //... somewhere else in our code ... RenderImage(KnightImage, X, Y); |
This works because each loop it checks if the key is LEFT, RIGHT, etc., and if so, we decrease or increase a variable. So, if our game is running at 30 frames per second and we press LEFT, then our guy would move to the left 30 pixels per second. If you don't understand the game loop, you soon will. Games need them to function correctly.
Going back to our conceptual code (the 5 functions), we can add these additional pages to our project:
CApp_OnInit.cpp CApp_OnEvent.cpp CApp_OnLoop.cpp CApp_OnRender.cpp CApp_OnCleanup.cpp
Go back to CApp.h, and add the following functions and variables:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#ifndef _CAPP_H_ #define _CAPP_H_ #include <SDL.h> class CApp { private : bool Running; public : CApp(); int OnExecute(); public : bool OnInit(); void OnEvent(SDL_Event* Event); void OnLoop(); void OnRender(); void OnCleanup(); }; #endif |
Go through each of the 5 files we just created and create the function themselves:
1
2
3
4
5
|
#include "CApp.h" bool CApp::OnInit() { return true ; } |
1
2
3
4
|
#include "CApp.h" void CApp::OnEvent(SDL_Event* Event) { } |
1
2
3
4
|
#include "CApp.h" void CApp::OnLoop() { } |
1
2
3
4
|
#include "CApp.h" void CApp::OnRender() { } |
1
2
3
4
|
#include "CApp.h" void CApp::OnCleanup() { } |
Now lets go back to our CApp.cpp code to link all of these functions together:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#include "CApp.h" CApp::CApp() { Running = true ; } int CApp::OnExecute() { if (OnInit() == false ) { return -1; } SDL_Event Event; while (Running) { while (SDL_PollEvent(&Event)) { OnEvent(&Event); } OnLoop(); OnRender(); } OnCleanup(); return 0; } int main( int argc, char * argv[]) { CApp theApp; return theApp.OnExecute(); } |
You'll notice some new variables, but let's look at what is happening first. First, we try to Initialize our game, if it fails we return -1 (an error code), thus closing our program. If everything is good, we continue on to the game loop. Within the game loop we use SDL_PollEvent to check for events, and pass them one at a time to OnEvent. Once done with Events, we go to OnLoop for move data around and what not, and then render our game. We repeat this indefinitly. If the user exits the game, we proceed to OnCleanup cleaning up any resources. Simple enough.
Now, lets look at SDL_Event and SDL_PollEvent. The first is a structure that holds information about events. The second is a function that will grab any events waiting in the queue. This queue can have any number of events, which is the reason why we have to loop through them. So, for example, lets say the user presses A and moves the mouse during the OnRender() function. SDL will detect this and put two events in the queue, one for a key press and one for a mouse move. We can grab this event from the queue by using the SDL_PollEvent, and then passing it to OnEvent to handle it accordingly. Once there are no more events in the queue, SDL_PollEvent will return false, thus exiting out of the Event queue loop.
The other variable added, Running, is our own. This is our exit out of the game loop. When this is set to false, it will end the program, and in turn exit the program. So, for example, if the user presses the Escape key we can set this variable to false, quitting the game.
You should be able to compile everything so far just fine, but you may notice you can't exit out. You'll probably have to use the task manager to end the program.
Now that everything is setup, let's start by creating the window our game will be drawn in. Jump over to CApp.h and add a SDL surface variable to the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
#ifndef _CAPP_H_ #define _CAPP_H_ #include <SDL.h> class CApp { private : bool Running; SDL_Surface* Surf_Display; public : CApp(); int OnExecute(); public : bool OnInit(); void OnEvent(SDL_Event* Event); void OnLoop(); void OnRender(); void OnCleanup(); }; #endif |
I suppose now would be a good time to explain exactly what a SDL Surface is. An SDL Surface is anything that can be drawn, or drawn to. Say we have a blank piece of paper, a pencil, and some stickers; this paper could be called our display "surface." We can draw to it, put stickers on it, or whatever. The stickers we have are also surfaces; we can draw on them and put other stickers on them as well. So, Surf_Display is simply our "piece of blank paper" that we will draw all our stuff on.
Now, lets jump on over to CApp_OnInit to actually create this surface:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#include "CApp.h" bool CApp::OnInit() { if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { return false ; } if ((Surf_Display = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL) { return false ; } return true ; } |
The first thing we need to do is start up SDL itself, so we can access its functions. We are telling SDL to Initialize everything it has; there are other parameters you can pass, but understanding them at this point is not important. The next function we use is SDL_SetVideoMode. This bad boy is what creates our window, and our surface. It takes 4 parameters: The width of the window, the height of the window, the bit resolution of the window (recommended to be 16 or 32), and then display flags. There are quite a few display flags, but the ones shown above are fine for now. The first flag tells SDL to use hardware memory for storing our images and such, and the second flag tells SDL to use double buffering (which is important if you don't want flickering on your screen). Another flag that may interest you now is SDL_FULLSCREEN, which makes the window go fullscreen.
Now that our display is setup, lets cleanup a little bit to make sure everything works smoothly. Open up CApp_OnCleanup.cpp and add the following:
1
2
3
4
5
|
#include "CApp.h" void CApp::OnCleanup() { SDL_Quit(); } |
We basically quit out of SDL. You should take note that in this function is where you would free other surfaces as well. This keeps all your code centralized to the function its performing.
To keep things tidy, lets also set the Surf_Display pointer to NULL on the class constructor. Open up CApp.cpp and add the following:
1
2
3
4
5
|
CApp::CApp() { Surf_Display = NULL; Running = true ; } |
Try compiling your code, and watching it work. You should have a nice blank window popup. You'll notice you can't close it though, so you'll need to use the task manager to do so.
Now that we have a window all setup, we're going to need a way to close it. Open up the CApp_OnEvent.cpp file, add the following:
1
2
3
4
5
6
7
|
#include "CApp.h" void CApp::OnEvent(SDL_Event* Event) { if (Event->type == SDL_QUIT) { Running = false ; } } |
The SDL event structure is broken down into types. These types can range from keypresses, to mouse movements; what we simply are doing here is checking the event type. The type above we are looking for is the request to close the window (i.e., when the user clicks the X button). If that event happens to take place, we set Running to false, thus ending our program. Simple enough. We'll look more into events in a later lesson.
Now, you should everything setup, and a good structure to work with later. It may be a good idea to take this project and turn it into an "SDL template" within CodeBlocks. I won't go over how to do that, but feel free to Google it.
Once you have a good idea what's going on with the code we covered in this lesson, jump over to the next game tutorial lesson to learn more about SDL surfaces.
[출처] http://www.sdltutorials.com/sdl-tutorial-basics
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.