How do I get my 3d Camera to loosely follow the mouse?

Using Godot 4.6.2

Hey forum, I am a novice in Godot and coding in general; I’m an artist making their own game. I am making a fnaf-like game, where the camera would only be at dedicated locations/angles and the player can’t fully control their view. For the sake of making the game feel smoother, I want to have the 3D Camera follow the movement of the mouse, but not have the mouse locked to the center of the screen. Essentially, I want the camera to lag behind the mouse’s position but still follow it only to clamp at a certain point (A good example for the type of camera and game format I am talking about would be a fnaf fan game called Five Nights at Frickbear’s 3). I have looked up things for help but have struggled a lot to understand what I could do and why what I have been doing was not working at all.

To elaborate on my attempts; I have tried using raycasting, but when people use that they tend to get the mouse position by having a raycast hit an object to get the location of the mouse to tell the camera where it is when the player clicks. I want the position to be constantly updating even while no inputs are being put in besides mouse movement if needed. I have tried the idea of having the 3d camera follow a 2d camera because 2d has more dedicated code, get_mouse_position(), to handle that tracking, but I found no way to have the two connect. I have been kind of banging my head at the wall trying to figure out this camera movement, I am sure I tried more things but they did not work either.

So do I just want someone’s code? Sort of? But I want to understand what it all means. I want to learn and not just being given things, hence why I don’t use LLM’s. I am hoping someone out there can help me, thanks forums :slight_smile:

extends Camera3D

@onready var raycast = $RayCast3D
var mouse_position : Vector2

func _process(delta: float) -> void:
		mouse_position = get_viewport().get_mouse_position()
		raycast.target_position = project_local_ray_normal(mouse_position) * 100
		raycast.force_raycast_update()
		if raycast.is_colliding():
			print(mouse_position)
			print("working")
			print(raycast.get_collider().get_parent())

I am putting this code here to show what language I am using, as well as show what types of methods I have been trying. I ask you try not to use this code as a jumping point as it is most likely failing to do what I want anyways. (also since this isn’t my code it’s from this video https://www.youtube.com/watch?v=bpNckNreSd8&t=469s)

What exactly do you mean by “follow the mouse”? Rotating the camera? Changing its position depending on local X and Y axes?

In both cases, you want the mouse’s position relative to the center of the viewport. You don’t need raycasts for this.

var mouse_position_from_center: Vector2 = get_viewport().get_mouse_position() - get_viewport().size / 2.0

You should also use some kind of normalization on this, otherwise viewport size would affect rotation/movement speed. There are different ways to do this, depending on the behavior you want. For example:

# normalizes X and Y independently towards the borders of the viewport:
var normalized_mouse_position: Vector2 = (mouse_position_from_center / Vector2(get_viewport().size) * 2.0).clampf(-1.0, 1.0)

# normalizes in a circle shape:
var normalized_mouse_position: Vector2 = (mouse_position_from_center / min(get_viewport().size.x, get_viewport().size.y) * 2.0).limit_length(1.0)

I believe that they mean it will move toward where the mouse is but not snap to it. I am just gonna spitball but maybe you could make a cube follow a mouse and make a characterbody2d move toward that cube?

Are you implying I essentially make a faux mouse that the player would use that is in the 2d portion of the scene? I tried doing something similar (I even mention it in the original post), but I don’t think I tried exactly what you are saying. My one fear with this idea is not having the faux mouse be as precise as the normal one causing delays between player input and reaction. (Not to mention I kind of don’t know where or how to start going about this coding wise :\)

I do not want the mouse to be at the center of the screen. I want it to be moveable, actionable in the MOUSE_MODE_CONFINED state so the player can click things and move over areas on the screen to hit the “turning points” aka 2D hitboxes that detect when the mouse is in them that will change the camera’s angle to view something specific. A good example of that being like turning around to look at the bed in Fnaf 4.

Can you link a video of that?

Yes but it does have its flaws. But stay at it and you will get it. I believe in you!!!

https://youtu.be/A0mrtF5gD4A?si=rewYGzelWicRn5Gi&t=573 | I hope this is time stamped right but an example would be a 9:33. Reminder, I was only referring to how I intend the camera to move to specific angles. Typically, fnaf games are made in 2D using 3D renders for the visuals, but under the hood everything is done with invisible 2D collision boxes looking for the player’s mouse so it can transition to the correlating position. I am not necessarily looking for how to do that, I was even able to do so in a primitive way using this code:

extends Node3D

@export var right = true
@export var left = true
@export var center = true

func _process(delta: float) → void:
if left == true:
if right == true:
center = true
if left == false:
if right == false:
center = true
if center == true:
left = true
right = true

func _on_area_l_mouse_entered() → void:
if left == true:
center = false
left = false
$“../Camera3D”.rotate_y(45)

func _on_area_r_mouse_entered() → void:
if right == true:
center = false
right = false
$“../Camera3D”.rotate_y(-45)

what I am looking for is the ability for the 3D camera to follow the mouse around but lag behind. Essentially, it will give the player the ability to look around while at that set angle, but not fully turn their head.

the undoubted best example of the camera movement I am looking for is in Tealerland https://youtu.be/orURh1iAESg?si=oFHwXPfQIJqma0dP&t=228 | This game also is made in 2D using 3D renders. I am not using 3D renders, I want things to be done in real-time.

I don’t see how 9:33 shows what you describe. Beside everything being in the dark most of the time, there’s no camera following the mouse in any way. You’ll need to give a better description of what exactly you want to achieve, or provide a visual mockup.

Please check my most recent response. Also, I mentioned in that post that what I was showing was just how camera positioning would be done in my game. I am more focused on how with a 3D camera you could perform camera movement like in this video https://youtu.be/orURh1iAESg?si=oFHwXPfQIJqma0dP&t=228

So it’s a mouselook around some specific look direction with a constrained look angle?

you’ve got it! at least I think you do

To clarify further; The mouse pointer is visible and when it is at the screen center, the camera looks into some nominal direction. When the pointer is farthest away from the screen center the inclination from that nominal direction is maximal?

I thought you wanted a camera 2d

I honestly am not too familiar with how technical you are being but I think yes. The camera is on one focused spot, but as the player moves their mouse towards the edges of the screen the camera will drag towards the mouse, but not actively turn around.

not to sound like a jerk, but it says 3d Camera in the discussion post title

What do you mean by “not actively turn around”. It must turn, otherwise nothing happens. The last example you posted turns the camera.

I mean, if they move their mouse to the left, they shouldn’t turn a full 90, 180 degrees. Only if they hit the trigger that will happen, not just move the mouse. Frickbears3 wasn’t the best example I will admit. It was more an example of showing how loose the mouse was and how the camera followed behind it while in a 3D game.

  • store initial camera basis (when the camera is centered)

On every frame:

  • calculate the x and y mouse pointer offset from the screen center
  • rotate initial camera basis around its y and x axes depending on pointer offset

That’s pretty much it.