Character Basis Matrix rotation help
Asked Answered
K

1

0

Hello,

So I just switched from Unity to Godot and I have a problem that I think is related to my lack of understanding the Transform3D Basis matrix.

I have a rollerblading game and I got my character to align with the floor normal direction below me so that when I'm going up ramps or down slopes it looks like I'm sliding down/up the angles properly. My problem is when my character is rotated at a 90 degree angle (basically when I am going to slide up a straight vertical ramp) my rotation stops working correctly,

As of right now my rotation around the Y axis is determined by a cube that is not a child of my player, I rotate it with A & D and set my player to copy its Y Rotation. I don't think this is a good long term way to handle my rotation.

I've tried a bunch of different things but it messes up my rotation so bad whenever my character is angled, which is one reason why I think my lack of matrix rotation understanding is the issue

So my question is, how can I edit my correct code to rotate left and right and still keep my upward facing direction based on the normal below me. As of right now I think this would need to be done when I am calculating my normal up direction in my normalCalc variable, but I am not sure how to go about doing this. Any help on my current code below or just any research advise would be a huge help.

`func _physics_process(delta):

velocity.z = clamp(velocity.z, -max_movespeed, max_movespeed)
velocity.x = clamp(velocity.x, -max_movespeed, max_movespeed)
velocity = velocity.move_toward(-global_transform.basis.z * MOVESPEED, 2) # Move the player forward based on move speed

var normal = $FloorRayCast.get_collision_normal()

var normalCalc = Basis()
normalCalc.x = normal.cross(global_transform.basis.z)
normalCalc.y = normal
normalCalc.z = global_transform.basis.x.cross(normal)
global_transform.basis = normalCalc
scale = Vector3(1,1,1)


floor_max_angle = 0.99999

#print(floor_max_angle)

rotation.y = player_turn_obj.rotation.y 

# Add the gravity.

if not $FloorRayCast.is_colliding():
	velocity.y -= gravity * 15 * delta
	
# Handle Jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
	
	velocity.y = JUMP_VELOCITY

if Input.is_action_pressed("ui_left"):
	player_turn_obj.rotate(Vector3(player_turn_obj.rotation.x, rot_speed, player_turn_obj.rotation.z).normalized(), 0.03)
if Input.is_action_pressed("ui_right"):
	player_turn_obj.rotate(Vector3(player_turn_obj.rotation.x, -rot_speed, player_turn_obj.rotation.z).normalized(), 0.03)
if Input.is_action_pressed("ui_up"):
	
	MOVESPEED = lerp(MOVESPEED, 15.0, 0.1)
	
	anim_tree.set("parameters/BlendSpace1D/blend_position", velocity.length())

else:
		MOVESPEED = lerp(MOVESPEED, 0.0, 0.001)



move_and_slide()`

When my character gets to a 90 degree angle at the top of the ramp I need it to rotate on its Y depending on the way its pointing, instead of the cube below current rotation.

Kirmess answered 16/12, 2023 at 19:9 Comment(0)
K
0

I figured it out. I discovered the magical rotate_object_local function and from there I was able to tweak my script to get the movement I want, and I was even able to get rid of my separate rotate object I was using with it

`func _physics_process(delta):

#Clamps the velocity so the player doesnt go spinning off into the ether
velocity.z = clamp(velocity.z, -max_movespeed, max_movespeed)
velocity.x = clamp(velocity.x, -max_movespeed, max_movespeed)
velocity = velocity.move_toward(-global_transform.basis.z * MOVESPEED, 2) # Move the player forward based on move speed

var normal = $FloorRayCast.get_collision_normal()

#Finds the differnce between angles to stand the player upright depending on the normal below
var newUp = Basis()
newUp.x = normal.cross(global_transform.basis.z)
newUp.y = normal
newUp.z = global_transform.basis.x.cross(normal)
global_transform.basis = newUp
scale = Vector3(1,1,1) #Without this the player disappears


#floor_max_angle = 0.99999


#rotation.y = player_turn_obj.rotation.y 

# Add the gravity.
if not $FloorRayCast.is_colliding():
	velocity.y -= gravity * 15 * delta
	
# Handle Jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
	velocity.y = JUMP_VELOCITY


rot_speed = 0 #Resets to 0 every frame to stop the player from spinning on its own
#Left and right rotation input
if Input.is_action_pressed("ui_left"):
	#player_turn_obj.rotate(Vector3(player_turn_obj.rotation.x, rot_speed, player_turn_obj.rotation.z).normalized(), 0.03)
	rot_speed += 0.05
if Input.is_action_pressed("ui_right"):
	#player_turn_obj.rotate(Vector3(player_turn_obj.rotation.x, -rot_speed, player_turn_obj.rotation.z).normalized(), 0.03)
	rot_speed -= 0.05
if Input.is_action_pressed("ui_left") or Input.is_action_pressed("ui_right"):
	# Had to put this in here to stop the player from rotating after input was let go
	rotate_object_local(Vector3.UP, rot_speed) # Rotates the player based on its up direction

#Handles forward speed
if Input.is_action_pressed("ui_up"):
	
	MOVESPEED = lerp(MOVESPEED, 15.0, 0.1) #Lerps to max speed
	
	anim_tree.set("parameters/BlendSpace1D/blend_position", velocity.length())

else:
		MOVESPEED = lerp(MOVESPEED, 0.0, 0.001) #Lerps back down to 0 when no input is made



move_and_slide()`
Kirmess answered 17/12, 2023 at 21:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.