MouseRayHit not updating while dragging

I have a MouseMoveEvent defined. I am checking it when the right mouse button is down (set in the press handler). I want to be able to see my road as I drag it from the startpoint.
But when this MouseMove event is called, the RayItems from MouseRayHit have the same point as the press point. As I move the mouse, the values don’t change. So it doesn’t seem like MouseRayHit is updating with every mouse move, but only when the button is pressed. My release handler is also only getting the same point as the press point.

procedure TViewPlay.MouseMove(const Sender: TCastleUserInterface;
                              const Event: TInputMotion; var Handled: Boolean);
 var rayitems : TRayCollision;
     c, i : integer;
     Itemhit : TCastleTransform;
     Point : TVector3;
 begin
   Handled := false;
   if right_drag and buildingroad then
    begin
      RayItems := MainViewport.MouseRayHit;
      c := RayItems.Count;
      for i := c - 1 downto 0 do
         begin
          ItemHit := RayItems[i].Item;
          IF ( ItemHit is TTerrainTile ) then
           begin
             Point := RayItems[i].Point;
             Notifications.Show( format( 'dragging %f, %f', [Point.x, Point.z]));
//             AddRoad(TTerrainTile( ItemHit ), Point );
             Handled := true;
           end;
         end
    end;
 end;                     

Thoughts? I haven’t updated to the engine that was just posted yet.

I switched to overriding the Motion method and am calling the inherited, but still the point values aren’t updating.

function TViewPlay.Motion(const Event: TInputMotion): boolean;
 var rayitems : TRayCollision;
     c, i : integer;
     Itemhit : TCastleTransform;
     Point : TVector3;
 begin
   result := inherited Motion( Event );
   if right_drag and buildingroad then
    begin
      RayItems := MainViewport.MouseRayHit;
      c := RayItems.Count;
      for i := c - 1 downto 0 do
         begin
          ItemHit := RayItems[i].Item;
          IF ( ItemHit is TTerrainTile ) and
             ( not ( csTransient in ItemHit.ComponentStyle )) then
           begin
             Point := RayItems[i].Point;
             Notifications.Show( format( 'dragging %f, %f', [Point.x, Point.z]));
//             AddRoad(TTerrainTile( ItemHit ), Point );
             Result := true;
           end;
         end
    end;
 end;                                                                                      

I got it to work by adding a call to MainViewport.Motion( Event ); which updated the MouseRayHit.

Thanks, I can reproduce the issue.

  • Created new project from “3D FPS Game” template

  • To TViewPlay.Update I added there

    if MainViewport.TransformUnderMouse <> nil then
      LabelInfo.Caption := MainViewport.TransformUnderMouse.Name
    else
      LabelInfo.Caption := 'Nothing under mouse';
    

    (The TransformUnderMouse value is derived from MouseRayHit.)

  • When I run, indeed the MainViewport.TransformUnderMouse.Name remains unchanged if I keep pressing left mouse button and moving the mouse.

The value is updated correctly if I don’t press any mouse button or press the right button. I have one idea how it can go wrong (the navigation class may set “Motion” event to “handled” (returns true) and then it would not be passed to other controls). I’ll see how to solve it in a way that seems “clean”.

Note: The ultimate solution will also be new navigation classes (that will not mark “Motion” as handled, they will be attached to TCastleTransform) – we work on them now with Andrzej Kilijański.

But in the meantime, I will also want to fix it for existing navigation classes.

I’ll let here know when it’s fixed!

Oh, I’ve just realized we’ve had this bug very long ago - when Window had SceneManager attached to it and it tried to do Mouse Look in this situation.

I pushed a commit that fixes it, alongside some other improvements. So

  • MouseRayHit is now updated always, period. Even if you move the mouse and hold some button. And even if you don’t move the mouse! This fixes also the case when you don’t move mouse (or even camera) but something “walks in front of you”, e.g. a creature walks and takes position under camera cursor.
  • Also, internally MouseRayHit is calculated on-demand, but with a flag that it is “valid” until next update. So the above change does not cause any more overhead for games that actually don’t access MouseRayHit (or TransformUnderMouse). And for games that access it, using MouseRayHit (or TransformUnderMouse) multiple times e.g. in one Update makes no additional overhead.
  • Also TransformUnderMouse is now only a shortcut to MouseRayHit.Transform, makes API a bit more flexible.
2 Likes