Привет. В этой статье попробуем создать что-нибудь маленькое и полезное. У шахматистов есть упражнение. Тренер задаёт вслух координату любого поля, ученик должен мысленно представить доску и ответить, какой у поля цвет. Примерно такое и попробуем реализовать, но с изменяемой сложностью, чтоб было интереснее.
Концепция программы:
Из квадратиков рисуется шахматная доска (стандартными функциями). Снизу буквы, слева цифры (рендерятся из шрифта). Текст задания и очки чуть поменьше, координаты задаваемой клетки чуть побольше. Две кнопки для ответов. Должны отлавливаться координаты кликов мышки внутри этих кнопок (стандартная функция с условиями), и обрабатываться соответствующим образом.
Самая фишка программы - сначала будут исчезать цифры, затем буквы, а затем и вовсе поля будут исчезать. Чтоб дойти до 100 очков, нужно отвечать только по памяти. При ошибке очки откатываются до ближайшего круглого значения. При ошибке на круглом числе очки уменьшаются до предыдущего круглого.
Сначала сделаем окно, нарисуем доску, и нарисуем две кнопки. Но в отличии от предыдущей статьи, окно должно показываться и перерисовываться до тех пор, пока человек сам не выйдет из программы.
В третьем уроке - http://lazyfoo.net/tutorials/S... /index.php - описывается использование событий SDL_Event. Кратко изложу основное.
Создаётся переменная "флаг". Как только он становится единицей, программа закончит работать. Пока флаг равен нулю, программа будет бесконечно выполняться в цикле.
Создается особая переменная для обработки событий. Когда человек нажимает на клавиатуру, двигает мышкой, жмёт на ждойстик, все события от операционной системы поступают в "очередь". Программа должна уметь обрабатывать эти события.
Создаём цикл для долгого выполнения программы, пока флаг не станет равен нулю.
Теперь этот цикл будет "главным циклом". Внутри него будут происходить все основные действия. Внутрь нам нужно добавить цикл обработки событий, функции проверки разных условий для игры, и функции рисования. Они будут повторяться бесконечно.
Чтоб отлавливать клики мышки, нажатия кнопок, джойстика и других, нужно сделать обработчик событий. Операционная система посылает все случившиеся события в программу. Создаем цикл, который проверит из очереди каждое событие, пока очередь не кончится. Если программа увидит событие SDL_QUIT (пользователь нажал на крестик закрытия программы), то флаг выхода станет равен единице, и программа выйдет из главного цикла на функции завершения работы.
| C | 1
2
3
4
| while( SDL_PollEvent( &e ) != 0 )
{
if( e.type == SDL_QUIT ) quit = 1;
} |
|
После обработки событий будут располагаться функции для проверки правильности ответа игрока. Сделаем попозже.
И в конце главного цикла мы сделаем отрисовку квадратиков, букв и цифр. После всех отрисовок не забываем вывести новое изображение на окно.
| C | 1
| SDL_UpdateWindowSurface( gWindow ); |
|
Попробуем накидать скелет программы для шахматной доски. Обратите внимание, что я объявление функций сделал сверху, а их описание убрал в низ кода, чтоб не мешалось. Так же убрал функции загрузки изображений.
Кликните здесь для просмотра всего текста
| C | 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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
| #include <SDL.h>
#include <stdio.h>
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
int init();
void close();
SDL_Window* gWindow = NULL;
SDL_Surface* gScreenSurface = NULL;
int main( int argc, char* args[] )
{
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
int quit = 0; // флаг для основного цикла
SDL_Event e; // указатель на очередь событий
while( !quit ) // пока флаг равен нулю
{
while( SDL_PollEvent( &e ) != 0 ) // пока есть события
{
if( e.type == SDL_QUIT ) // нажат крестик закрытия окна или alt+f4
{
quit = 1;
}
}
// обработка игровых условий
// рисование игровой области
// обновляем поверхность
SDL_UpdateWindowSurface( gWindow );
} // в этом месте программа выйдет из главного цикла, когда флаг станет равен 1.
}
close(); // освобождаем память и закрываем sdl
return 0;
}
int init()
{
//Initialization flag
int success = 1;
//Initialize SDL
if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
{
printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
success = 0;
}
else
{
//Create window
gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
success = 0;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface( gWindow );
}
}
return success;
}
void close()
{
//Destroy window
SDL_DestroyWindow( gWindow );
gWindow = NULL;
//Quit SDL subsystems
SDL_Quit();
} |
|
Программа компилируется, запускается, видно чёрное окно (мы же ещё ни чего не рисовали) и успешно закрывается по крестику.
################################
Давайте попробуем нарисовать слева шахматную доску, а справа квадратики для ответов.
Сначала заливаем всё окно белым цветом
| C | 1
| SDL_FillRect( gScreenSurface, NULL, SDL_MapRGB( gScreenSurface->format, 0xff, 0xff, 0xff ) ); |
|
Затем создаём вложенные циклы для отрисовки квадратиков полей. Чтобы рисовать каждое поле отдельно, нужно для каждого определить положение и размер. Для этого вводим новую структуру SDL_Rect , в которой описывается координата x (смещение слева на право), координата y (сверху вниз), ширина прямоугольника w, высота прямоугольника h.
| C | 1
2
3
| SDL_Rect field_rect; // прямоугольник для клеток
field_rect.h = FIELD_SIZE;
field_rect.w = FIELD_SIZE; |
|
Присваиваем значения ширины и высоты из #define в самом начале кода, по 45. Смещения будут зависеть от i j.
| C | 1
2
| field_rect.x = 20 + FIELD_SIZE + i*(FIELD_SIZE );
field_rect.y = FIELD_SIZE + j*(FIELD_SIZE ); |
|
Сейчас надо понять, какая клетка каким цветом должна закрашиваться. Для этого создадим простой двумерный массив для доски и обозначим цифрой 1 светлые поля, цифрой 0 тёмные. Теперь просто нужно проверить, если значение в нужном месте 1 значит красим светлым. Иначе чёрным.
| C | 1
2
3
4
5
6
7
8
| if (board[i][j] == 1)
{
SDL_FillRect( gScreenSurface, &field_rect, SDL_MapRGB( gScreenSurface->format, 0xff, 0xce, 0x9e));
}
else
{
SDL_FillRect( gScreenSurface, &field_rect, SDL_MapRGB( gScreenSurface->format, 0xd1, 0x8b, 0x47));
} |
|
Ещё предварительно нужно создать структуру для квадратов ответов. Отдельно для тёмного и светлого.
| C | 1
2
3
4
5
6
7
8
9
10
11
| SDL_Rect dark_rect; // ответ темный квадрат
dark_rect.x = 438;
dark_rect.y = 250;
dark_rect.w = 90;
dark_rect.h = 90;
SDL_Rect light_rect; // ответ светлый квадрат
light_rect.x = 540;
light_rect.y = 250;
light_rect.w = 90;
light_rect.h = 90; |
|
Функции для рисования квадратов ответов:
| C | 1
2
| SDL_FillRect( gScreenSurface, &light_rect, SDL_MapRGB( gScreenSurface->format, 0xff, 0xce, 0x9e));
SDL_FillRect( gScreenSurface, &dark_rect, SDL_MapRGB( gScreenSurface->format, 0xd1, 0x8b, 0x47)); |
|
Можно ещё поставить обработку события от нажатия клавиши Esc, чтоб выходить из программы.
| C | 1
2
3
4
5
6
7
| if ( e.type == SDL_KEYDOWN ) // если нажата клавиатура
{
if (e.key.keysym.sym == SDLK_ESCAPE) // выход при Esc
{
quit = 1;
}
} |
|
Вот теперь начинает вырисовываться каркас программы. Текущий код с начала программы до конца main функции:
Кликните здесь для просмотра всего текста
| C | 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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
| #include <SDL.h>
#include <stdio.h>
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
#define FIELD_SIZE 45
int init();
void close();
SDL_Window* gWindow = NULL;
SDL_Surface* gScreenSurface = NULL;
int main( int argc, char* args[] )
{
if( !init() )
{
printf( "Failed to initialize!\n" );
}
else
{
int quit = 0; // флаг для основного цикла
SDL_Event e; // указатель на очередь событий
int i,j;
SDL_Rect field_rect; // прямоугольник для клеток
field_rect.h = FIELD_SIZE;
field_rect.w = FIELD_SIZE;
SDL_Rect dark_rect; // ответ темный квадрат
dark_rect.x = 438;
dark_rect.y = 250;
dark_rect.w = 90;
dark_rect.h = 90;
SDL_Rect light_rect; // ответ светлый квадрат
light_rect.x = 540;
light_rect.y = 250;
light_rect.w = 90;
light_rect.h = 90;
int board[8][8] = { {1,0,1,0,1,0,1,0}, // 1 светлый, 0 тёмный
{0,1,0,1,0,1,0,1},
{1,0,1,0,1,0,1,0},
{0,1,0,1,0,1,0,1},
{1,0,1,0,1,0,1,0},
{0,1,0,1,0,1,0,1},
{1,0,1,0,1,0,1,0},
{0,1,0,1,0,1,0,1}
};
while( !quit ) // пока флаг равен нулю
{
while( SDL_PollEvent( &e ) != 0 ) // пока есть события
{
if( e.type == SDL_QUIT ) // нажат крестик закрытия окна или alt+f4
{
quit = 1;
}
else if ( e.type == SDL_KEYDOWN ) // если нажата клавиатура
{
if (e.key.keysym.sym == SDLK_ESCAPE) // выход при Esc
{
quit = 1;
}
}
}
// обработка игровых условий
// РИСОВАНИЕ
// очищаем экран
SDL_FillRect( gScreenSurface, NULL, SDL_MapRGB( gScreenSurface->format, 0xff, 0xff, 0xff ) );
// перебираем по циклам шахматную доску
for (j=0; j<8; j++ )
{
for ( i=0; i<8; i++)
{
// устанавливаем в каком регионе будем рисовать текущую клетку
field_rect.x = 20 + FIELD_SIZE + i*(FIELD_SIZE );
field_rect.y = FIELD_SIZE + j*(FIELD_SIZE );
if (board[i][j] == 1)
{
SDL_FillRect( gScreenSurface, &field_rect, SDL_MapRGB( gScreenSurface->format, 0xff, 0xce, 0x9e));
}
else
{
SDL_FillRect( gScreenSurface, &field_rect, SDL_MapRGB( gScreenSurface->format, 0xd1, 0x8b, 0x47));
}
}
}
// рисуем квадратики для ответов
SDL_FillRect( gScreenSurface, &light_rect, SDL_MapRGB( gScreenSurface->format, 0xff, 0xce, 0x9e));
SDL_FillRect( gScreenSurface, &dark_rect, SDL_MapRGB( gScreenSurface->format, 0xd1, 0x8b, 0x47));
// обновляем поверхность
SDL_UpdateWindowSurface( gWindow );
} // в этом месте программа выйдет из главного цикла, когда флаг станет равен 1.
}
close(); // освобождаем память и закрываем sdl
return 0;
} |
|
В следующей статье мы постараемся загрузить шрифт, сделать разметку доски, и прикрутить логику заданий/ответов.
|