Skip to content

Make projectile collisions with walls be one way#379

Closed
JuanFdS wants to merge 2 commits intomainfrom
make-blobs-collisions-with-walls-be-one-way-raycast
Closed

Make projectile collisions with walls be one way#379
JuanFdS wants to merge 2 commits intomainfrom
make-blobs-collisions-with-walls-be-one-way-raycast

Conversation

@JuanFdS
Copy link
Copy Markdown
Contributor

@JuanFdS JuanFdS commented Apr 29, 2025

The collision with walls is turned back on once they left that elevated terrain.

This is an attempt to fix the issue mentioned here:
#358 (review)

If you stand to the right of the InkDrinkers, then the projectiles from the top one get stuck on top of the rocks.

image

This is essentially the same thing discussed on #353 (comment) . I think if we want to do this, we need to find a way to have a one-way collision shape that allows the projectiles to come "down" from the top of the rocks, but not get back "up" again.

How this works

Instead of handling collisions through the rigidbody, handle those collisions through raycast. That way, we can decide what to do when we detect that the raycast is colliding. This lets us set collision exceptions with some nodes (like the tilemap layers) if needed.
When a projectile spawns, it detects if any point in the vertices of its bounding box is in an elevated terrain tile and adds it to the exceptions list.
Then, every frame it checks if the projectile's bounding box has escaped that tilemap layer (no vertices are in any tile of the layer), and if that's the case, it erases the layer from the exceptions list.

Other possible solutions (❌ were explored but couldn't make them work)

  • ❌ One way collisions: It can't be configured which way the collision should go :(, at least not at the moment. Add one-way collision direction for tiles godotengine/godot-proposals#7483
  • ❌Using RigidBody.add_collision_exception_with: that would be great for this use case but sadly it can't be used with objects that are not CollisionObject2D, and tilemap layers aren't: Collision exceptions don't work with TileMap node godotengine/godot#17090
  • Turn walls collision mask off and on depending on whether the projectile is on top of a tilemap layer with elevated terrain: Projectiles: avoid collisions with walls if they spawn in an elevated terrain #364 . I lean more toward the solution in this PR instead of that one because this one allows colliding with other things that are walls and just turns off collisions with the tilemap layer.
  • Have the ink blob not hit any walls for a small amount of time when it's spawned. This could go well with a spawn effect that makes it look like the blob was thrown into the air for some frames (I guess we can achieve it by scaling it up and then back to its regular size). However, this has some drawbacks: If the projectile spawned in an elevated terrain but a bit far from the walls, this won't work. Also, if there are 2 elevated terrains near each other, the projectile might enter into the other one.

JuanFdS added 2 commits April 29, 2025 11:32
This lets us tell apart which terrain is floor and which terrain is elevated

Related to #277
… escaped that terrain

Collisions with walls are now handled by raycast instead of by the rigidbody itself.

On spawn, the projectile detects which tiles of each tileset is 'touching', and if any of those tiles is an elevated terrain, it adds that tilemap layer to a collision exception list.

As soon as the projectile isn't touching any tile from a tilemap in the collision exception list, that exception gets removed.

Had tocheck positions instead of using the raycast itself on spawn because not all tiles with elevated terrain have collisions: for example, the projectile could have spawned in the middle of a wide mountain and it'd be in elevated terrain but it wouldn't find any collisions until it got to the edge of the cliffs.

Also, used several points to find tiles in its bounding box because if I only checked the origin position of the projectile, it could spawn just at the side of a cliff, not add it to the exception list, and then be impulsed into it, causing the projectile to get stuck in the cliff. With this implementation, it is a bit more generous with what tilemap layers will end up in the collision exception list.

Related to #277
@JuanFdS JuanFdS marked this pull request as ready for review April 29, 2025 14:54
@wjt wjt requested a review from manuq April 29, 2025 15:06
@manuq
Copy link
Copy Markdown
Collaborator

manuq commented Apr 29, 2025

@JuanFdS thank you so much for attempting so many ways to fix this!

I placed an enemy behind a wall but is not doing what I would expect:

Grabacion.de.pantalla.desde.2025-04-29.16-48-58.webm

I don't think there is a general way to fix this issue without adding a new "height" or "z" or "elevation" property to world objects. I have an idea for how to do it but it would be a major change. At this point I would rather change the level design than trying to fix this in a complex way. What do you think?

@JuanFdS
Copy link
Copy Markdown
Contributor Author

JuanFdS commented Apr 29, 2025

@JuanFdS thank you so much for attempting so many ways to fix this!

I placed an enemy behind a wall but is not doing what I would expect:
Grabacion.de.pantalla.desde.2025-04-29.16-48-58.webm

I don't think there is a general way to fix this issue unless we add a "height" or "z" or "elevation" property to world objects. I have an idea for how to do it but it would be a major change. At this point I would rather change the level design than trying to fix this in a complex way. What do you think?

Ohh, I see, I kind of expected it to work the way it did because the ink blob spawns on the mountain :P, but I see your point.
I think that could be supported by making the elevation of the blob depend on the tile where the ink drinker is placed instead of where the ink blob spawns, but since the position of the blob is separate from the position of the ink drinker, it could spawn a blob inside a wall, so, yep, it just gets more complex.

I think that for the mvp it's okay to avoid this issue via level design and tackle these edge cases later!

@manuq
Copy link
Copy Markdown
Collaborator

manuq commented Apr 29, 2025

@JuanFdS thank you so much for attempting so many ways to fix this!
I placed an enemy behind a wall but is not doing what I would expect:
Grabacion.de.pantalla.desde.2025-04-29.16-48-58.webm
I don't think there is a general way to fix this issue unless we add a "height" or "z" or "elevation" property to world objects. I have an idea for how to do it but it would be a major change. At this point I would rather change the level design than trying to fix this in a complex way. What do you think?

Ohh, I see, I kind of expected it to work the way it did because the ink blob spawns on the mountain :P, but I see your point. I think that could be supported by making the elevation of the blob depend on the tile where the ink drinker is placed instead of where the ink blob spawns, but since the position of the blob is separate from the position of the ink drinker, it could spawn a blob inside a wall, so, yep, it just gets more complex.

Yes but even with that, if the enemy is set to move around (something not part of current rounds) the illusion will be broken.

Here is more or less what I would do:
20250429_172941

  • Add each floor as its own Node2D
  • Each floor has its tilemap layers, and a Y-sorted Node2D called "OnTheGround"

So in this sketch there is a 6x6 tile:

  • Player is on Floor0 "OnTheGround"
  • Enemy is on Floor1 "OnTheGround"
  • Floor0 has walls for the elevation and the water on the right
  • Floor1 has walls (or maybe a new "cliff" collision layer?) all around the 2x2 walkable square

And this is just the beginning. There should be ways to move (or teleport?) things from floor to floor. For instance, with a new "cliff" collision layer, the projectile can fall from Floor1 to Floor0 on contact.

I think that for the mvp it's okay to avoid this issue via level design and tackle these edge cases later!

Yes indeed, I would avoid this issue for the MVP.

@JuanFdS
Copy link
Copy Markdown
Contributor Author

JuanFdS commented Apr 30, 2025

@JuanFdS thank you so much for attempting so many ways to fix this!
I placed an enemy behind a wall but is not doing what I would expect:
Grabacion.de.pantalla.desde.2025-04-29.16-48-58.webm
I don't think there is a general way to fix this issue unless we add a "height" or "z" or "elevation" property to world objects. I have an idea for how to do it but it would be a major change. At this point I would rather change the level design than trying to fix this in a complex way. What do you think?

Ohh, I see, I kind of expected it to work the way it did because the ink blob spawns on the mountain :P, but I see your point. I think that could be supported by making the elevation of the blob depend on the tile where the ink drinker is placed instead of where the ink blob spawns, but since the position of the blob is separate from the position of the ink drinker, it could spawn a blob inside a wall, so, yep, it just gets more complex.

Yes but even with that, if the enemy is set to move around (something not part of current rounds) the illusion will be broken.

Here is more or less what I would do: 20250429_172941

* Add each floor as its own Node2D

* Each floor has its tilemap layers, and a Y-sorted Node2D called "OnTheGround"

So in this sketch there is a 6x6 tile:

* Player is on Floor0 "OnTheGround"

* Enemy is on Floor1 "OnTheGround"

* Floor0 has walls for the elevation and the water on the right

* Floor1 has walls (or maybe a new "cliff" collision layer?) all around the 2x2 walkable square

And this is just the beginning. There should be ways to move (or teleport?) things from floor to floor. For instance, with a new "cliff" collision layer, the projectile can fall from Floor1 to Floor0 on contact.

I think that for the mvp it's okay to avoid this issue via level design and tackle these edge cases later!

Yes indeed, I would avoid this issue for the MVP.

Yeah, I think the scene tree approach might make it easier to understand when level designing 🤔 (the alternative could be an altitude property but I think it's fine to group by the altitude they are in).
Then, it gets a bit trickier when "changing altitudes" because sometimes there won't be a cliff but instead a stair or other tiles. And I'm not sure if we would want to consider multiple levels of altitude (the approach in this PR handles that). But yeah, let's do this at other time!

Closing this to tackle it after MVP.

@JuanFdS JuanFdS closed this Apr 30, 2025
@wjt wjt deleted the make-blobs-collisions-with-walls-be-one-way-raycast branch May 2, 2025 08:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants