• 3D
  • Have 3d mouse cursor infront of objects.

I have tried and tried for days now and I cant figure out a way to simply have the mouse cursor have a "3d mouse" or a random 3d object appear infront of another object, or "glide across" a larger. I know there has to be a simple way to do this.

This is what I have done. It does work sometimes, but it will rapidly flash between to positions sometimes, most of the time.

public override void _Input(InputEvent @event)
    {

        var emb = @event;
        if (emb is InputEventMouseMotion)
        {

            var mouse_position = GetViewport().GetMousePosition();
            var from = camera.ProjectRayOrigin(mouse_position);
            var direct_state = GetWorld().DirectSpaceState;

            var collision = direct_state.IntersectRay(GlobalTransform.origin, new Godot.Vector3(0, 0, -distance_from_camera), new Godot.Collections.Array { this.GetParent().GetNode("Player"), this.GetParent().GetNode("Player").GetNode("CollisionShape"), this.GetParent().GetNode("Player").GetNode("CameraRig"), selfy, selfy.GetNode("CollisionShape"), this.GetParent() });
            Transform positionz = this.GlobalTransform;
            var to = from + camera.ProjectRayNormal(mouse_position) * distance_from_camera;
            positionz.origin = to;
            if (collision.Contains("position") && collision.Count != 0)
            {

                var tempV3 = (Godot.Vector3)collision["position"];

                var closeCol = (Transform.origin - tempV3).Length();
                //GD.Print(closeCol + " " + collision["collider_id"] + " " + collision["collider"] + " " + collision["rid"] + " " + collision["position"]);

                if (closeCol <= distance_from_camera * 1.5 && closeCol > distance_from_camera)
                {
                    to = from + camera.ProjectRayNormal(mouse_position) * (distance_from_camera + closeCol + offset);
                    //var to = tempV3;
                    GD.Print("INHERE-1- " + to + " " + closeCol);
                    positionz.origin = to;
                }
                else if (closeCol <= distance_from_camera)
                {
                    to = from + camera.ProjectRayNormal(mouse_position) * (closeCol + offset);
                    //var to = tempV3;
                    GD.Print("INHERE-2- " + to + " " + closeCol);
                    positionz.origin = to;
                }
                else
                {
                    to = from + camera.ProjectRayNormal(mouse_position) * distance_from_camera;
                    //var to = tempV3;
                    GD.Print("sOmeWhErE- " + to + " " + closeCol);
                    positionz.origin = to;
                }
            }
            this.GlobalTransform = positionz;
            //else
            //{
            //    var to = from + camera.ProjectRayNormal(mouse_position) * distance_from_camera;
            //    GD.Print("outthere- " + to);
            //    positionz.origin = to;
            //    return positionz;
            //}
            LookAtFromPosition(GlobalTransform.origin, camera.GlobalTransform.origin, Godot.Vector3.Up);
            Transform.Rotated(new Vector3(0, 1, 0), (float)Math.PI);
        }

@crogaro said: I have tried and tried for days now and I cant figure out a way to simply have the mouse cursor have a "3d mouse" or a random 3d object appear infront of another object, or "glide across" a larger. I know there has to be a simple way to do this.

I have spent quite some with the mouse in a 3D environment, but from what you wrote here I don't really understand what you're trying to do. Could you give an example of the desired outcome?

@Erich_L said:

@crogaro said: I have tried and tried for days now and I cant figure out a way to simply have the mouse cursor have a "3d mouse" or a random 3d object appear infront of another object, or "glide across" a larger. I know there has to be a simple way to do this.

I have spent quite some with the mouse in a 3D environment, but from what you wrote here I don't really understand what you're trying to do. Could you give an example of the desired outcome?

I'll try to upload a video later tonight trying to demonstrate what I'm trying to do, but simply put, I'm trying to make the cursor for a rail shooter. I probably should just do a 3d sprite thats always on the top layer and be done with it instead of doing it this way.

I want a 3d box controlled by moving around the mouse pointer. If it collides with another 3d box, instead of going thru each other, the mouse pointer box will go "infront of" the other box in relation to the camera viewing it. I thought it would be as easy as , "distance from camera -2 " but that was not the case.

I tried another go at it. This is somewhat cleaned up and somewhat works. It messes up if the cursor gets too close to the player, and only works at a specific distance. I don't know what I'm doing wrong.

using System.Numerics;
using Godot;
using System;

public class FollowMouseMovement: Spatial {
  public Godot.Camera camera = null;
  const float distance_from_camera = 15 f;
  public Transform positionz;
  const float RAY_LENGTH = 1000 f;
  public bool isColliding = false;
  public CursorRay CR;
  public Godot.Vector2 mouse_position; // = new Godot.Vector2(0,0);
  public Godot.Collections.Dictionary collision;
  public Godot.PhysicsDirectSpaceState direct_state;
  public Node PlayerNode;
  public float timer = 0 f;
  public float closeCol = 0 f;

  public Node selfy;

  public override void _Ready() 
  {
    selfy = this;
    collision = new Godot.Collections.Dictionary();

    mouse_position = new Godot.Vector2(0, 0);

    camera = (GetParent().GetNode("Player").GetNode("CameraRig").GetNode("InterpolatedCamera") as Godot.Camera);
    PlayerNode = (GetParent().GetNode("Player"));
    positionz = this.GlobalTransform;
    CR = (GetNode("CursorRay") as CursorRay);
    SetAsToplevel(true);
    Visible = true;
  }
  //  // Called every frame. 'delta' is the elapsed time since the previous frame.
  //public override void _Process(float delta) {}
  public override void _Input(InputEvent @event) 
  {
    CR.Transform = Transform;
    CR.ForceRaycastUpdate();
    isColliding = CR.IsColliding();
    if (collision.Contains("position") && collision.Count != 0) 
    {
      var tempV3 = (Godot.Vector3) collision["position"];
      closeCol = (GlobalTransform.origin - tempV3).Length();
    }
    GD.Print(closeCol);
    if (isColliding) 
    {
      GlobalTransform = positionz;
      var from = camera.ProjectRayOrigin(mouse_position);
      var to = (from + camera.ProjectRayNormal(mouse_position) * (10 f));
      positionz.origin = to;
      CR.Transform = positionz;
      Update(CR);

    }
    if (isColliding == false) 
    {
      mouse_position = GetViewport().GetMousePosition();
      positionz.origin = (PlayerNode as Spatial).GlobalTransform.origin * (3 f);
      GlobalTransform = positionz;
    }
  }
  //public override void _UnhandledInput(InputEvent @event)    //{         //GD.Print(collision);    }
  public override void _PhysicsProcess(float delta) 
  {
    mouse_position = GetViewport().GetMousePosition();
    if (timer > .05 f) 
    {
      direct_state = GetWorld().DirectSpaceState;
      collision = direct_state.IntersectRay(Transform.origin, new Godot.Vector3(0, -15 f, -15 f), 
      new Godot.Collections.Array 
      {
        this.GetParent().GetNode("Player"), selfy, selfy.GetNode("CollisionShape"), this.GetParent()
      });
      timer = 0;
    }
    timer = timer + delta;
  }

  public void Update(RayCast ray) 
  {
    // update manually instead only once per frame in process
    ray.ForceRaycastUpdate();
    isColliding = ray.IsColliding();
    //Visible = isColliding;
    GD.Print("INHERE " + isColliding);
    if (isColliding) 
    {
      Godot.Vector3 collisionPoint = ray.GetCollisionPoint();
      Godot.Vector3 collisionNormal = ray.GetCollisionNormal();

      var transform = this.GlobalTransform;
      transform.origin = collisionPoint + collisionNormal * 0.01 f;
      GlobalTransform = transform;

      LookAt(collisionPoint - collisionNormal, GlobalTransform.basis.y.Normalized());
      Transform.Rotated(new Godot.Vector3(0, 1, 0), (float) Math.PI);


    }
  }
}

In the video inside this zip file you can see what I want it to do, and what it kind of already does. It Only works well in the most ideal situations. If I move the mouse too far out as you see in the video, you can see the cursor not really being part of the 3d object anymore.

Alright I think I get it, you're trying to design a FPS where there's two modes for mouse movement? I'm guessing you want the mouse to be able to switch from being able to direct the players camera to be able to aim a weapon. It's interesting but as to the mechanic itself I'm sure there's a reason I've never seen anything like it in FPS games. Tell me if I understood you right.

As for "messing up near the player" makes sure the player's nodes aren't "input ray pickable".

I tried not to, but I did look at your code a bit. It looks like you're trying to get this done from a mathematical point of view, when IMO in this case it might be better to just let the engine take care of that for you.

Have your game objects forward this function to your targeting node: func _on_Area_input_event(_camera, event, click_position, click_normal, _shape_idx): That way each object can just send the targeting node this very useful information: event, click_position, _click_normal That click position should be in 3D, you can check for mouse motion like this: if event is InputEventMouseMotion:

Then do something like if mouseTargeterActive: adjustPositionOfTargeter(click_position,click_normal)

Remember there in my code there's a _ before _camera and _shape_idx just because I'm not currently using them.

6 days later

Well its basically a rail shooter where the players avatar is also on screen. Ideally, the player has to try to maneuver their character as well as aim and shoot, but its fixed on a two day plain. Just Left, right, and maybe jump. With the enemy coming infront of the player toward the avatar.

I will try you advise and make the engine do it for me. It does sound a lot easier.