• 2D
  • One-Way Collision on Spikes?

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()

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.

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.

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.

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.

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()

@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.

@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.

@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.

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()

@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.

@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! :)

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)