One-Way Collision on Spikes?

SosaseesSosasees Posts: 104Member
in 2D

I currently have a GitHub Issue with Semisolid Spike Collision, but Godot Forums Discussions were for me always more reliable in attracting fixes to my problems.

Unlike in this YouTube video, I need the Player Character to be able to jump up without injury when ze is in front of the Spike.
I made sure to enable One-Way Collision on the
Collision Shape (Rectangle) 2D,
yet the spike Still counts collisions from BOTH sides as
,,ha ha, you die!".

This is the Spike Code:

extends Area2D

func _physics_process(_delta):
    var bodies = get_overlapping_bodies()
    for body in bodies:
        if body.name == "Player1" or body.name == "Player2":
            body.die()

Tags :

Best Answer

  • SosaseesSosasees Posts: 104
    edited July 28 Accepted Answer

    I found a way to check the Player's Y-velocity like @Azedaxen suggested:

    I explored the Player Script for a while, and when I found motion.y,
    print("motion.y: ", motion.y) confirmed that this value is Negative when Leaping and Positive when Falling.
    So I added body.motion.y > 0 as the second if-condition on the SemisolidSpike Script, and it now works as intended:

    func _on_Spike_body_entered(body):
        if body.name == "Player1" or body.name == "Player2":
            if body.motion.y > 0:
                body.die()
    

Answers

  • AzedaxenAzedaxen Posts: 41Member
    edited July 26

    I'm a little confused by what your diagram is supposed to convey. It looks like you want the player to be able to jump through the bottom of the spike and not die?

    You could try putting two separate areas on the spikes, one death trigger on the sharp part and one area that doesn't kill the player on the other end. If I'm understanding your diagram correctly, you'd probably have to make a script that briefly disables your death trigger while the player is passing through the bottom. Or you could just teleport the player up past the death trigger.

    I'd also recommend using the on_body_entered(body) signal and checking to see if the body parameter is a player rather than checking for an overlap on every physics frame. That should be a bit more performant.

  • SosaseesSosasees Posts: 104Member
    edited July 27

    These all seem like great suggestions. I'll definitely try them.

    And yes, the diagram means exactly what you think it means.
    I made it because it makes the issue more interesting and easier-to-understand.

  • SosaseesSosasees Posts: 104Member
    edited July 27

    I replaced the for-loop with a Signal. I'm not sure if the game ACTUALLY runs any easier, because
    the Framecounter spelled 60 then and still spells 60 now.
    And even while I temporarily disabed VSync, specifically to measure the performance change in numbers,
    these code changes still don't raise or lower the Framecounter.

    But at least the code looks much cleaner now:

    extends Area2D
    
    func _on_Spike_body_entered(body): #The Signal
        if body.name == "Player1" or body.name == "Player2":
            body.die()
    

    @Azedaxen While I thank you for pointing out this possibility for improving existing code,
    I still need a working way of toggling the collision or making body.die() run only when the player touches it from above.

  • SosaseesSosasees Posts: 104Member

    I tried making a "Protection Collider" beneath the ,,Ouch Collider", which disables the ,,Ouch Collider" when entered, and re-enables it with a time delay when exited. It didn't work, so the gameplay doesn't change and the player character still dies when touching the point from below.

  • TwistedTwiglegTwistedTwigleg Posts: 2,831Admin

    For checking to see if the player is above the spike, maybe try to just get the delta position of the player and the spike, and see if the Y value is above a certain threshold. Something like this:

    const Y_THRESHOLD = 32
    func _on_Spike_body_entered(body):
        var body_delta = body.get_global_transform().origin - global_transform.origin()
        if body_delta.y >= Y_THRESHOLD:
            if body.name == "Player1" or body.name == "Player2":
                body.die()
    
  • AzedaxenAzedaxen Posts: 41Member
    edited July 28

    @TwistedTwigleg said:
    For checking to see if the player is above the spike, maybe try to just get the delta position of the player and the spike, and see if the Y value is above a certain threshold.

    Oh yeah, that's a lot more elegant than my idea. I wasn't able to find the player script in the repo, but if you have a variable that stores the velocity of the player, you could easily just check to see if the Y velocity is a negative number and if so, kill the player when they touch the spike.

  • SosaseesSosasees Posts: 104Member
    edited July 28

    @Azedaxen said:
    I wasn't able to find the player script in the repo.

    Most of the scripts are embedded into nodes. This makes my project much more clean because it means that the scripts folder isn't filled with only-used-once scripts that would make it much harder to find the used-multiple-times scripts I actually look for.

    You could clone the repository and open it in Godot, then you'll be able to find my Player Script in the Player Scene.

    @Azedaxen said:
    if you have a variable that stores the velocity of the player, you could easily just check to see if the Y velocity is a negative number and if so, kill the player when they touch the spike.

    Do you mean a positive velocity? In Godot, the Y-Coordinate is reversed: Up is Negative and Down is Positive.

  • SosaseesSosasees Posts: 104Member
    edited July 28

    @TwistedTwigleg I can't really comprehend your answer,
    but @Azedaxen​'s suggestion of checking the player's Y-velocity sounds awesome.

    I need one of two things:
    A small explanation of @TwistedTwigleg​'s answer
    (Mainly, what the term ,,delta position" means, because I can't find it),
    or a way to check the player character's Y-velocity like @Azedaxen suggested.

  • SosaseesSosasees Posts: 104Member
    edited July 28 Accepted Answer

    I found a way to check the Player's Y-velocity like @Azedaxen suggested:

    I explored the Player Script for a while, and when I found motion.y,
    print("motion.y: ", motion.y) confirmed that this value is Negative when Leaping and Positive when Falling.
    So I added body.motion.y > 0 as the second if-condition on the SemisolidSpike Script, and it now works as intended:

    func _on_Spike_body_entered(body):
        if body.name == "Player1" or body.name == "Player2":
            if body.motion.y > 0:
                body.die()
    
  • SosaseesSosasees Posts: 104Member
    edited July 28

    @Azedaxen would you like to be credited in my Game Credits for finding the answer?
    I'll credit you on the July 30th if you don't disagree.

  • AzedaxenAzedaxen Posts: 41Member

    @Sosasees said:
    would you like to be credited in my Game Credits for finding the answer?
    I'll credit you on the July 30th if you don't disagree.

    Sure, I'd appreciate that! :)

  • SosaseesSosasees Posts: 104Member

    I credited you, and @TwistedTwigleg as ze was also very important in finding the answer (and already agreed that ze always wants to be credited)

Leave a Comment

BoldItalicStrikethroughOrdered listUnordered list
Emoji
Image
Align leftAlign centerAlign rightToggle HTML viewToggle full pageToggle lights
Drop image/file