Limit rotation of bone in gdscript

Godot Version

4.2.1

Question

I’m making an open source 3d fps game, and replacing a capsule with a 3d model, the problem I’m having is I can’t find a reliable way to keep the bone from rotating in the x axis too far.
repo

Code

func _input(event):
	if event is InputEventMouseMotion:
		rotate_y(deg_to_rad(-event.relative.x * mouse_sensitivity))
		# Get the current pose of the bone
		var bonePose = skel.get_bone_global_pose(17)
		# Save the original position
		var original_position = bonePose.origin
		# Define the rotation axis as the X axis
		var axis = Vector3(1, 0, 0)
		# Define the rotation angle based on relative.x
		angle = event.relative.y * mouse_sensitivity * VERTICAL_sensitivity
		#angle = clamp(angle, deg_to_rad(-0.671), deg_to_rad(0.265)) # this dose not work
		# Apply the rotation to the pose
		bonePose = bonePose.rotated(axis, angle)
		# Reset the position to the original one
		bonePose.origin = original_position
		# Set the new pose of the bone
		skel.set_bone_global_pose_override(17, bonePose, 1.0, true)
1 Like

The issue seems to be that you’re clamping the input but not the result. So it’s clamping how far it can move in a single frame, but not overall.

Instead, I’d suggest using an accumulator (just a float you add to or subtract from when you move the mouse), clamping the accumulator, and then using that to lerp between the two angles you want.

2 Likes

ok how would you do that?

accum += event.relative.x * scalar
accum = clampf(accum,0.,1.)
var angle = lerp_angle(angle_a, angle_b, accum)
skel.set_bone_pose_rotation(17, Quaternion(axis, angle))

I don’t quite get how to use your code but I did figure it out.
here’s what I ended up with

func _input(event):
	if event is InputEventMouseMotion:
		rotate_y(deg_to_rad(-event.relative.x * mouse_sensitivity))
		# Get the current pose of the bone
		var bonePose = skel.get_bone_global_pose(17)
		# Save the original position
		var original_position = bonePose.origin
		# Define the rotation axis as the X axis
		var axis = Vector3(1, 0, 0)
		# Define the rotation angle based on relative.x
		angle = event.relative.y * mouse_sensitivity * VERTICAL_sensitivity
		# Apply the rotation to the pose
		bonePose = bonePose.rotated(axis, angle)
		# Changes the basis to a euler
		var bonePosEuler = bonePose.basis.get_euler()
		# Clamps that euler
		bonePosEuler.x = clamp(bonePosEuler.x,-0.671,0.265)
		# Turns the euler into a bias
		bonePose.basis = Basis().from_euler(bonePosEuler)
		# Reset the position to the original one
		bonePose.origin = original_position
		# Set the new pose of the bone
		skel.set_bone_global_pose_override(17, bonePose, 1.0, true)

2 Likes

Awesome! You did it without an accumulator, and that way works just fine too.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.