LineShape2D one-way collision pulling RigidBody2D from opposite side

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By yerbestpal

Hi folks,

I’m having an issue where a LineShape2D with one-way collision enabled is ‘pulling’ or ‘warping’ the rigidBody2D from underneath (i.e. the side it is not meant to interact with) when I activate the associated layer bit.

Demonstration of the warping issue.

The GIF isn’t as clear as I would like, but hopefully it demonstrates that I am trying to make the player header the ball on a button press, otherwise the ball should pass through. Collision is working fine, it’s just the warping issue.

The only code involved is used to set the relevant collision layer bit when in the ‘header’ state, and unset it when exiting that state.


Player node tree:

enter image description here

Ball node tree:

enter image description here


func _transition_state(_delta):
match state:
	states.idle:
		if !get_parent().is_on_floor():
			return states.jump
		if get_parent().velocity.x != 0:
			return states.run
		if get_parent() and Input.is_action_just_pressed('player_action'):
			return states.header
	states.run:
		if !get_parent().is_on_floor():
			return states.jump
		if get_parent().velocity.x == 0:
			return states.idle
		if get_parent() and Input.is_action_just_pressed('player_action'):
			return states.header
	states.jump:
		if Input.is_action_just_pressed('player_action'):
			return states.spin
		if get_parent().is_on_floor():
			return states.idle
		elif get_parent().velocity.y >= 0:
			return states.fall
	states.fall:
		if get_parent().is_on_floor():
			return states.idle
	states.spin:
		if get_parent().velocity.y > 0:
			return states.fall
	states.header:
		if get_parent().anim_player.current_animation != 'header':
			if get_parent().velocity.x != 0:
				return states.run
			else:
				return states.idle


func _on_enter_state(_new_state, _old_state):
	var anim = get_parent().anim_player
	match state:
		states.idle:
			collision_shape_head.set_collision_layer_bit(1, false)
			anim.playback_speed = 2.5
			anim.play('idle')
		states.run:
			collision_shape_head.set_collision_layer_bit(1, false)
			anim.playback_speed = 8
			anim.play('run')
		states.jump:
			anim.stop()
			get_parent().get_child(0).frame = 5
		states.fall:
			get_parent().set_collision_layer_bit(1, false)
			get_parent().get_child(0).frame = 6
		states.spin:
			get_parent().set_collision_layer_bit(1, true)
			anim.playback_speed = 2
			anim.play('spin')
		states.header:
			collision_shape_head.set_collision_layer_bit(1, true)
			anim.play('header')

The gif isn’t displaying, could you edit please? Also is there code / node setup you can share? There’s not enough to go on here, at least for me.

DaddyMonster | 2022-05-20 18:01

Apologies, the GIF should be viewable now. I’ll get some code and screenshots up in a sec.

yerbestpal | 2022-05-20 18:20

Done. Hopefully this is enough information, just let me know if it isn’t.

yerbestpal | 2022-05-20 18:36

Hmm. The gif still isn’t working for me. Obviously you’re getting some kind of stretching when you’re headering the ball but I’m not clear on what’s happening. I do have a couple of general observations which may or may not be helpful:

  1. Is your animation moving the RigidBody? The RB is run by the physics engine. If you move it yourself you’re fighting with the engine (=bad). Try changing the mode to kinematic during the animation or only apply the animation to the Sprite - ensure you do not directly set the transform of the RB.

  2. You’re using the animation player for what is quite an elaborate set up. I advise against this, it becomes unmanageable very quickly. Add an animation tree - it’s one of the best features in Godot. You’ve got several options but the one that looks best for you is a StateMachine. This will allow you do add nodes and use XY coordinates to lerp between the states so you get smooth transitions between states and you can massively reduce / simplify the code. Docs:

Using AnimationTree — Godot Engine (stable) documentation in English

Sorry I can’t be more help.

DaddyMonster | 2022-05-20 18:51

Is your animation moving the RigidBody?

No, there is no interaction between the animation and RigidBody.

Add an animation tree - it’s one of the best features in Godot

I’ll need to look into this. for now, it all goes over my head. Thanks for the suggestion and help regardless.

yerbestpal | 2022-05-20 19:09

I’m annoyed that I couldn’t answer this one. Hopefully you’ll get someone else comment. If the gif had worked I might have stood a chance but your code and node setup you shared all look basically fine, I’ve read through it three times now (unless I missed something…) The major issue is I can’t picture in my head what’s happening.

For the collision obj, check where the origin is - it should be in the middle (or at the neck) - and make sure it has an identity basis matrix (Transform2D.x = Vector2(1, 0) and Transform2D.y = Vector2(0, 1)) - if that’s anything else there’s your problem). Check that the layer / mask indexes are correct. Run the collision without the animation. Then run it with an animation that does nothing. Usual debugging stuff, pressure and time solves these things.

Anyway, when you have some time look into AnimationTree, there will be a “it does all that?!” moment when the penny drops. :slight_smile:

Good luck!

DaddyMonster | 2022-05-20 21:21

and make sure it has an identity basis matrix (Transform2D.x = Vector2(1, 0) and Transform2D.y = Vector2(0, 1)) - if that’s anything else there’s your problem).

I don’t actually know what an identity basis matrix is and I’m not making use of Transform2D in my project to my knowledge.

With regards to AnimationTree, I’ve implemented an AnimationTreeStateMachine and that its self is really cool, although I’m a bit lost as to how to control animation speed now. I’m yet to research what else AnimationTree is capable of.

Thanks for all your advice.

yerbestpal | 2022-05-22 18:14

Honestly, I’m 99.9% sure your problem is not the basis. Quick explanation of what it is if you’re interested as on lunch and have a minute and it’s pretty fundamental:

Basis is part of an object’s “transform” (along with “origin” which states where the start point of the object is).

When a node has a vector, eg Vector2(3, 4), you’re saying it’s so far on the x and so far on the y. But which way is x and which way is y to this object? Well, you define this with a basis matrix. It’s like defining the graph paper your vectors are drawn on.

The standard/simplest way is the “identity”: Transform2D.x = Vector2(1, 0) and Transform2D.y = Vector2(0, 1).

So any vector is multiplied by its basis matrix. If it’s “identity” (as above), nothing changes - just like multiplying by 1 with a float. This means local space is the same as world space.

If we changed the basis on the x to Transform2D.x = Vector2(2, 0) then it’ll scale it on the x and it’ll be twice as wide. Transform2D.y = Vector2(0, -1) and it’s upside down. With a bit more maths we can rotate the object and sheer it. In Godot the transform matrices of children are multiplied. So if you move an object, its children move, if you scale it, it’s children scale.

Meh, I thought maybe your object might be sheered, but I doubt it.

DaddyMonster | 2022-05-23 12:59