program tiles02;

// Example for creating sprites with animation

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}

uses SysUtils,
     fwLogging,
     fwCustomEngine,
     fwPlattform,
     fwResource,
     fwAnimation,
     fwSprite;

const
  SCREEN_WIDTH     = 320;
  SCREEN_HEIGHT    = 240;
  SCREEN_BPP       = 16;

  cStepX           = 2;
  cStepY           = 2;

var
  iLoopX, iLoopY   : Integer;
  iSequence        : Integer;
  Viewpoint        : TWorldRect;
  Screen           : TfwCESurface;
  Resources        : TfwResourceManager;
  SpriteEngine     : TfwSpriteEngine;
  ShipImage        : TfwCESurface;
  GunImage         : TfwCESurface;
  BulletImage      : TfwCESurface;
  TileImage        : TfwCESurface;
  ShipAnim         : TfwAnimSequences;
  GunAnimation     : TfwAnimSequences;
  ShipSprite       : TfwSprite;
  BulletSprite     : TfwSprite;
  GunSprite        : TfwSprite;
  GunTile          : PTileItem;
  Tiles            : TfwCustomTileMap;
begin
  // setup graphic engine
  SetHAL(TfwEngine.Create(false, false));
  try
    Screen := HAL.Init(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP);
    if Assigned(Screen) then begin
      // video, audio and control init done with default values for
      // each plattform.

      Resources := TfwResourceManager.Create();
      try
        // Loading image
        ShipImage := HAL.CreateSurface('../Media/ip_ship2.bmp', $00FF00FF);
        if not Assigned(ShipImage) then begin
          Exit;
        end;
        Resources.Add('S1', ShipImage);

        BulletImage := HAL.CreateSurface('../Media/bullet01.bmp', $00FF00FF);
        if not Assigned(BulletImage) then begin
          Exit;
        end;
        Resources.Add('BT1', BulletImage);

        TileImage := HAL.CreateSurface('../Media/sftiles.bmp', $00FF00FF);
        if not Assigned(TileImage) then begin
          Exit;
        end;
        Resources.Add('T1', TileImage);

        // Creating animation for ship. Multiple sprites can sharing
        // one animation obcekt.
        ShipAnim := TfwAnimSequences.Create;
        if not Assigned(ShipAnim) then begin
          Exit;
        end;
        Resources.Add('RM1', ShipAnim);

        GunAnimation := TfwAnimSequences.Create;
        if not Assigned(GunAnimation) then begin
          Exit;
        end;
        Resources.Add('GUNA1', GunAnimation);

        // define one animation sequence. A sprite can have more
        // than one sequence. Each sequence contains one or
        // more sub images.
        ShipAnim.AddSequence.AddFrame( 0, 48, 24, 24);      // 0 - move left
        ShipAnim.AddSequence.AddFrame( 0,  0, 24, 24);      // 1 - move left top
        ShipAnim.AddSequence.AddFrame(48,  0, 24, 24);      // 2 - move top
        ShipAnim.AddSequence.AddFrame(96,  0, 24, 24);      // 3 - move top right
        ShipAnim.AddSequence.AddFrame(96, 48, 48, 24);      // 4 - move right
        ShipAnim.AddSequence.AddFrame(96, 96, 48, 24);      // 5 - move right down
        ShipAnim.AddSequence.AddFrame(48, 96, 24, 24);      // 6 - move down
        ShipAnim.AddSequence.AddFrame( 0, 96, 24, 24);      // 7 - move down left

        Viewpoint.Left   := 0;
        Viewpoint.Top    := 0;
        Viewpoint.Right  := 319;
        Viewpoint.Bottom := 239;

        // Creating the world for all sprites
        SpriteEngine := TfwSpriteEngine.Create;
        if not Assigned(SpriteEngine) then begin
          Exit;
        end;

        // create animation for gun
        GunAnimation.AddSequence.AddFrames(0,  34, 16, 16, 7, 1, 1);

        Tiles := TfwCustomTileMap.Create(SpriteEngine);
        if not Assigned(Tiles) then begin
          Exit;
        end;
        Resources.Add('TILES01', Tiles);

        Tiles.TileImage := TileImage;
        Tiles.AddTiles(1, 4, 2, 0, 0, 16, 16, 1, 1);
        GunTile := Tiles.AddTile(128, GunAnimation.Items[0].Items[0]);
        if Assigned(GunTile) then begin
          GunTile^.Animation := GunAnimation;
        end;

        // Erstelle die Karte
        Randomize;
        Tiles.SetMapSize(100, 50, 16, 16);
        for iLoopY := 0 to 50 do begin
          for iLoopX := 0 to 100 do begin
            Tiles.AddMapItem(Random(8) + 1, iLoopX, iLoopY, True);
          end;
        end;
        Tiles.Show;

        Tiles[15, 15]^.Tile := GunTile;

        Tiles.PosX :=  0;
        Tiles.PosY :=  0;
        Tiles.PosZ := -1;

        // Create one sprite
        ShipSprite := TfwSprite.Create(SpriteEngine);
        if not Assigned(ShipSprite) then begin
          Exit;
        end;
        Resources.Add('SPR01', ShipSprite);

        // set image and animation stuff
        ShipSprite.Image := ShipImage;
        ShipSprite.AnimController.Animation := ShipAnim;
        ShipSprite.AnimController.AutoLoop  := True;
        ShipSprite.Show;

        ShipSprite.PosX := 148;
        ShipSprite.PosY := 108;

        // Add sprite to render pipeline
        SpriteEngine.Add(Tiles);
        SpriteEngine.Add(ShipSprite);

        while (not HAL().ExitKeyPressed()) do begin

          // paint background black
          HAL.ClearScreen($00000000);

          // render all srpite to screen
          SpriteEngine.Render(Screen, Viewpoint);

          // show graphics
          HAL.Flip(Screen);

          // update control all
          HAL.Idle();
          HAL.UpdateInput();

          // Actor movement
          iSequence := 0;
          if HAL.Controls.KeyPressed(LEFT_BUTTON) then begin
            if (SpriteEngine.PosX < 134) then begin
              ShipSprite.PosX := ShipSprite.PosX - cStepX;
              SpriteEngine.PosX := SpriteEngine.PosX + cStepX;
              iSequence := 1;
            end;
          end;

          if HAL.Controls.KeyPressed(UP_BUTTON) then begin
            if (SpriteEngine.PosY < 94) then begin
              ShipSprite.PosY := ShipSprite.PosY - cStepY;
              SpriteEngine.PosY := SpriteEngine.PosY + cStepX;
              iSequence := iSequence or 2;
            end;
          end;

          if HAL.Controls.KeyPressed(RIGHT_BUTTON) then begin
            if (SpriteEngine.PosX > -1430) then begin
              ShipSprite.PosX := ShipSprite.PosX + cStepX;
              SpriteEngine.PosX := SpriteEngine.PosX - cStepX;
              iSequence := iSequence or 4;
            end;
          end;

          if HAL.Controls.KeyPressed(DOWN_BUTTON) then begin
            if (SpriteEngine.PosY > -670) then begin
              ShipSprite.PosY := ShipSprite.PosY + cStepY;
              SpriteEngine.PosY := SpriteEngine.PosY - cStepX;
              iSequence := iSequence or 8;
            end;
          end;

          case iSequence of
            1 : ShipSprite.AnimController.Sequence := 0;
            2 : ShipSprite.AnimController.Sequence := 2;
            3 : ShipSprite.AnimController.Sequence := 1;
            4 : ShipSprite.AnimController.Sequence := 4;
            6 : ShipSprite.AnimController.Sequence := 3;
            8 : ShipSprite.AnimController.Sequence := 6;
            9 : ShipSprite.AnimController.Sequence := 7;
           12 : ShipSprite.AnimController.Sequence := 5;
          else
            // nothing to do, mostly unusable key combination
          end;

          // do all animations
          SpriteEngine.Move(HAL.FrameTime);
        end;
      finally
        FreeAndNil(Resources);
      end;
    end;
  except
    on E : Exception do begin
      fwLog(E.Message);
    end;
  end;
end.
