Среда, 15.05.2024, 23:37
Personal dimanche13 site
Главная | Регистрация | Вход Приветствую Вас Гость | RSS
Категории каталога
Мои статьи [22]
BlitzMax [17]
раздел содержит статьи относящиеся к языку программирования BlitzMax
SDL [9]
раздел содержит статьи на тему SDL
Code::Blocks [3]
в этом разделе рассказывается как прикрутить движок к интегрированной среде разработки(IDE) Code::Blocks
Форма входа
Поиск
Друзья сайта
Главная » Статьи » SDL

Основы SDL (часть№2 вывод текста)

Введение.

Ага, окошко мы сделали. (Да! мы сделали это! ведь Вы его сделали?) И надо сказать, что это было совсем не сложно. Теперь нам надо сделать нечто полезное в нем. Я пробежался по многим туторам СДЛ и нашел в них, что в большинстве своем вторая попытка сделать что-то на СДЛ, сводилась к рисованию спрайта или пикселя. Я же решил поступить несколько иначе. О загрузке графики и рисовании спрайтов мы поговорим в третьем уроке, это от нас никуда не убежит. А рисование пикселя я и вовсе решил опустить, мне кажется что начинать изучение какого-либо движка или библиотеки с такого старомодного метода, как рисование пикселя это знаете ли, моветон. Ничего полезно это вам не даст, а голову порядком замутит. Да и не припомню я чтобы были какие-нить игры с пикселями. Впрочем, если вам эта тема всеже интересна, то в конце статьи есть ссылки на подобные туторы. 

Задачи.

Тем временем мы приступим к нашему второму уроку. В нем я расскажу как выводить текст на экран. Ранее я говорил, что сама библиотека имеет ряд функций облегчающих работу с графикой, устройствами ввода, таймерами и др. причем эти вещи совершенно не привязаны к какой-то конкретной системе, что в принципе ведет к легкой переносимости программ под разные платформы. Тем не менее, некоторые полезные функции в СДЛ не представлены, такие как звук, загрузка картинок, сеть... Но не стоит расстраиваться, потому как сама библиотека задумывалась таким образом, что ее без труда можно расширить под ваши нужды и для этого создан целый ряд дополнительных модулей. Например, для загрузки картинок разных форматов можно подключить SDL_Image, для музыки SDL_Mixer, сеть SDL_net , а шрифты SDL_Font.  

Подключаем.

Давайте подключим в нашу программу шрифты и напечатаем на экране, что-нибудь такое, ммм эдакое: чтоб ласкало слух и радовало глаз. Например, всем известную фразу: "To be or not to be." Ну вот, мне нравится, блин. Вы можете написать что-нить другое. Но сначала займемся выводом классики. Для этого нам необходимо 

скачать эту библиотеку. Она как и все находится на офф.сайте СДЛ в разделе projetcts вот ссылка: 

http://www.libsdl.org/projects/SDL_ttf/

Переходим и скачиваем этот вот файл:

devel - в названии файла говорит о том, что этот архив для тех кто будет, что-то с этим разрабатывать(development). И в дальнейшем, если вам будут нужны какие-нибудь библиотеки для подключения к проекту, надо будет качать их devel-версии. В этих архивах находятся 4 вещи:

  1. папка include - хидеры (заголовки)
  2. папка lib - где лежит .lib
  3. там же dll - необходимые динамические библиотеки
  4. лицензионные соглашения этой библиотеки

Надо разобраться что с этим добром делать. Если вы уже знаете это, то пропустите абзац, остальные - за мной. 

ОК, мы создали новый СДЛ проект, теперь нам надо "приютить" файлы, которые находились в архиве SDL_ttf. Для этого кидаем SDL_ttf.h в папку include нашей SDL. А файл SDL_ttf.lib в папку lib. Дальше я буду приводить скриншоты, как это выглядит у меня :


Потом первым делом включаем заголовочный файл нашей библиотеки вслед за основным хидером SDL (SDL.h)

.....

#include <SDL.h>
#include <SDL_TTF.h>
.....

Затем идем в опции линковщика проекта(Project->Build options...->Linker Settings) и прицепляем наш lib-файл. У меня так:


И последним делом нам надо разместить dll-ки из нашего архива(zlib1.dll, SDL_ttf.dll, libfreetype-6.dll) . Я уже говорил о том куда их класть, но повторюсь(в последний раз), что их можно положить в:

  1. папку вашего проекта, это хороший вариант, не забывайте все нужные dll-ки таскать с exe-шником
  2. папку bin в Code::Blocks, в том случае если у вас много СДЛ-проектов, а dll-ки таскать из папки в папку жутко ломает. 
  3. папку system32 в windows-е 

Скажу вам честно, что я поступил самым тривиальным третьим путем, скинул все в windows\system32 знаю что засирание виндуса ни к чему хорошему не приводит, но тем не менее, я сделал именно так. 

В принципе так подключается любая библиотека SDL.

Ну подключить-то мы ее подключили, а как ею пользоваться? Об этом дальше.

Пробуем.

Ага потираем ручки. Как и в случае с инициализацией самой SDL и ее подсистем, TTF - надо сначала инициализировать. Вы мне не поверите, но тысяча чертей, это проще пареной репы:

TTF_Init();

А деинциализация:

TTF_Quit();

Де жа вю... очень похожие названия. Но ведь в этом и суть, что для выполнения одной и той же функции для однотипных заданий, использовать функции сходные в названиях, а самое главное "говорящие" названия функций - это есть самый правильный подход к оформлению программы. Не забывайте, что вашу программу, возможно будут читать другие люди, и сколько бессонных ночей они потеряют пытаясь понять что делает функция sdfgljkgk(), одному Богу известно. Да и вам самим будет проще потом разобраться :) 

А теперь возвращаясь к теме нашего повествования, хочу отметить, что TTF_Init() при верной инициализации выдает 0, а при неверной -1. За этим как всегда надо следить, поэтому аккуратно оборачиваем её в if с проверкой:

if (TTF_Init() == -1) 
{
  printf("Unable to initialize SDL_ttf: %s \n", TTF_GetError());
}

как видите функция возвращающая значение ошибки, так же имеет "говорящее" название TTF_GetError(). О том инициалицирована ли библиотека, можно узнать функцией TTF_WasInit();

Теперь не мешало бы поговорить о фонтах(font-шрифт). Эта библиотека работает со шрифтами ttf( TrueTypeFont) рекомендую нагуглить парочку таких бесплатных шрифтов для наших эксперементов, можно конечно воспользоваться стандартными виндовсовскими, но они залицензированы и использовать их в коммерческом проекте нельзя, только если вы не купите право их использовать у МС. В интернете есть тонны бесплатных шрифтов, надо тока поискать любой на ваш вкус.

Теперь нам необходимо загрузить шрифт и указать его размер, чтобы использовать в дальнейшем для написания нашего предложения. Делает это функция TTF_OpenFont, вот как надо ее использовать:

TTF_Font* TTF_OpenFont( font_name, font_size );

Она принимает 2 параметра, название шрифта и его размер, а возвращает указатель на объект типа TTF_Font. Итак чтобы инициализировать конкретный шрифт, нам надо создать указатель и "заполнить" его загруженным шрифтом. Сам шрифт должен лежать в папке проекта, думаю это очевидно.

TTF_Font *my_font = NULL; // указатель на шрифт

my_font = TTF_OpenFont("Diablo Heavy.ttf", 36); // грузим шрифт

if (my_font == NULL) {  // если он не загрузился и остался NULL
  printf("Unable to load font: %s \n", TTF_GetError());
  return false;
}

И после не забываем проверить, что он загружен. Таков хороший стиль программирования. 

Я скачал и использовал шрифт, отображающий текст в стиле игры Diablo - он называется "Diablo Heavy.ttf",  скачать его можно вот по этой ссылке http://www.creamundo.com/index.php?lang=en&letra=d&fuente=Diablo+Heavy+TTF или еще где-нибудь. Мне кажется что он наиболее подходит для этой фразы, но вы можете использовать любой другой шрифт, тока не забудьте поменять название в функции загрузки TTF_OpenFont ;)

Итак, шрифт загружен и теперь его надо бы отобразить, а иначе зачем мы это все затевали? Так вот чтобы нам отобразить текст, надо знать как минимум 3 вещи, это координаты в окне, где мы будем выводить наш текст, цвет текста и цвет фона под текстом. Начнем с цвета.

Цвет.

Абсолютно любой цвет образуется путем смешивания трех основных цветов красного(red), зеленого(green) и голубого(blue). Подобно тому как художник на мольберте смешивает цвета красок для того чтобы отбразить нужный цвет, мы можем сделать это и в компьютере. Нам необходимо будет лишь задать контраст этих цветов от 0 до 255 и мы получим нужный нам цвет. Вы наверное замечали в различных редакторах, что выбирая цвет показывается так же уровни этих трех цветовых компонентов. 

Из рисунка видно, что этот цвет... эмм (блин, во выбрал-то, и названия такого не знаю, будет считать серо-бур-малиновый) можно представить как три цвета красный, зеленый и синий в такой вот пропорции( 54,154,56 ). В SDL цвет задается структурой SDL_Color:

  typedef struct{
      Uint8 r; // Величина красной составляющей
      Uint8 g; // Величина зеленой составляющей
      Uint8 b; // Величина синей составляющей
      Uint8 unused; // неиспользуемый параметр
  } SDL_Color;

Создав объект этого типа и заполнив цветовые компоненты, значениями - мы в итоге получим нужный цвет в представлении SDL. Заполнить структуру можно двумя способами: 

1) задать значения поэлементно

  SDL_Color back_color;

  back_color.r = 255;
 
back_color.g = 0;
 
back_color.b = 128;

2) а можно задать более простым способом, в одну строку

   SDL_Color back_color = { 255, 0, 128 }

Второй вариант предпочтительнее, по той причине, что мы можем дефайнами (#define) предопределить цвета и более удобно использовать их. Например:

#define BLACK_COLOR 0,0,0
#define WHITE_COLOR 255,255,255
#define RED_COLOR 255,0,0
#define BLUE_COLOR 0,0,255

Создание SDL-цвета сокартится, до:

SDL_Color fore_color = { RED_COLOR };

Теперь поговорим о координатах для отображения нашего текста в окне SDL. 

Координаты.

Для того чтобы указать где отображать текст нам достаточно двух цифр, координат по оси X и по оси Y от левого верхнего края окна SDL-приложения. Но в функции, которая нам будет необходима, мы должны передавать тип SDL_Rect. Так, я ничегошеньки про эту функцию не сказал. Что же надо восполнить упущение. 

int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);

Эта функция копирует одну поверхность(сурфейс) на другую. Я уже говорил, что в SDL очень много работы с сурфейсами. Пока мы знали только сурфейс окна, созданную функцией SDL_SetVideoMode, для текста мы тоже должны создать свой сурфейс, заполнить его текстом и положить на сурфейс окна(ну то есть проще, говоря, отобразить надпись в окне, а технически получается - скопировать сурфейс на сурфейс). И как раз для этого нужна эта функция.

1)Первый параметр SDL_Surface *src сурфейс источника,

2)второй: SDL_Rect *srcrect прямоугольник сурфейса источника, если второй параметр NULL, то копируется вся сурфейс

3)третий:  SDL_Surface *dst сурфейс получателя(у нас это экран(screen)),

4)четвертый: SDL_Rect *dstrect прямоугольный участок сурфейса получателя , если 4 параметр равен NULL - то копируется в координаты (0,0) - левый-верхний угол получателя.

 Так что если быть совсем точным, то эта функция копирует заданный прямоугольник одного сурфейса в прямоугольник другого. Зная это, можно уже прикинуть как будет выглядеть наша функция при вызове:

SDL_BlitSurface(textSurface, NULL, screen, &textLocation);

,где textSurface - сурфейс текста, screen - сурфейс окна, textLocation - координаты прямоугольника отрисовки (текста в окне). Так выглядит структура прямоугольного участка SDL_Rect:

typedef struct{
  Sint16 x, y;  // Позиция верхнего левого угла прямоугольной области
  Uint16 w, h;  // Ширина и высота прямоугольной области
} SDL_Rect;

Заполнять объект этого типа можно так же простым способом как и SDL_Color, что сократит время и усилия:

SDL_Rect textLocation = { 100, 200, 0, 0 };

TextSurface.

Остался один нерешенный вопрос, как создать сурфейс с нашим текстом? В библиотеке SDL_ttf для этого есть 3 основые режима:

1) Solid - рисует быстро, но не очень качественно и потому используется в тех случаях, когда важнее скорость

2) Blended - обратная Solid, то есть медленная, но за качество "отвечает"

3) Shaded - отличная от первых двух, прежде всего тем, что тескто можно рендерить с бэк-колором, то есть помимо цвета текста надо задавать цвет фона на котором этот текст будет отображаться. Быстрый как Solid, и качественный как Blended.

Отвечают за это 3 функции: TTF_RenderText_Solid, TTF_RenderText_Blended и TTF_RenderText_Shaded. Мы воспользуемся здесь третьим вариантом. Объявим сурфейс для текста:

SDL_Surface* textSurface = NULL;

Заполним сурфейс классической фразой, в Shaded режиме: первый параметр -шрифт, второй - текст, третий цвет текста, четвертый - цвет фона под текстом.

  textSurface = TTF_RenderText_Shaded(my_font, "To be or not to be.", fore_color, back_color);

проверим обязательно, что сурфейс создана, иначе вываливаемся в панике:

  if(textSurface == NULL)
  {
  printf("Unable to load textsurface: %s \n", SDL_GetError()); return false;
  }

Ну а дальше, когда мы получили сурфейс текста, можно уже копировать ее на сурфейс экрана. Об этом я уже рассказывал ранее, какой функцией это делается. Но надо учесть и еще один факт, что когда мы создавали сурфейс окна SDL мы разрешили делать двойную буфферизацию экрана флагом SDL_DOUBLEBUF. И чтобы отобразить нашу поверхность и увидеть текст, надо флипнуть буффер экрана

SDL_Flip(screen);

по завершении мы должны освободить все используемые нами сурфейсы. У нас их 2: сурфейс окна и сурфейс текста. И если сурфейс окна освобождается командой SDL_Quit(), то остальные сурфейсы мы должны удалить вручную специально предназначенной для этого функцией SDL_FreeSurface(сурфейс). Следите за этим внимательно, это не только хороший стиль программирования, но и забота о пользователе вашей программы. Не забудьте, что как бы ваша программа ни была хороша, но если она не освободит ресурсы, то по ее завершении пользователю, возможно, надо будет рестартануть систему, а пару раз рестартанув, он уже наврятли захочет еще раз запустить ваше творение.

Это всё, а вот текст программы, которая у нас получилась.

#include <SDL.h>
#include <SDL_TTF.h>

#define BLACK_COLOR 0,0,0
#define WHITE_COLOR 255,255,255
#define RED_COLOR 255,0,0
#define BLUE_COLOR 0,0,255

const int WINDOW_WIDTH = 640;
const int WINDOW_HEIGHT = 480;

int main ( int argc, char** argv )
{

 if(SDL_Init( SDL_INIT_EVERYTHING ) == -1) // инициализируем видео-подсистему
  {
  printf("SDL_Init failed: %s\n", SDL_GetError() ); return false;
  }
 
 if (TTF_Init() == -1) 
  {
  printf("Unable to initialize SDL_ttf: %s \n", TTF_GetError());
  } 
  
  TTF_Font* my_font = NULL;
  my_font = TTF_OpenFont("Diablo Heavy.ttf", 36); //ARIAL.TTF", 24);

  if(my_font == NULL)
  { // если он не загрузился и остался NULL
  printf("Unable to load font: %s \n", TTF_GetError()); return false;
  }

  SDL_Surface* screen = NULL;
  screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 0, SDL_HWSURFACE | SDL_DOUBLEBUF );
  if(screen == NULL)
  {
  printf("Unable to load screen: %s \n", SDL_GetError()); return false;
  }

  SDL_Color fore_color = { RED_COLOR }; //255, 255 };
  SDL_Color back_color = { BLUE_COLOR };

  SDL_Surface* textSurface = NULL;
  textSurface = TTF_RenderText_Shaded(my_font, "To be or not to be.", fore_color, back_color);
  if(textSurface == NULL)
  {
  printf("Unable to load textsurface: %s \n", SDL_GetError()); return false;
  }

  // Pass zero for width and height to draw the whole surface
  SDL_Rect textLocation = { 100, 200, 0, 0 };

  SDL_BlitSurface(textSurface, NULL, screen, &textLocation); // скопируем тектовую сурфейс на экранную screen

  SDL_Flip(screen); // отобразим сарфейс screen

  SDL_Delay(3000); // подождем

  SDL_FreeSurface(textSurface); // освободим поверхность для текста

  TTF_CloseFont(my_font); // закроем используемый шрифт

  TTF_Quit(); // закроем библиотеку шрифтов

  SDL_Quit(); // закроем SDL

  return 0;

}


А вот что вы должны получить в итоге выполнения этой программы.

Выведение.

Отлично! Вы справились и с этим! И теперь, когда вы совладали с выводом текста, подумаем насчет этого предложения. Я склоняюсь к варианту "быть", нежели чем "не быть" :) Думаю и вы тоже.

На очереди отрисовка спрайтов. Но это уже в следующий раз. Чао.


Категория: SDL | Добавил: dimanche13 (14.03.2009)
Просмотров: 15605 | Комментарии: 146 | Рейтинг: 5.0/2 |
Всего комментариев: 131 2 »
13 BrandonCex  
0
hangover remedys <a href=""> https://forums.dieviete.lv/profils/127605/forum/ </a> herbal potpourri blends

12 Prenoccannige  
0
http://www.sarvajal.com - viagra

11 excadaWribrer  
0
http://google2.com - google2

10 foren  
0
Пишу игру, там естественно присутствуют числа,
которые необходимо выводить на экран. Тут пример
показан как вывести просто текст. Дак вот, 1я проблема
проблема, которая у меня возникла, это как вывести значение
изменяющейся переменной(ну к примеру в моей игре есть валюта размер
которой в процессе игры изменяется), а точнее перевести число в текст
и вывести его на экран. Но потом знакомый подсказал, что в СДЛ есть
команда SDL_itoa(int,char*,int); которая собственно говоря и и помогает
вывести число. 1ое значение в этой команде int - целое число, которое надо
перевести(у меня валюта к примеру),2ое значение char* это та переменная
В которую мы собираемся перевести это число, иначе говоря контейнер
и наконец 3е значение это система счисления(мне необходима 10ричная =) ).
2ая проблема,которую я вообщем то и не решил пока заключается в следующем.
В игре я решил сделать возможность пользователю сохранить свою игру.
Я решил что все числа которые присутствуют в игре просто записать
в текстовый документ, ну к примеру игрок решил выйти и сохранился перед
выходом, на тот момент значение переменной было таким valuta=105
чтоб игрок в следующий раз начал играть с этого места я в блокнот запишу
эти данные которые потом считаю, в текстовике данные эти будут выглядеть так:

105

Код записи такой:

FILE * fo;
fo = fopen("test.txt","wt");
fprintf( fo, "%d\n", valuta );
fclose(fo);

Вроде пока все получается, теперь игрок вновь запускает игру и необходимо
передать значение обратно к переменной, вот к примеру таким образом:

FILE * fi;
fi = fopen("test.txt","rt");
fscanf( fi, "%d", &valuta );
fclose(fi);

Затем уже знакомой командой SDL_itoa(); перевести значение для понятного
библиотеке SDL_ttf, но тут то и просисходит интересное, приложение
мгновенно сворачивается и не показывается ни одной ошибки
при удалении команды SDL_itoa(,,); программа вновь компилица
и запускается без ошибок.Хотя если для проверки в SDL_itoa();
записать не переменную valuta, а просто какую-нибудь
int ff=10; то он ее выводит.Возникает вопрос, берется ли из документя
test.txt верное значение? Дописываю код после которого появится еще один
текстовик назавем его test2.txt, код выглядит так:

FILE * ee;
ee = fopen("test2.txt","wt");
fprintf( ee, "%d\n", valuta );
fclose(ee);

запускаю блокнот, в нем значение 105, это говорит о том, что значение
считано правильно, тогда где подвох?=)
Кто понял что я не так сделал, напишите пожалуйста, а то я тут целую
книгу расписал, да еще и нудную ;)

9 J3d1  
0
Освоил кросс-компил в Линукс с использованием SDL (Linux, Windows32, WinCE-ARM. Один исходник - 3 исполняемых файла. Кому интересно: j3d1adm1n@yandex.ru

6 J3d1  
0
Перешел в Linux - осваивать gcc, mingw32, mingw32ce, маке, vim. Назад к истокам как говорится. Надо знать основы - без этого трудно smile

7 dimanche13  
1
Как это не странно, но я тоже вынужден был начать изучать Линукс. biggrin

8 J3d1  
0
biggrin

5 J3d1  
0
Ок, как соберу достаточно материала по компилированию под WinCE в codeblocks - поделюсь обязательно smile

4 dimanche13  
0
насчет урока по выводу спрайтов - то он обязательно будет. Хотя таких уроков миллион и маленькая тележка, мне хотелось бы изложить это в простой и более доступной манере. Об SDL и КПК я бы сам с удовольствием почитал biggrin Впрочем я считаю, что это возможно.

3 J3d1  
0
Маленько офтоп: можно ли прикрутить компилятор cegcc к code::blocks? Хотелось бы писать с SDL и на КПК (WinCE5)

2 J3d1  
0
Спасибо, очень помог. А будет урок по выводу спрайтов? Очень хотелось бы!

1-10 11-11
Имя *:
Email *:
Код *:
Copyright MyCorp © 2024