Clicking on loaded models?

I have moved from water and trees to animals. I found some simple low poly rigged & animated animals and added them. The are loaded as TCastleScene objects with pickable set to true. However they don’t register my clicks like other pickable objects do. So I am unable to select them. What am I missing? Maybe they should be loaded into a different class to be interactive?

Hm, any TCastleScene should be clickable without any issue, if it has Pickable (default true).

Note that by default PreciseCollisions is false, which means the scene collides as a bounding box. Set PreciseCollisions to true to make the collisions follow the mesh (but it only really makes sense for non-animated models).

Idea 1: Make sure you set PreciseCollisions to true on your terrain. (TCastleTerrain.PreciseCollisions). Otherwise the terrain box will “capture” all clicks within it.

Idea 2: Test if your models detect clicks OK by substituting them for models in examples/viewport_and_scenes/detect_scene_hit/ .

If the above doesn’t help, I’ll need to see a testcase to debug it more :slight_smile:

The hexagon didn’t work either. The problem was in my click handler. I was filtering an item if the item ‘is’ TCastleScene but that was including my TAnimalGraphics which inherit from that. I will have to adjust the filter to be more precise. Thanks for the clue.

1 Like

I was doing this filtering because it seems like adding one object like a TCastleCylinder to another one (ie adding a child) creates a ‘ghost’ TCastleScene (I presume to join them together into one thing) that shows up in the ray collision list. If I try to make that TCastleScene not pickable then it makes the the object and its child unpickable too. All my objects have their own classnames. So I am filtering by classname instead of using IS. But this still seems clunky. Maybe there is a better way?

Some CGE components indeed create internal children. In particular, TCastleCylinder creates an internal TCastleScene that actually “does the job”.

In general you should not pay attention to these internal scenes. You also should not change their properties directly, e.g. you should not change the Pickable on that internal TCastleScene – we don’t guarantee what happens there, how it relates to TCastleCylinder.Pickable. Only manipulate on things using TCastleCylinder properties.

The TCastleViewport.TransformUnderMouse does not return such internal scenes. The TCastleViewport.MouseRayHit returns them – you can ignore them checking csTransient in SomeChild.ComponentStyle.

As for how to best filter – I’d need to see exact example of your setup. I guess you use MouseRayHit and determine hit scene from it? Then ignore the scenes with csTransient. E.g. TransformUnderMouse is implemented like this:

function TCastleViewport.TransformUnderMouse: TCastleTransform;
var
  I: Integer;
begin
  if MouseRayHit <> nil then
    for I := 0 to MouseRayHit.Count - 1 do
    begin
      Result := MouseRayHit[I].Item;
      if not (csTransient in Result.ComponentStyle) then
        Exit;
    end;

  // Return nil if all items on MouseRayHit list are csTransient, or MouseRayHit = nil
  Result := nil;
end;

So it literally searches MouseRayHit, and returns first TCastleTransform that is not internal (doesn’t have csTransient flag).

For some other hints how to use MouseRayHit see Tiled maps | Manual | Castle Game Engine .

Great information, thanks!!