#RigidBody2D - Detect which TileMap tile was collided.

39 messages · Page 1 of 1 (latest)

zinc tiger
#

I have a simple scene set up, with:
4 StaticBody2D rectangles at the edges of the screen, as borders
1 RigidBody2D with a circle collision shape, as a ball
1 TileMap, with one single tile, that has physics set up and a collision shape set to it.

The "ball" has an initial velocity and is moved around the screen with move_and_collide().
Everything works fine, and the ball bounces off of the walls and the random tiles that I place on the TileMap.

My problem is that I can't manage to get any collision events from the body, even though I set contact_monitor to true and max_contacts_reported to 4.

My goal is to remove a tile if it's "hit" by the ball.

stable terrace
#

It may very well be that using move_and_collide wont trigger collision events for a rigidbody. Usually you move rigidbodies by applying forces or setting the velocity directly (_integrate_forces)

tepid meteor
#

Oh, @zinc tiger, didn’t see that you were using move_and_collide. Aren’t collisions returned directly by that function, then?

zinc tiger
#

@tepid meteor yes, but it returns a TileMap

#

I need the specific tile

tepid meteor
#

Can you get the cell from the tilemap with the collision position?

stable terrace
#

yeah you need to get the tile via the collision position. the collider is the entire tilemap, it wont get more specific than that

zinc tiger
#

Yeah, that's ehat I'm doing at the moment.
But it has some annoying edge cases.
For example, if the ball collides with a tile from below, the collision position brings you to a tile that is below the tile I'd like to remove.
Same case when colliding from the right.

So I had to put annoying if statements that check the ball's position compared to the collision position, and corrects the selected tile accordingly.

It's fragile and there are bugs.

Was hoping to avoid all that with a simple collision event.

noble elk
#

I couldn't really figure this out either, but I found out that you can put entire scenes in tilemaps now, so I made a Brick scene with its own code for getting collided with and put that in a tilemap. Though I'd also like to learn how to do it with tilemaps directly.

zinc tiger
#

Thanks, @noble elk .
That's a valid option.

Using this option, do you need to (somehow) declare each tile unique?
What if I queue_free() one tile, like in your suggestion? Will it remove all of them?

noble elk
#

Looks like doing simply that worked just fine for me, no issues.

#

My script is inside the brick scene, getting the tile from outside is not something I have experiencee with and might have unexpected discrepancies.

zinc tiger
#

Yeah, that sounds great.
I'll check it, hopefully, later today.

I assume you used a StaticBosy2D, and hooked the event to something like queue_free()?

noble elk
#

Static bodies don't seem to actually have a signal for collisions, as far as I could see? So I used a rigid body frozen in kinematic mode.

zinc tiger
#

@noble elk I can't seem to find any reference on how to create a tileset from a scene.
I did it before, but can't remember how, and can't find anything online.

Can you give me a pointer?

noble elk
#

Yeah I'll just finish eating then go check

zinc tiger
#

take your time. thanks

noble elk
zinc tiger
#

amazing

noble elk
#

Basically on the left in the tileset window you add a scene collection by clicking on the small plus, while on the right you just drag your scene into the window and that should be it.

zinc tiger
#

okay. cool

#

meanwhile, I might have figured out something else as well

noble elk
#

Ooh, do tell

zinc tiger
#

well, didn't work.
I tried this:

var collision_info = move_and_collide(velocity)
...
var instance_id = PhysicsServer2D.body_get_object_instance_id(collision_info.get_collider_rid())
var instance = instance_from_id(instance_id)

But that just returns the TileMap, and I can get that with a simple collision_inf.get_collider()

noble elk
#

Aw, that's a shame.

zinc tiger
#

I'm clearly missing something important, because I followed the guide, and it's not catching the signals.

#


func _on_rigid_body_2d_body_entered(body):
    print("Collision" + str(body))
    self.queue_free()

func  _ready():
    print("Loaded custom tile 2...")


func _on_rigid_body_2d_body_shape_entered(body_rid, body, body_shape_index, local_shape_index):
    print("Collision" + str(body))
    self.queue_free()
#

I created a bunch of tiles from the scene, and indeed the "loaded" message is printed.

#

Also collisions happen, and the ball bounces around

#

but no signal are fired...

#

Tried to connect a print() to the mouse_entered signal.

Nothing fires

#

🤔

#

Just figured out something.
This is what my "map" looks like.
Notice how that square on the top overlaps with some of the tiles.
Why I loads the game, all the tiles that touch that square get removed.

So it seems like the tiles are getting collisions from the static body, but not from the "ball". why?

#

ohhhhh kaaaaay

Made the following change: the "ball" was set to freeze in kinematic mode.

It's now triggering collision signal on the tiles,

Not sure what just happened, but it's working 🤷‍♂️

noble elk
#

I did say before I used kinematic mode. Glad you figured it out on your own though.
Originally, I just checked the custom integration variable, but sometimes they actually wouldn't disappear and just start floating away instead. When I first tried freeze they didn't disappear at all. It was only through random guesses I figured out it worked with kinematic mode myself as well.

zinc tiger
#

Follow-up question - it the tile scene aware of its hosting TileMap?