субота, 18 листопада 2017 р.

Розробка фреймворка для 2-Д відеоігор на основі мультимедійної бібліотеки SDL2. Частина 5. Додаємо картинки.


Виведення зображення на екран

Давно вже була остання публікація циклу, тому що я був досить сильно завантажений різними справами і питаннями, які вимагали не відкладати їхнього вирішення, тому виділити час на розробку фреймворка не вдавалось. Зараз я трохи прихворів, і вирішив доки підліковуюсь продовжувати тему.
Отже, ми вже навчились працювати з вікном, тепер будемо виводити зображення на екран. Я не художник, сам малювати вмію не дуже добре, тому будемо розглядати лише програмну частину роботи з зображеннями. Я вирішив скористатись вже готовими малюнками, які можна без особливих проблем знайти і скачати з інтернету. В кінці цієї статті я приведу список сайтів, де можна безкоштовно скачати графіку (і не тільки) для відеоігор.
Для подальшої роботи тобі буде потрібно зображення. Я взяв наступне (якщо знаєш, з якої це гри, напиши в коментарії):


Це зображення збережене в форматі BMP. Бібліотека SDL вміє працювати з цим форматом. Фактично, тут є три зображення персонажа гри для створення анімації стрибка (я спеціально так підібрав), але як створити таку анімацію я розповім пізніше. Спочатку тобі потрібно зберегти це зображення з іменем sample.bmp, наприклад, в папку assets, яку можеш створити в папці bin проекту. В мене повний шлях (відносно проекту) виглядає наступним чином:
sdl2engine/bin/assets/sample.bmp
Для того, щоб зображення можна було вивести на екран, спочатку потрібно створити текстуру (тип PSDL_Texture), куди воно буде завантажене. Але безпосередньо завантажити текстуру з файла SDL не вміє, тому потрібно спочатку створити поверхню (тип PSDL_Surface), куди завантажиться зображення, а тоді створити з поверхні текстуру. Чому ми бужемо використовувати текстуру, а не поверхню? Тому що є одна важлива відмінність: текстура зберігається в пам’яті відеокарти, що забезпечує апаратне прискорення при обробці, а поверхня знаходиться в оперативній пам’яті і не може використовувати апаратного прискорення.
Для простого завантаження малюнка і виведення його на екран я створю новий проект в тій самій папці, що й попередні, а коли ми навчимося повністю працювати з зображеннями, ми інтегруємо це в наш фреймворк.
Запускай Lazarus, відкривай наш самий перший проект demo.lpr і додай в нього наступні зміни (відразу після опису змінних):
     SDLTexture  : PSDL_Texture;
​
procedure LoadImage;
//щоб код краще сприймався,
//винесемо завантаження малюнка окремою процедурою
 var tmpsurface : PSDL_Surface;
begin
  tmpsurface:=SDL_LoadBMP(’assets/sample.bmp’);
  SDLTexture:=SDL_CreateTextureFromSurface(SDLRenderer,tmpsurface);
  SDL_FreeSurface(tmpsurface);
end;
Виклик цієї процедури постав перед головним циклом.
Тепер ми маємо текстуру з малюнком, і потрібно її вивести на екран. Для цього просто додай ще один рядок в головному циклі так, як це зроблено в наступному сніпеті:
          //очищаємо вікно
          SDL_RenderClear(SDLRenderer);
          //виводимо текстуру
          SDL_RenderCopy(SDLRenderer,SDLTexture,nil,nil);
          //показуємо вікно на екрані
          SDL_RenderPresent(SDLRenderer);
Після запуску в тебе з’явиться вікно, на яке повністю буде розтягнутий наш малюнок.

“Добре,” - скажеш ти, - “а як мені вивести малюнок з врахуванням його оригінального розміру і в тій позиції, де я схочу?” Цим ми й займемось зараз.
SDL має спеціальний тип - TSDL_Rect, який містить чотири поля: x,y,w,h (координати лівого верхнього кутка, ширину і висоту). Тому додамо ще дві змінних такого типу, щоб вивести малюнок в потрібному місці і з потрібними розмірами:
     SRCRect, DSTRect : TSDL_Rect;
Тепер опитаємо текстуру, щоб дізнатись її розміри. Зробимо це відразу після створення:
  SDL_QueryTexture(SDLTexture,nil,nil,@SRCRect.w,@SRCRect.h);
Тепер при виведенні текстури на екран змінимо наступні параметри:
          //виводимо текстуру
          SDL_RenderCopy(SDLRenderer,SDLTexture,nil,@SRCRect);
Після запуску на екрані з’явиться вікно з текстурою у верхньому лівому кутку:

Якщо змінити координати в SRCRect, текстура змінить свою позицію відносно вікна. Можеш спробувати в головному циклі випадковим чином ставити координати в межах максимального розміру вікна, тільки ще додай затрримку процедурою SDL_Delay(100), щоб не так швидко перемальовувалось вікно і побачити переміщення текстури.
А тепер починається найцікавіше. Зміни код після опитування текстури наступним чином:
  DSTRect.x:=20;
  DSTRect.y:=20;
  DSTRect.h:=SRCRect.h;
  DSTRect.w:=SRCRect.w div 3;
  SRCRect.w:=SRCRect.w div 3;
а виведення текстури зміни так:
          //виводимо текстуру
          SDL_RenderCopy(SDLRenderer,SDLTexture,@SRCRect,@DSTRect);
І після запуску програми в тебе повинно вивести лише частину зображення:
Як бачиш, ми можемо самі вибирати, що і де повинно малюватись на екрані.

Підтримка прозорості та інші графічні формати

Здається, все у нас добре, і картинка на екран виводиться, і керувати що і куди малювати ми можемо, але є один недостаток - усі картинки лише в форматі BMP, який не підтримує прозорості і займає досить багато місця порівняно з іншими графічними форматами. Звісно, є можливість визначити колір прозорості для зображення, але для цього потрібно знати точно який колір має бути прозорим у форматі R,G,B (пізніше я покажу, як дізнатись колір конкретного пікселя). Набагато зручніше використати, наприклад, формат PNG, який підтримує прозорість, але як ним користуватись? Відповідь - офіційне розширення бібліотеки SDL2 SDL2_Image, яке підтримує роботу з багатьма графічними форматами. Оскільки при підготовці ми вже все встановили, достатньо буде лише підключити відповідний модуль sdl2_image і змінити функцію завантаження зображення з файлу на IMG_Load(’assets/sample.png’) (відповідно усі функції розширення мають префікс IMG_). Ось те ж саме зображення, яке ми використовували, але у форматі PNG і з прозорим фоном:
Спробуй змінити код, так як я описав, і запустити - тепер персонаж не має зеленого фону.
На сьогодні поки що буде усе, а в наступній статті я розповім про те, як можна визначити колір фона і зробити його прозорим, а також зробимо анімацію персонажа та спробуємо інтегрувати все це в наш фреймворк.
Код і ресурси для цієї статті можна скачати тут.
Готові ассети для відеоігор безкоштовно можна знайти на наступних ресурсах: