SInt32; button: UInt8); virtual; procedure doOnJoyAxisMotion(axis: UInt8; value: SInt32); virtual; procedure doOnCheckCollitions; virtual; procedure WireUpEvents; procedure doLoadTextures; virtual; procedure doFreeTextures; virtual; procedure doBeforeStart; virtual; procedure doQuit; public constructor Create; destructor Destroy; override; procedure Start; procedure Stop; property Name: string read fName write fName; property OnRender: TRenderEvent read fOnRender write fOnRender; property OnUpdate: TUpdateEvent read fOnUpdate write fOnUpdate; property OnKeyDown: TKeyboardEvent read fOnKeyDown write fOnKeyDown; property OnKeyUp: TKeyboardEvent read fOnKeyUp write fOnKeyUp; property OnJoyButtonUp: TJoyButtonEvent read fOnJoyButtonUp write fOnJoyButtonUp; property OnJoyButtonDown: TJoyButtonEvent read fTJoyButtonEvent write fTJoyButtonEvent; property OnJoyAxisMotion: TJoyAxisMotionEvent read fOnJoyAxisMotion write fOnJoyAxisMotion; property OnCheckCollisions: TEvent read fOnCheckCollisions write fOnCheckCollisions; property OnQuit: TNotifyEvent read fOnQuit write fOnQuit; end;Na inicializacao da classe, chamamos o metodo WireUpEvents para ajustar os ponteiros dos eventos fazendo com que eles apontem para seu metodo protegido equivalente. As cenas que iremos criar mais a frente, deverao implementar suas funcionalidades sobrescrevendo estes metodos virtuais.Ja TSceneManager servira para agrupar todas as cenas do jogo. Sua implementacao e a mais simples possivel: uma colecao de TScenes, alguns metodos de busca e um indexador para a cena que esta sendo exibida em um determinado momento.TGSceneList = specialize TFPGObjectList; { TSceneManager } TSceneManager = class strict private fCurrentScene: integer; fScenes: TGSceneList; function GetCurrentScene: TScene; procedure SetCurrentScene(AValue: TScene); public function Add(scene: TScene): integer; function ByName(const name: string): TScene; constructor Create; destructor Destroy; override; property Current: TScene read GetCurrentScene write SetCurrentScene; end;Vamos em frente e, com a ideia de desacoplar os varios componentes do motor em subsistemas menores, criamos as seguintes classes:TFonts, para encapsular as fontes do gameTTextManager, para desenhar textos na tela usando as fontes de TFontsTSoundManager, para organizar os sons em memoria e realizar seu playbackTTexrureManager, para organizar as instancias de TTextureCada uma destas classes, atua como um conteiner especializado para possamos comecar a separar os recursos especificos de uma cena ou jogo (imagens, sons e fontes) do codigo de nosso motor, permitindo criar diferentes cenas a partir do mesmo conjunto de classes.Com os recursos devidamente isolados, podemos nos concentrar no motor e em sua logica.Vimos, nos artigos anteriores, que toda a logica do jogo acontecia dentro de um loop. Iremos abstrair a logica deste loop no metodo TEngine.Run e faremos com que ele execute no contexto de uma cena (fActiveScene).procedure TEngine.Run;var deltaTime : real; thisTime, lastTime : UInt32;begin if fActiveScene = nil then raise EngineException.Create('There is no scene to proccess.'); deltaTime := 0.0; thisTime := 0; lastTime := 0; fRunning := true; while fRunning do begin thisTime := SDL_GetTicks; deltaTime := real((thisTime - lastTime) / MSecsPerSec); lastTime := thisTime; doCheckDevices; doHandleEvents; doUpdate(deltaTime); doCheckCollisions; doRender; SDL_Delay(1); end;end;Antes disto, entretanto, e necessario garantir que os subsistemas estao todos inicializados. Para tanto, criamos em TEngine.Inicialize, que recebe a resolucao da tela e o titulo da janela como parametros.procedure TEngine.Initialize(const width: integer; const height: integer; const title: string);var flags, result: integer;begin if ( SDL_Init( SDL_INIT_VIDEO or SDL_INIT_TIMER or SDL_INIT_JOYSTICK or SDL_INIT_AUDIO ) <> 0 )then raise SDLException.Create( SDL_GetError ); fTitle:= title; fWindow := SDL_CreateWindow( PAnsiChar( fTitle ), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN); if ( fWindow = nil ) then raise SDLException.Create( SDL_GetError ); fRenderer := SDL_CreateRenderer( fWindow,