Design for units

Good day!
Is I understand right, that DesignedComponent is function of the TCastleView means that I can load disigned components only if Iuse child class of TCastleView?
For example this is class of inventory display.

  TInventoryDisplay = class(TCastleUserInterface)
    DisplayScroll : TCastleScrollView;
    Area1, Area2 : TCastleUserInterface;
    Display1, Display2 : TItemsDisplay;

    ControlArea : TCastleRectangleControl;
    Description : TCastleLabel;
    RotationButton : TCastleButton;
    constructor Create(AOwner: TComponent); override;
    procedure FillingOfTheDScroll(inv1, inv2: TInventory);
    procedure AddItemToDScroll(item: TItemDisplay);
    procedure DelItemToDScroll(item: Integer);
    procedure RotateInventory(Sender : TObject);
    procedure From1to2(ItemNum: Integer);
    procedure From2to1(ItemNum: Integer);
    destructor Destroy; override;

For now I use too much code to group it all rightly. So, if I create this class in special unit and want to construct in CGE Editor, I have only one approach:

TInventoryDisplay = class(TCastleView)

When I did it and run project I get message:

DesignedComponent can only be used if the design was loaded, which means that TCastleView has started and DesignUrl is not empty.
There are few parts of code:

constructor TInventoryDisplay.Create(AOwner: TComponent);
  DesignUrl := 'castle-data:/gameviewmain.castle-user-interface';


procedure TInventoryDisplay.Start;
  RotationButton := DesignedComponent('Button') as TCastleButton;
  RotationButton.OnClick := @RotateInventory;

And this in the Main unit:

  Player_Inv := TInventoryDisplay.Create(Char_Items_Disp_Area);
  Player_Inv.FillingOfTheDScroll(Character_Items, Containers_Items);

So, what the problem with this?..

I must admit I do not fully understand what exactly you are trying to achieve (in other words, how exactly you envision usage of TInventoryDisplay) . Guessing from the function names, this is a single inventory item, right?

Unfortunately too tired right now to explain in more detail, but more likely you are looking for something like Components to reuse a design in other designs | Manual | Castle Game Engine - if you have designed them using Editor and placed them in your View.

You can load the designs by code through Castle Game Engine: CastleControls: Class TCastleDesign - this may be more flexible than the previous path.

1 Like

Thanks, I began to understand.

1 Like

One additional question is how to get access to the objects “inside” of design from code?
I can’t just create Design and use the button, I must manually create Button and set they personal URL from Design?..
Sorry, if I explained a little confused. For Example, I need to use ControllButton from here:
Снимок экрана_2024-02-09_12-06-44

I must do approximately this:

ContBut : TCastleButton;
ContBut := TCastleButton.Create(Somewhere);
ContBut := DesignedComponent('ControlButton'') as TCastleButton;

, or I can use all objects Inside the Design, when that is already created (without additional manipulation)?

  1. The method TCastleView.DesignedComponent can only be used between design Start and Stop. I think this answers your original question? :slight_smile:

  2. Moreover, to be clear, you can load designs (files like .castle-user-interface) without TCastleView.

2.1. One approach is mentioned by @eugeneloza , Components to reuse a design in other designs | Manual | Castle Game Engine . This means you use class like TCastleDesign, point the URL to a design file, and then use TCastleDesign.DesignedComponent. Like

  MyDesign: TCastleDesign;
  MyButtonFromDesign: TCastleButton;
  MyDesign := TCastleDesign.Create(...);
  MyDesign.Url := 'castle-data:/button_design.castle-user-interface';
  MyButtonFromDesign := MyDesign.DesignedComponent('MyButton') as TCastleButton;

  // remember to add it to some parent, e.g. from view, to make it visible

2.2. Or you can deserialize the design files using UserInterfaceLoad. You then set at owner of the loaded things, and you can use FindRequiredComponent on t, like this:

  OwnerOfLoadedComponents: TComponent;
  MyDesignRoot: TCastleUserInterface;
  MyButtonFromDesign: TCastleButton;
  OwnerOfLoadedComponents := TComponent.Create(...);
  MyDesignRoot := UserInterfaceLoad('castle-data:/button_design.castle-user-interface', OwnerOfLoadedComponents);
  MyButtonFromDesign := OwnerOfLoadedComponents.FindRequiredComponent('MyButton') as TCastleButton;

  // remember to add it to some parent, e.g. from view, to make it visible

I would usually recommend using TCastleDesign over UserInterfaceLoad, the API is a bit more straightforward, though deep down they do the same thing.

1 Like

P.S. Take a look at example examples/advanced_editor/advanced_loading_designs in CGE sources, castle-engine/examples/advanced_editor/advanced_loading_designs at master · castle-engine/castle-engine · GitHub . It shows some stuff we mention above, and has a README that provides an overview.

1 Like

Thanks, examples added understanding!
For now it looks enough simple to use :upside_down_face:

1 Like