Епізод 02. "Розділяй і владарюй!"

В минулому епізоді ми створили просту програму з використанням SDL 2.0, яка створювала вікно розміром 640х480 пікселів з заголовком "demo01" і голубим фоном. Вікно вміло реагувати на подію закриття. Всеь код, який відповідав за це, був одним цілим і не зовсім зрозуміло, як з нього можна отримати гру.

Сьогодні спробуємо розділити цей код на окремі логічні фрагменти і винести їх у відповідні підпрограми. Але спочатку давайте розглянемо з чого складається будь-яка гра, точніше, алгоритм, по якому працює будь-яка гра.

Після успішної ініціалізації потрібних даних та створення усіх об'єктів запускається бескінечний цикл, в якому перевіряється ввід даних від користувача і обробка відповідних подій, на основі цього прораховуються зміни в ігровій логіці та відбувається відображення поточного стану гри на екран. Коли користувач завершує гру, цикл переривається і відбувається очистка пам'яті та коректне завершення виконання. Тож давайте спробуємо виділити ці фрагменти і в нашій програмі.

Перший фрагмент буде відповідати за ініціалізацію, тому першу підпрограму так і назвемо. До неї перенесемо рядки коду від початку програми до початку циклу - саме в цих рядках ініціалізується SDL 2.0, створюються вікно та візуалізатор і встановлюється ознака виконання циклу. Також непогано було б цей код зробити не процедурою, а функцією, яка буде приймати на вхід параметри - розміри вікна та заголовок, а повертати true якщо все пройшло успішно і false коли щось пішло не по плану.

function Initialize(aCaption : PChar; _w,_h : Integer) : Boolean;
begin
  result:=false;
  //ініціалізація бібліотеки SDL 2.0
  if SDL_Init(SDL_INIT_EVERYTHING)>=0 then begin
    //успішна ініціалізація - створюємо вікно
    SDLWindow:=SDL_CreateWindow(aCaption,
                               SDL_WINDOWPOS_UNDEFINED,
                               SDL_WINDOWPOS_UNDEFINED,
                               _w,
                               _h,
                               SDL_WINDOW_SHOWN);
    //якщо вікно створене, створюємо візуалізатор
    if SDLWindow<>nil then begin
      SDLRenderer:=SDL_CreateRenderer(SDLWindow,-1,0);
      if SDLRenderer=nil then begin
        WriteLN('SDL error: ',SDL_GetError);
        Exit;
      end;
    end;
    //виділення пам'яті для структури обробки подій
    New(SDLEvent);
    //встановлення ознаки виконання циклу і його запуск
    isRun := true;
    result:=true;
    end;
end;

Також перед запуском циклу буде перевірятись результат виконання цієї функції і запускатись він буде лише при успішному виконанні ініціалізації.

Наступний крок алгоритму - обробка подій. Винесемо цей фрагмент теж окремою процедурою. Окрім неї, в алгоритмі ще є обробка ігрової логіки, але оскільки в нас ще фактично ніякої ігрової логіки не задіяно, створимо для використання в майбутньому порожню процедуру:

procedure DoEvents;
begin
  //намагаємось відловити подію закриття вікна
  if SDL_PollEvent(SDLEvent)=1 then begin
    if SDLEvent^.type_=SDL_QUITEV then isRun:=false;
  end;
end;

procedure GameLogic;
begin
  //тут в майбутньому буде щось прораховуватись
end;

Усі ігри виводять якусь картинку на екран. І хоча в нас ще немає що виводити, проте є код який відповідає за очищення вікна кольором фону. Отримуємо ще одну процедуру:

procedure Draw;
begin
  //встановимо колір вікна в голубий
  SDL_SetRenderDrawColor(SDLRenderer,0,128,255,255);
  //очисстити вікно
  SDL_RenderClear(SDLRenderer);
  //показати вікно на екран
  SDL_RenderPresent(SDLRenderer);
end;

І останній крок, який нам лишився - очистка пам'яті після завершення циклу.

procedure Cleanup;
begin
  //прибрати за собою - в оберненому порядку створення
  Dispose(SDLEvent);
  SDL_DestroyRenderer(SDLRenderer);
  SDL_DestroyWindow(SDLWindow);
  SDL_Quit();
end;

Після усіх маніпуляцій з кодом програма стане наступною:

program demo02;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Classes
  { you can add units after this },sdl2;
var
  SDLWindow : PSDL_Window;     //вікно
  SDLRenderer : PSDL_Renderer; //візуалізатор
  SDLEvent : PSDL_Event;       //події
  isRun : Boolean;             //ознака виконання циклу

//тут в кінцевому коді будуть підпрограми, описані вище

begin
  if Initialize('Demo02',640,480) then
    while isRun=true do begin
      DoEvents;
      GameLogic;
      Draw;
    end;
    Cleanup;
end.

Ну ось, тепер в нас починає вимальовуватись щось схоже на заготовку для гри, проте до справжньої гри ще досить далеко. В наступному епізоді спробуємо перевести отриманий код на ООП і сформувати основний клас для майбутнього фреймворку, який поступово будемо доповнювати.

На сьогодні буде достатньо, код проекту можна скачати на Github, а весь процес можна подивитись на відео:

← попередня частина | наступна частина →

Немає коментарів:

Дописати коментар