How to create array as class

Good day!
I use TSptiteBlocksArray and function NewSpritesArray in the next code for ease of working with sprite arrays.

  TViewEnvironmentUnit = class(TCastleView)
    type
      TSpriteBlocksArray = array of TSpriteBlock;
  published
    MainMenu : TCastleUserInterface;
    QuitButton : TCastleButton;
    EnvironmentViewport : TCastleViewport;
    Camera : TCastleCamera;
  private
    FarSpriteBoxes   : TSpriteBlocksArray;
    CloseSpriteBoxes : TSpriteBlocksArray;
    MidSpriteBoxes   : TSpriteBlocksArray;
    ChrsSpritesBoxes : TSpriteBlocksArray;
    InanSpritesBoxes : TSpriteBlocksArray;

    ***

    function NewSpritesArray(Objects : TEssences; Distance : Integer;
                             Scale : Single;      StartTag : Integer): TSpriteBlocksArray;  

***

implementation

function TViewenvironmentunit.NewSpritesArray(Objects : TEssences;
                                              Distance : Integer;
                                              Scale : Single;
                                              StartTag : Integer): TSptiteBlocksArray;
var
  Sector : Single;
  I : Integer;
begin
  SetLength(Result, Length(Objects.Essences));
  Sector := Pi*2/Length(Result);
  for I := 0 to High(Result) do
  begin
    Result[I] := TSpriteBlock.Create(EnvironmentViewport);
    Result[I].PositionBlock(Distance, Sector*I);
    Result[I].Scale := Vector3(Scale, Scale, Scale);
    Result[I].LoadSprite(Objects.Essences[I].ImageUrl);
    Result[I].Sprite.Tag := I + StartTag;
  end;
end;    

But in the function NewSpritesArray compiler indicates Result is not exists.
So my questions is:
Is I must create TSpriteBlocksArray as class before add sprites
(Result := TSptiteBlocksArray.Create;) ? It seems weird, because I haven’t destructor for it.
What is better practice when “array class” is needed?
ResInit

You can safely ignore it. Managed types like dynamic array are auto initialized, see Managed types.

1 Like

Alternative answer would be to not use an array :slight_smile:

In all places in CGE, instead of dynamic arrays (TSpriteBlocksArray = array of TSpriteBlock) we use generic lists (TSpriteBlocksArray = specialize TObjectList<TSpriteBlock>) and I’m happy with it – generic classes remain type-safe (you cannot insert wrong class, compiler will not allow it) and have a bit more features (like methods to sort, can also free instances if you pass true to constructor, can also easily be changed to TComponentList<...> to manage using component-ownership mechanism).

1 Like

Thanks, seems like more elegant instrument then native arrays!
As I see, you use generics not from the FGL?
Is there for the compatibility with Delphi?..
I use only Lazarus, so, TFPGObjectList is optimal list generic for me?

In general, the FGL and Generics.Collections units are both reasonable choices IMO to use for generic classes – see Modern Object Pascal Introduction for Programmers | Castle Game Engine , section " 7.2. Containers (lists, dictionaries) using generics".

Some comparison:

  • Generics.Collections are compatible across FPC and Delphi, this is one of the reasons why we chose them in CGE indeed. FGL is only in FPC.

  • Generics.Collections have out-of-the-box working “comparer” implementations. This meant using them e.g. as lists of records was comfortable out-of-the-box, with FGL we had to define custom operators for comparison. That was a small difference in favor of Generics.Collections long time ago for me (though one could argue that FGL, forcing to define the operators, forced the code to be longer but also safer). And this difference doesn’t matter if you only consider lists of objects, i.e. compare FGL.TFPGObjectList with Generics.Collections.TObjectList.

  • Generics.Collections in FPC can be annoying as they produce a lot of warnings by default ( Compiling code using TDictionary from Generics.Collections results in a number of warnings and notes that developer cannot do anything about (#40222) · Issues · FPC / FPC / FPC Source · GitLab ). If you only compile using CGE build tool/editor, then this doesn’t matter, as we hide these warnings.

All in all, none of the differences matter much, and if your project targets only FPC/Lazarus, then FGL is indeed a reasonable choice too. In my personal projects, even if only for FPC/Lazarus, I tend to choose Generics.Collections anyway, just because I’m used to some details of it more.

1 Like