0 votes

Hello! This is my first post on here so I apologize if this is the wrong place to ask this or I've omitted any important information.

I have a 3D third-person camera setup with a camera, a spring arm and a spatial I've designated camera_pivot. what I'm trying to do is create a camera system where when you look down, the camera pivot rotates along the X axis to make the camera move upward to get a bird's eye view, but when you look up, the pivot remains stationary and only the camera rotates. Put more simply, the camera moves up when you look down, but it doesn't move down when you look up.

To achieve this, I've tried using an if statement so that if the camera's X rotation is at 0 degrees or below, only the camera rotates, but if it's above 0, the camera pivot rotates.

var min_camera_rot : float = 0
var max_camera_rot : float = 90
var min_pivot_rot : float = -45
var max_pivot_rot : float = 0

#(Irrelevant code omitted)

func _input(event):
    if event is InputEventMouseMotion:
        rotation_degrees.y -= event.relative.x * mouse_sensitivity

        if camera.rotation_degrees.x <= 0:
            camera.rotation_degrees.x -= event.relative.y * mouse_sensitivity
            camera.rotation_degrees.x = clamp(camera.rotation_degrees.x, min_camera_rot, max_camera_rot)
        else:
            camera_pivot.rotation_degrees.x -= event.relative.y * mouse_sensitivity
            camera_pivot.rotation_degrees.x = clamp(camera_pivot.rotation_degrees.x, min_pivot_rot, max_pivot_rot)

But this results in the camera pivot rotating, but clamping at 0 degrees and not handing rotation off to the camera like it's supposed to.

I've also considered making the if statement check whether camera is at a higher global y position than camera_pivot, but I couldn't get that to work either.

Godot version 3.4.2
in Engine by (22 points)

1 Answer

+1 vote
Best answer

I don't know if this will completely solve your problem, but I should point out something about the following bit:

var min_camera_rot : float = 0
var max_camera_rot : float = 90
var min_pivot_rot : float = -45
var max_pivot_rot : float = 0
# ...
func _input(event):
    if event is InputEventMouseMotion:
        rotation_degrees.y -= event.relative.x * mouse_sensitivity
        if camera.rotation_degrees.x <= 0:
            camera.rotation_degrees.x -= event.relative.y * mouse_sensitivity
            camera.rotation_degrees.x = clamp(camera.rotation_degrees.x, min_camera_rot, max_camera_rot)
        else:
        # ...

The inner if block checks the camera's local rotation. This means that camera.rotation_degrees.x will never be less than 0 (since it gets clamped to 0 whenever it's negative), and if it ever goes above 0 then the code will just start jumping to the else block, at least until something sets it back to 0 or less. As a result, as soon as the camera.rotation_degrees.x turns positive, the camera will never turn again.

I'm not exactly sure if this works in your case, but I would suggest removing the if block and instead using something like:

const min_camera_rot : float = 0
const max_camera_rot : float = 90
const min_pivot_rot : float = -45
const max_pivot_rot : float = min_camera_rot

# this records the actual x rotation that the camera should be pointing along
var view_rot_x : float = 0.0
# ...
func _input(event):
    if event is InputEventMouseMotion:
        rotation_degrees.y -= event.relative.x * mouse_sensitivity
        view_rot_x -= event.relative.y * mouse_sensitivity
        # no need for conditional here, just set and clamp both
        camera_pivot.rotation_degrees.x = clamp(view_rot_x, min_pivot_rot, max_pivot_rot)
        camera.rotation_degrees.x = clamp(view_rot_x, min_camera_rot, max_camera_rot)

This is effectively equivalent to an if block: "if the view's x rotation should be below 0, then lock the camera's rotation and rotate the pivot; otherwise, rotate the camera but don't touch the pivot."

Note that I usedmax_pivot_rot = min_camera_rot since I assume that you wouldn't want any intersection in their ranges, and I also set them to constants, but of course those details depend on your intent. If you do want some range with intersection, you should be careful to split the total rotation between the two, or else the view would turn twice as fast in that range.

by (109 points)
selected by

Thank you so much for your help! I had to add a clamp to viewrotx to fix a bug, but after that, everything is working perfectly!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.