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 otherTComponent
) instance from code, theName
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
forNL
(newline) -
CastleStringUtils
forPointerToStr
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
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.ā
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.