Using Designed Components in code (part 2)

Hi!

Can I use (combine) more designed ‘gamestateplay.castle-user-interface’ in code at the same time that were made with CGE editor, or is every user-interface erased from memory automatically when I load a new one in the code?
I would like to make a user-interface for every background location scene (with background and location objects etc) without erasing player scene.

And how can I hide the mouse cursor?
I have ‘Viewport.Cursor := mcNone’; but it is still displayed.

I’m afraid I don’t fully understand what you mean here or trying to achieve. Do you want to edit the scene in Castle-Editor and immediately see the changes in-game? No, you should re-launch the game State (and do some additional in-code manipulations if the State was preloaded).

If the next sentence is the problem you are trying to solve:

First - you should not worry about erasing Player scene. It will be stored in cache once loaded. If you want, you can even preload it by using “warmup cache”: Customize look by CastleSettings.xml | Manual | Castle Game Engine

Second - I’m not sure if having locations as different castle-user-interface is a good idea. My first guess would be to have castle-user-interface for … actually User Interface, and have a placeholder into which load the locations as it changes.

If you still want to achieve exactly this result - you may have either your location or Player scene or both of them as TCastleDesign Castle Game Engine: CastleControls: Class TCastleDesign - it’s literally a castle-user-interface inside another castle-user-interface. E.g. this way you can change location but have Player and UI unchanged and inside the same TUiState that handles their behavior.

If I remember correctly - you have to set mouse cursor also for your mouse cursor image:

Yes, that is what I want.
:slight_smile:

Found:

I guess I need a different hierarchy and put everything I already have under the TCastleDesign?
This is what I have but when I want to put the TCastleDesign above it the editor wants to close my current design:

image

If I remember correctly - you have to set mouse cursor also for your mouse cursor image:

I could not find the Cursor property in Scene in the editor but got it to work in the code:

Scene := DesignedComponent (‘Mouse’) as TCastleScene;
Scene.Cursor:= mcNone;

Funny thing is, when I now move my custom mouse scene , the standard cursor becomes visible for a very short moment. Maybe I am picky now but it’s not perfect.

Strange, because that’s exactly the problem this approach should fix :slight_smile: I’ll need to test it on my side, I’ve added custom cursor by code, not through Castle Editor.

Try the mcForceNone instead of mcNone. Now I recall it may be the best solution to.

Depends on what you are trying to achieve. Overall, TCastleDesign is a castle-user-interface file. I.e. like you load an image into TCastleImageControl, the same way you load castle-user-interface file into TCastleDesign. That means that you create your Design file separately and then just reference it from main Design.

Just tried but when I move the ‘mouse’ scene the default windows cursor appears again, only when moving the scene.

The cursor should definitely stay hidden if you hide it. Maybe you move mouse over some other invisible control, that wants to show the cursor? You can use mcForceNone to avoid this.

The logic is: the top-most UI control under mouse determines the cursor.

… Unless any UI control under the mouse has mcForceNone, then the cursor is always hidden.

Note that you can also use Window.Container.OverrideCursor to force a specific cursor, completely regardless of what UI controls say.

As for adding

  • one inner.castle-user-interface (which may be location1.castle-user-interface, location2.castle-user-interface etc/)
  • inside another outer.castle-user-interface (which may be a state design, i.e. gamestatexxx.casle-user-interface):

this is absolutely possible and indeed I think it’s a good approach in your case. You can do it by:

  • placing TCastleDesign inside your outer.castle-user-interface. At runtime (or at design-time) you can set the URL of this TCastleDesign instance to point to e.g. castle-data:/locations/location1.castle-user-interface

  • or do it entirely by code, using UserInterfaceLoad('castle-data:/locations/location1.castle-user-interface', ...) to load the location UI and then add it to the scene.

See examples/advanced_editor/ for example.

Note: you should carefully choose the place where you load things “specific to locations”. Above I described what to do if each location is a new UI control, something descending from TCastleUserInterface. But you may as well choose that all UI controls (including e.g. TCastleViewport) should stay constant, i.e. within outer.castle-user-interface and you only want to change some TCastleTransform / TCastleScene inside. A very similar answer applies in this case:

  • you can use TCastleTransformDesign inside Viewport.Items. You can switch the URL (at runtime or design-time) of TCastleTransformDesign to point to some inner.castle-transform file

  • or you can load inner.castle-transform file by TransformLoad('inner.castle-transform', ...)

Example also in examples/advanced_editor/.

The mouse cursor is moving over the background scene.
Ok, now I added a mcForceNone for the background scene. And indeed, the cursor now is gone when I move the mousescene.
:slight_smile:
It is still visible when I move over the playing character scenes, so I have to mcForceNone for all scenes or, if I understand you right, I should put the Mouse Scene as the last one in the rendering order (see the hierarchy in my earlier uploaded file).

I experimented with it but got confused.
:slight_smile:

This is now what I have.

I want the Gamestateplay user interface to be the main interface, containing only mouse and main player character scene.
I have added a ‘LocationDesign’ TCastleTransformDesign to it, that should be used for displaying locations/backgrounds and objects on location. (also NPC characters but in code).

See the hierarchy. Is this the right approach?
And I can’t get the Location Design viewport fullsize, but I have checked the fullsize box.

I’m afraid it doesn’t make sense :slight_smile:

You now have one TCastleViewport, inside it you added TCastleDesign as a child, and inside it you added another TCastleViewport as a child.

What you want instead:

  • You want to have 1x TCastleViewport in your game. And place all TCastleScene/TCastleTransform inside Items of this viewport.

  • To assign stuff to TCastleDesign, set TCastleDesign.URL to point to another xxx.castle-user-interface file (while you can add children explicitly to TCastleDesign too, in this case it is probably not what you want).

  • But you likely want TCastleDesignTrasform not TCastleDesign. I described them both in my earlier answer, to describe to you the choice, as I don’t know all your game requirements. But you need to decide and choose which one fits you best. Test examples/advanced_editor/ to understand them.

  • Note that in your post you also show TCastleDesign , while writing abuot TCastleDesignTransform.

To make viewport (under TCastleDesign) fullscreen, you likely want to also set TCastleDesign.FullSize = true (otherwise viewport inside it will only fill the TCastleDesign parent). But first you need to remake your hierarchy to make sense, this question may then be irrelevant.

What you (probably – this depends on your game requirements, so I cannot give guaranteed solutions here, but only speak from what I know) want is a hierarchy like this:

gamestatemain.castle-user-interface contains

  • As root, instance of TCastleUserInterface itself (not any descendant; it acts just as a group of UI components then). It has children:
    • various UI, like TCastleLabel
    • and it contains MainViewport: TCastleViewport. The viewport contains (inside viewport’s Items) instances of classes descending from TCastleTransform:
      • TCastleDesignTransform that points (by URL) to a file like location1.castle-transform
      • and any other TCastleScene/TCastleTransform that may be constant (not specific to a location

location1.castle-transform contains:

  • As root, instance of TCastleTransform. It has children:
    • any TCastleScene/TCastleTransform that is specific to a location

Got it, thanks.
Learning to use the editor by trial and error.

Update:

Is this correct? Now I have a pointer to the first location url user interface.
But the location is placed over the scenes of the main user interface (I can see only part of it and the mouse is not visible).
All scenes have translation Z > 0 but they still are behind the location picture.

And the animation of PlayerScene is now very slow and laggy. 
This is part of the code. It worked okay with just the main interface but now it is not.

procedure TStatePlay.CreateLocation;
begin
  Location := TLocation.Create;
  Location.Name := 'westbeach';
  DesignUrl := 'castle-data:/westbeach-gamestateplay.castle-user-interface';
  Location.BackgroundScene := DesignedComponent ('Background') as TCastleScene;
  Location.BackgroundScene.URL := 'castle-data:/locations/' + Location.Name + '.png';
  Location.BackGroundScene.Cursor:= mcForceNone;
end;

procedure TStatePlay.Start;
var I: integer;
begin
  inherited;
   CreateLocation;
   DesignUrl := 'castle-data:/gamestateplay.castle-user-interface';
   MainViewport := DesignedComponent ('Viewport') as TCastleViewport;

   PlayerScene := DesignedComponent ('PlayerScene') as TCastleTransform;

   Mainviewport.Navigation := TCastle2DNavigation.Create(Mainviewport);

   Label1 := DesignedComponent ('Label1') as TCastleLabel;             
end;

Hm, I guess I should have used
UserInterfaceLoad(‘castle-data:/westbeach-gamestateplay.castle-user-interface’ …) instead of DesignUrl.
But what do I have to put as TComponent in interface’, … ?

And trying to load the example you mentioned ‘examples/advanced_editor/’ gives an error?

This gives an error? I have to add a component in ', … but what?

type TLocation = class
  public
    Name: String;
    BackGroundScene: TCastleScene;
    end;
  1. Please do not edit your posts to add substantial information, as you did with “Learning to use the editor by trial and error.” – I do not get a notification about it. Make a new post in thread.

  2. To open the design inside examples/advanced_editor/, you need to first do “Project → Restart Editor (With Custom Components)” as the warning at the bottom says.

    I just improved the dialog box that you posted, to be more friendly in this case, and offer the correct solution. With latest CGE you would see this:

    Zrzut ekranu z 2021-05-20 23-22-22

  3. In general, your hierarchy is not at all what I described in my “proposed hierarchy” a few posts above, Using Designed Components in code (part 2) - #9 by michalis .

    Of course you have the freedom to design it however you want, and I do not know your game requirements/future plans, and I’ll answer your questions about TCastleUserInterface below (though they are probably somewhat unrelated to the actual solution you want)… but it seems you just tried something random. If you don’t have a good reason to do otherwise, please follow my proposed hierarchy from Using Designed Components in code (part 2) - #9 by michalis – I believe this is what you want. What you have now is not what you want. I slightly edited my above post now (with proposed hierarchy), in the hope of making it more clear.

    Do not use TCastleDesign – I should not have described to you this option, it caused confusion. Use only TCastleDesignTransform, as I described in my post Using Designed Components in code (part 2) - #9 by michalis .

    Do not use UserInterfaceLoad. I answer your question about it below, but it is just not an easy API for you. And it loads xxx.castle-user-interface to TCastleUserInterface, while I instead advise you to load xxx.castle-transform to TCastleTransform.

  4. My general advise to you:

    I get that you’re experimenting with things, and you’re stumbling into lots of random troubles. To some extent this is understandable. And I do admit that our API docs, manual and examples are not perfect, it is a work-in-progress, but I encourage to still explore them, there’s lots of examples and information there.

    But overall it feels that you’re trying things at random too much, without understanding why would you use some feature and what it does. Some of your questions are “all over the place” – some things that I answer you are somewhat irrelevant to the original problem you were solving, because while trying to do one thing, in somewhat random way, you stumbled into an unrelated problem.

    Here are some advices:

    • If you are unsure what something does, create a simple project and experiment there with only this 1 feature, in isolation.

    • If you have a simple syntax/compilation problem, do consult the API docs ( Castle Game Engine: Introduction ). All our classes/types and their connections are documented there. You also have the source code of CGE. If you are unsure about how something in classes or type-casting works, read our Pascal guide on Modern Object Pascal Introduction for Programmers . There are other Pascal guides on the Internet that explain these things in more detail too.

    • If you don’t understand what something does, it is generally better to resign from using it, than trying to force it into doing what you want by guessing (and then extending a code/design that you don’t fully understand). This absolutely may mean resigning from using some complicated engine feature. It is better to keep things simple, and more understandable, and in effect the game you make more reliable. For example, maybe you should not really use TCastleDesign or TCastleDesignTransform, despite my initial recommendation on Using Designed Components in code (part 2) - #6 by michalis . That is OK (and much better than trying to use them without fully understanding what they do).

    • The point is: you want to get to a “working application” such you will know why it works (instead of “I tried random things X, Y, Z, and Z worked, so I use Z”). The simpler solution is better, as it is more understandable.

  5. You added TCastleDesign as a child of TCastleViewport, which is why whatever you load there is displayed on top (children are always on top of parent rendering). You can drag things in the editor tree on the left, to change their front/back order and parent. But…

    Please do not try to fix this blindly / by trying random things. It will not lead us to the solution you want. Instead follow my advise from point 3: just do not use TCastleDesign. It is not what you want (probably).

  6. The parameter of UserInterfaceLoad is Owner: TComponent, which is a standard practice in Pascal to denote that you need to provide a component that “owns” (manages memory of) the returned instance. Read Modern Object Pascal Introduction for Programmersfreeing_classes and especially section _ To avoid the need to explicitly free the instance, one can also use the TComponent feature of “ownership”. An object that is owned will be automatically freed by the owner if you’re unsure what it means.

    The owner is useful to easily free the UI instance, and also to search there for components like MyOwner.FindRequiredComponent('NameOfSomething').

    But please follow my advise from point 3: just do not use UserInterfaceLoad. It is not what you want (probably).

Thanks for your tips.
I examined the 'examples/advanced_editor’ and API example stuff on ‘CastleTransform load.’
I did not know there were examples in API; I earlier took a look at the list of API commands but could not find examples how to use them. Now I found one directly following the ‘CastleTransform load’ and it was a very clear example that helped me a lot.

And now I got the hierarchy and transforms right; I know because I got it compiled and it works just as I wanted.
:slight_smile:

procedure TStatePlay.CreateLocation;
var LocationOwner: TComponent;
begin
  LocationOwner := TComponent.Create(FreeAtStop);
  Location := TLocation.Create;
  Location.Transform := TCastleTransform.Create(nil);
  Location.BackgroundScene := TCastleScene.Create(nil);

  Location.Transform := TransformLoad('castle-data:/westbeach.castle-transform', LocationOwner);
  Location.Transform.Add(Location.BackgroundScene);

  MainViewport.Items.Add(Location.Transform);  
end;
1 Like

Cool!

Note that you have a memory leak, as you do:

Location.Transform := TCastleTransform.Create(nil);
...

Location.Transform := TransformLoad('castle-data:/westbeach.castle-transform', LocationOwner);

Thus the result of earlier Location.Transform := TCastleTransform.Create(nil) is lost, and nothing frees it. From what I can see, you can just delete that Location.Transform := TCastleTransform.Create(nil) line.

Ok! :slight_smile:
I did not know it was automatically created when loading a transform.