Transformundermouse not working in scenes created in code?

Transformundermouse detection of scenes work okay when I create scenes in the editor but when I create scenes in code they seem not to be recognized. Do I need additional code to get this working?
(the scenes are displayed allright in the viewport).

There isnā€™t any internal difference between scenes created from code and created in editor. From code, you can set all the same properties as you can in editor, and then the scene is really exactly the same thing.

So, it should workā€¦

I know I have already some other pending things related to our threads ( Convenient way to determine exact point under mouse - #18 by Carring ). But for this, Iā€™d also have to see a testcase to reproduce the problem.

Ok. Here is a stripped down version of the code.
Moving the mouse pointer over the scenes created in the editor displays their scene name but not when the mouse pointer is moved over the 2 avatars created in code, their scene name is not showed.

Rescue Island-test.zip (94.7 MB)

Any news on this and my other pending questions and testcases?

Sorry for the lack of response for such a long time! I was buried in lots of CGE tasks ā€“ and today Iā€™m finally getting back to resolve various pending questions from the forum.

Thank you for the testcase to reproduce, the issue in this case is simple: By default the Name is equal to '' (empty String). If you want to see different names, just assign them.

So, the detection in Viewport.TransformUnderMouse is OK, itā€™s just that the code

    Label1.Caption := Viewport.TransformUnderMouse.Name;

ā€¦ was sometimes setting Label1.Caption to an empty string. Simply set Name, replacing

  face_southwest := TCastleScene.Create(face_southwest);
  face_southeast := TCastleScene.Create(face_southeast);

ā†’

  face_southwest := TCastleScene.Create(face_southwest);
  face_southwest.Name := 'face_southwest';
  face_southeast := TCastleScene.Create(face_southeast);
  face_southeast.Name := 'face_southeast';

Note that nothing forces you use the same name as variable name. Itā€™s a useful convention, but you could as well do

  face_southwest := TCastleScene.Create(face_southwest);
  face_southwest.Name := 'SomethingSomething';
  face_southeast := TCastleScene.Create(face_southeast);
  face_southeast.Name := 'SomethingElse';

ā€¦ and it will also work. As long as all names (within given owner) are unique (except empty names which donā€™t need to be unique) it is OK.

In more details, the difference between instances designed in editor and created by code:

  • When you load the design created in the editor, it sets the Name to the one you set in editor. The design file (like .castle-user-interface) contains these names.

  • When you create the TCastleScene (or really any other TComponent) instance from code, the Name is initially empty. You need to set it, to do the same thing that loading the design created in editor is doing.

    At runtime, the compiler doesnā€™t even know that you assign it to variable name face_southwest (the local variable names, or non-published fieldsā€™ names, are not even present in the compiled executable), so it cannot set this. Also you could assign an instance to multiple variables, or change it between variablesā€¦ so thereā€™s no ā€œautomatic Nameā€ when you create instances using code.

P.S. To avoid seeing empty names, even if you forget to set them, you can consider displaying more information about the scene.

Change:

Label1.Caption := Viewport.TransformUnderMouse.Name;

ā†’

Label1.Caption := Format('Name: %s' + NL +
  'ClassName: %s' + NL +
  'Pointer: %s', [
  Viewport.TransformUnderMouse.Name,
  Viewport.TransformUnderMouse.ClassName,
  PointerToStr(Viewport.TransformUnderMouse)]);

Add to the uses clause:

  • CastleUtils for NL (newline)
  • CastleStringUtils for PointerToStr

Thatā€™s maybe even more than you want to see:), but itā€™s bound to display something useful, even if you forget to set some name :slight_smile:

P.S. As we make label taller, make sure to anchor it to top:

Many thanks for this and the useful suggestions ; the label caption format you use here also gave me an ā€œAha!ā€

Ok, now I get the name of the scenes displayed but I actually want to use the name of the Transform instead, not the scene but it is not shown. It looks like TransformUnderMouse is actually ā€˜SceneUnderMouse.ā€™ :wink:
I want the Transform name to be the characters name.

I have this (where firstname is a string as argument).
Scene Name works but not Transform name:

constructor TAvatar.Create(firstname: string);
begin

  Personalia := TPersonalia.Create;

  Personalia.FirstName := firstname;

  Transform := TCastleTransform.Create(Transform);

  face_west := TCastleScene.Create(face_west);
  face_north := TCastleScene.Create(face_north);
  face_east := TCastleScene.Create(face_east);
  face_south := TCastleScene.Create(face_south);
  face_southwest := TCastleScene.Create(face_southwest);
  face_southeast := TCastleScene.Create(face_southeast);
  face_northwest := TCastleScene.Create(face_northwest);
  face_northeast := TCastleScene.Create(face_northeast);
  walk_west := TCastleScene.Create(walk_west);
  walk_north := TCastleScene.Create(walk_north);
  walk_east := TCastleScene.Create(walk_east);
  walk_south := TCastleScene.Create(walk_south);
  walk_southwest := TCastleScene.Create(walk_southwest);
  walk_southeast := TCastleScene.Create(walk_southeast);
  walk_northwest := TCastleScene.Create(walk_northwest);
  walk_northeast := TCastleScene.Create(walk_northeast);

  Transform.Add(face_west);
  Transform.Add(face_east);
  Transform.Add(face_north);
  Transform.Add(face_south);
  Transform.Add(face_southwest);
  Transform.Add(face_southeast);
  Transform.Add(face_northwest);
  Transform.Add(face_northeast);
  Transform.Add(walk_west);
  Transform.Add(walk_east);
  Transform.Add(walk_north);
  Transform.Add(walk_south);
  Transform.Add(walk_southwest);
  Transform.Add(walk_southeast);
  Transform.Add(walk_northwest);
  Transform.Add(walk_northeast);

  face_southwest.name := Personalia.FirstName; // this works
  Transform.Name:= Personalia.FirstName;  // transform name is not shown

  ViewMain.Viewport.Items.Add(Transform);      
```

TCastleScene, as various other classes, is a descendant of TCastleTransform. See Viewport with scenes, camera, navigation | Manual | Castle Game Engine ā€“ " 1.3. TCastleTransform descendants".

So TransformUnderMouse returns the TCastleTransform descendant at the deepest point of the hierarchy, underneath the mouse.

I guess you want the parent of it ā€“ it is simplest to just use Parent property then, like

if (Viewport.TransformUnderMouse <> nil) and
   (Viewport.TransformUnderMouse.Parent <> nil) then
  Label1.Caption := Viewport.TransformUnderMouse.Parent.Name;

Thanks, this is exactly what I needed. :slight_smile:

1 Like