Reversing the direction of a clamp()

Godot Version

4.6.2.stable

Question

This was a re-upload because I don’t think I knew what it was well enough before, so I tried doing a bit more bug fixing. I found that the z direction of the neck is reversed, or something like that. The clamp() that I am trying to use to allow you to look forward from -x to x is instead going in reverse, so I can look between those same max and min, but instead of facing forward I am facing backwards.

I tried looking for a way to just use the other side of the clamp() but it seems more complicated than I thought. Another detail is that the max and min of this clamp need to rotate, because this clamp is tied to a vehicle so you can only look forwards, and the vehicle needs to rotate.

func _unhandled_input(event: InputEvent) -> void:
	
	#Capturing a mouse means it isn't visible and can't be seen
	if event is InputEventMouseButton:
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	elif event.is_action_pressed("ui_cancel"):
		Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
	
	if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
		if event is InputEventMouseMotion:
			Neck.rotation_degrees.y += (-event.relative.x * 0.5)
			Head.rotation_degrees.x += (-event.relative.y * 0.5)
			
            Neck.rotation_degrees.y = clamp(Neck.rotation_degrees.y, -80, 80)
			Head.rotation_degrees.x = clamp(Head.rotation_degrees.x, -45, 45)
			

This code is what I used to make the camera follow the neck/head smoothly, the comment is what I will hopefully be able to replace the global position one, but I was trying to limit variables.

print("Head y rotation:",Head.rotation_degrees.y," Neck y rotation:",Neck.rotation_degrees.y," Vehicle y rotation:",rotation_degrees.y)
Camera.global_position = lerp(Camera.global_position,Head.global_position,follow_speed)
	Camera.global_rotation = Vector3(Head.global_rotation.x,Neck.global_rotation.y,Head.global_rotation.z)
	#Camera.global_rotation = Vector3(lerp_angle(Camera.global_rotation.x,Head.global_rotation.x,LOOK_SPEED),lerp_angle(Camera.global_rotation.y,Neck.global_rotation.y,LOOK_SPEED),lerp_angle(Camera.global_rotation.z,Head.global_rotation.z,LOOK_SPEED))

Im not too sure about what the problem is.

Does the clamp sometimes reach the correct end position but take a path there you dont want? Like going to -80 from +80 by adding +1 until it wraps around to negatives instead of by adding -1 until at the correct angle?

I would look closer here:

if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:

	if event is InputEventMouseMotion:

		Neck.rotation_degrees.y += (-event.relative.x \* 0.5)

		Head.rotation_degrees.x += (-event.relative.y \* 0.5)

Looks like you always make it move in the same direction. Not right if already left or left if already right.

I don’t really understand the movement code perfectly, but without a clamp() for the y it seems to rotate fine, removing a negative just reverses the direction, so it just inverts the controls.

I followed this tutorial for the character controls:

I made an image to describe it better, but I cant add it here. The camera is able to move from -45 to 45 like the clamp shows, but if 0 is forwards, it moves across 180 to loop around. I was under the assumption you needed a wrapf() to do this so I don’t really know what was going on but everything is working fine except for inverted clamp().

Shouldn’t you be printing head’s x rotation here, not y rotation.

Oops, yeah I should have done that, though the up/down movement that the head is doing isn’t the problem, I can try to test the results with the updated print() but I don’t think it will be too helpful.

It’ll let you see the range you might want to clamp to.

You can use remap to map an input to an output

var x := clampf(Head.rotation_degrees.x, -45.0, 45.0)

Head.rotation_degrees.x = remap(x, -45.0, 45.0, 45.0, -45.0)

Also your rotation is a float so I’d recommend using clampf.

Another detail is that the max and min of this clamp need to rotate, because this clamp is tied to a vehicle so you can only look forwards, and the vehicle needs to rotate.

You can handle this two ways:

  1. Adjust your rotation value by the amount your rotated

  2. Do the rotation in local space instead of global space.

I ended up fixing it using:

	if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
		if event is InputEventMouseMotion:
			Neck.rotation_degrees.y += (-event.relative.x * 0.5)
			Head.rotation_degrees.x += (-event.relative.y * 0.5)
	
			if Neck.rotation_degrees.y <= -280.0: Neck.rotation_degrees.y = -280.0
			if Neck.rotation_degrees.y >= -80.0: Neck.rotation_degrees.y = -80.0
			Head.rotation_degrees.x = clampf(Head.rotation_degrees.x, -45, 45)

I just printed out the Neck rotation and saw -180 is forwards so I made my own clamp() around that, but thank for the help, I hope I won’t need it but this forum seems helpful!

You can replace

			if Neck.rotation_degrees.y <= -280.0: Neck.rotation_degrees.y = -280.0
			if Neck.rotation_degrees.y >= -80.0: Neck.rotation_degrees.y = -80.0

with

			Neck.rotation_degrees.y = clampf(Neck.rotation_degrees.y, -280.0, -80.0)

Your old code (Neck.rotation_degrees.y = clamp(Neck.rotation_degrees.y, -80, 80)) limits the value to the range from 0-80 to 0+80, the new code limits it to the range from -180-100 to -180+100