0 votes

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')
Godot version 3.5 Beta 4
in Engine by (19 points)
edited by

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.

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

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

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:

https://docs.godotengine.org/en/stable/tutorials/animation/animation_tree.html

Sorry I can't be more help.

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.

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. :)

Good luck!

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.

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.

Please log in or register to answer this question.

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 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 webmaster@godotengine.org with your username.