Problem with TransformUnderMouse

I am trying to use Viewport.TransformUnderMouse (in 2D environment).

When it finds TCastleScene object (just containing image) it returns the object and works fine.

But when the found object is of any other class for example TCastleImageTransform or TCastlePlane then the returned object’s Name parameter returns empty string and changing its parameters gives no effect.

Are there any extra steps needed to access TCastleImageTransform object returned from Viewport.TransformUnderMouse? I am using Lazarus and FPC 3.2.2 on Windows 10.

It was a bug – your expectation was right, TransformUnderMouse should return just TCastleImageTransform or TCastlePlane instance.

Aaand… fixed, thank you for reporting!

I committed and pushed the fix ( TransformUnderMouse returns first non-csTransient instance · castle-engine/[email protected] · GitHub ) to “master” branch of CGE on GitHub, GitHub - castle-engine/castle-engine: Cross-platform (desktop, mobile, console) 3D and 2D game engine supporting many asset formats (glTF, X3D, Spine...) and using modern Object Pascal . Within ~6 hours it will be automatically published in our downloads on Download | Castle Game Engine .

Background what was wrong: the TCastleImageTransform and TCastlePlane actually create an internal TCastleScene instance, and place it as “hidden” child of themselves. It is “hidden” just by setting the flag csTransient is ComponentStyle – so it’s hidden in inspector/editor, but otherwise all the code processes it is a regular child. And in this case, TransformUnderMouse was returning you this internal scene instance – it was indeed unnamed, and trying to modify it could have all sorts of weird effects (as parents like TCastleImageTransform and TCastlePlane treat it as internal to them).

I reproduced the problem in 3D, tweaking examples/viewport_and_scenes/detect_scene_hit. Screenshots after fixing attached :slight_smile:


1 Like

@michalis Is there any cge documentation how to use TransformUnderMouse?
Up until now I use a TCastleScene sprite image that is ‘locked’ to the mouse coordinates to collide with other objects.

And how can I hide the standard mouse cursor?

This my cge design tree:
Clipboard01

Hiding the mouse cursor in Viewport (Viewport.Cursor:=mcNone) or ImageTransform does not hide the mouse, only when I set it in design property of Group1 but I want to turn it on and off while running the game code but then Group1.cursor := mcNone; is not recognised?

See API docs – Castle Game Engine: CastleViewport: Class TCastleViewport and the example I mentioned above, examples/viewport_and_scenes/detect_scene_hit. There isn’t that much to document, I hope the name is mostly self-explanatory :slight_smile: It intuitively returns the current TCastleTransform under the mouse (or last touch position, on mobile).

I wanted to ask to create new topics for new questions :slight_smile: But this happens to be related :slight_smile:

The algorithm to adjust cursor is:

  1. If you hover over a UI control that is not TCastleViewport, then the TCastleUserInterface.Cursor value of the (deepest, i.e. child) UI control determines the mouse cursor. See Castle Game Engine: CastleUIControls: Class TCastleUserInterface

  2. Over TCastleViewport, it’s a bit special. Setting TCastleViewport.Cursor is currently just ignored and instead the TCastleViewport.Cursor is actually automatically overridden each frame following this trivial algorithm:

    T := TransformUnderMouse;
    if T <> nil then
      Cursor := T.Cursor
    else
      Cursor := mcDefault;
    

    So we use TCastleTransform.Cursor from the TransformUnderMouse. Or mcDefault if TransformUnderMouse is nil.

I don’t like much the AD 2 part – it is admittedly unexpected, makes the explanation more complicated than it should be. Maybe in the future we will just deprecate TCastleTransform.Cursor and let your code control TCastleViewport.Cursor explicitly.

And to give a more straightforward solution: There is Container.OverrideCursor property, that (when not mcDefault) overrides the whole algorithm I described in the previous post.

So if you just want to always hide cursor, just set Container.OverrideCursor := mcNone.

And if you’re looking for ways to implement custom cursor – see example examples/user_interface/custom_cursor :slight_smile:

I don’t get it?

Ah, that’s a trap I hope to remove at some point. The Container property of TUIState is set after Start method has finished working (because only then the TUIState is UI child of container).

Long story short: if you write code inside Start method, use StartContainer instead of Container. So

StartContainer.OverrideCursor := ...

will work.

And yes, I hope to remove this “trap” at some point. Unfortunately the decision “how” is not easy – while it’s not intuitive that Container is not initialized here, but it is consistent with how UI children are initialized.

Done! I mean, I have fixed CGE to make Container work in Start intuitively. So if you use latest CGE (I pushed the fix to GitHub master, it will be available in binary downloads in ~6 hours) then your

Container.OverrideCursor := ...

will just work. Until then, my workaround

StartContainer.OverrideCursor := ...

is of course also still valid.

1 Like

I just installed latest CGE but I still get this:

If I alternate try StartContainer.OverrideCursor it is not recognised so I guess this is okay because you replaced it with Container.OverrideCursor?
I also tried Container.OverrideCursor in other procedures than Start but with the same error.
Are you sure it is in latest CGE?

Ups, it should be StateContainer not StartContainer, sorry. StateContainer.OverrideCursor := ... will work.

See API docs of TUIState: Castle Game Engine: CastleUIState: Class TUIState .

Ah, binary version didn’t build to the end, because of server maintenance I did last night. It will be available in ~6 hours from now.

You can check looking at Release Latest release of Castle Game Engine (Auto-Updated Snapshot) · castle-engine/castle-engine · GitHub – right now it shows " 1 commit to master since this release" and you can click on “1 commit” and see that the missing commit is exactly the one fixing it.

Note that I didn’t remove StateContainer, it remains available.