How can I detect collisions/area2ds at a given area?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Introdile

I’m doing grid-based movement in my 2d game, but I want characters to be able to stack in a single tile to a certain point. I’m trying to figure out a movement solution that would allow me to do this.

My current idea is having characters have an Area2d for their collision and when moving to a new tile, they have a second small ‘checker’ Area2d that is unmonitorable. When a character wants to move, it throws its checker to the position is wants to move and checks for collisions at that point. If there’s a wall or more than 5 area2ds in that tile, it won’t be able to move there.

get_overlapping_areas() doesn’t seem to update fast enough for my function and using signals haven’t worked either. Also, detecting collision bodies for walls just haven’t worked at all. I do have my layer masks set up so the checker should be able to see the walls.
For the get_overlapping_areas(), I’m guessing I’m trying to use it too fast? I have no idea for get_overlapping_bodies() which doesn’t trigger at all. Relevant code:

actor.gd

func _physics_process(_delta) -> void:
	if Active:
		if Input.is_action_just_pressed("left_click"):
			var target_pos = get_viewport().get_mouse_position()
			var checked = check_move(target_pos)
			if checked != position:
				global_position = checked

func check_move(pos : Vector2) -> Vector2:
	var snapped_pos = Grid.snap_pos_to_grid(pos)
	$Checker.global_position = snapped_pos
	
	if $Checker.overlapping_bodies.size() > 0:
		print("Wall here!!")
		return position
	
	print("%s areas detected here!!" % $Checker.overlapping_areas.size())
	return snapped_pos

checker.gd (this is where the variables from $Checker from above come from)

var overlapping_areas : Array
var overlapping_bodies : Array

func _physics_process(_delta):
	overlapping_areas = get_overlapping_areas()
	overlapping_bodies = get_overlapping_bodies()

I haven’t read your code (yet), but if it’s true that collision detection is “slow” for you, what about to prepare four checkers for every movement direction?

Reloecc | 2020-09-15 07:53

:bust_in_silhouette: Reply From: Reloecc

Your detection is “slow” because you are not really waiting for overlapping areas to recalculate after moving the $Checker. You can’t expect that _physics_process of checker.gd is called right after line $Checker.global_position = snapped_pos

What I made to solve this is I’ve stored the direction I want go to variable, moved the $Checker and made actual move in next _process call, when the collisions are recalculated.

This way the movement is going to be allways delayed by 1/FPS ms, but it’s not really noticable in 60 FPS.

I forgot to mention I did try this and the code above was my current attempt at it. get_overlapping_areas also didn’t work when I called it directly, I’m guessing again cause I was trying to use it too fast? It would take several tries for it to tell me how many areas it was overlapping when I tried it.

Introdile | 2020-09-15 23:35

So I’ve created this for you, all working as expected, can’t help you here more (based on 3.2.2-stable)
Movement.zip - Google Drive

Btw notice how you don’t need to work with global position of checker and calculatesnap_pos_to_grid and so on in my code.

Reloecc | 2020-09-16 07:55

I’ve just realized what’s going wrong with both yours and mine code as well. During the “after time” testing I was able to reproduce your issue. As stated in documentation, there needs to be one _process being called between moving and detecting collisions. Documentation says you are supposed to use signals, what is not suitable for your case because there may be no enemies nor walls in the direction you’re trying to go so no enter signal may be called after you move your checker.

I would really go the way of four checkers.

But… I’ve fixed my code. In the v2 I am setting the direction I want go to the variable and making actual move in next _process call. This way the movement is going to be allways delayed by 1/FPS ms, but it’s not really noticable in 60 FPS.

Movement_v2.zip - Google Drive

Reloecc | 2020-09-16 11:58

Oh wow, this is really cool! Thank you so much for going out of you way to make that for me, this is absolutely perfect for what I need. I’ll see about adapting it to my project!

And truth be told, in the project I’m working on, the characters aren’t going to be directly controlled, which is why this is the sorta solution I was going for. With a checker like that, I could have them move instantly to where they want to go and animate their sprite along a path to their new location and allow them to stack up. Thank you again for doing this for me! :slight_smile:

Introdile | 2020-09-16 15:59

Glad to help. Mark my answer if plausible then :slight_smile:

Reloecc | 2020-09-16 16:50