Move node directly down when no mode is below it

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

I have a kinematicBody2d node as base and some inherited nodes of it. I add 5 instances of them every 0.2 seconds using a timer. They start from bottom of the screen and move upwards constantly. So there are moving(with same speed) rows with node instances.
Is there an easy way to check those instances and if there is no node directly below an instance, then that instance to move to that empty position(and continue to move upwards as all others)?

:bust_in_silhouette: Reply From: exuin

Use a Raycast2D to detect bodies below. Slow down the upward movement of the instance to allow it to move to the lower position while still moving upwards.

I tried use Raycast2D and after some different(try and error) approaches I found so far only one way which kinda works.
But there are some problems:

  1. There are some glitches when the positions change and on the tween I use to remove the matched pieces.
  2. After 10 minutes of playing the tiles starting to overlap each other. Until then the distances seems fine, so I don’t know why this happens.
  3. On android when I use the above I have a different behaviour from pc. Instead of 1 row to appear after the other, appears 2 rows(the one at top of the other), and a big gap(the size of a tile) between them.
    I use this function to check and move the tiles:
func detect_empty():
	for fruit in $Fruits.get_children():
		if fruit.get_child(5).is_colliding() == false and fruit.position.y < get_viewport().size.y - fruit.get_child(0).texture.get_height():
			fruit.position =Vector2(fruit.position.x, fruit.position.y+115)

and call it in _process of the MainScene.
There I have a node2d named Fruits and all instances are children of that node.
The position change of the tile rows is called on _process in the base tile scene script. The velocity is defined at a global script which autoloads. I tried to change it at the above method but I didn’t see any difference(tried to make it zero and restore it after the positions change).

dancaer69 | 2021-04-22 16:44

Hmm, can you just parent all the moving nodes to one node and just move the parent node? That way you don’t have to calculate speed relative to the parent node.

exuin | 2021-04-23 03:50

They already are. Move the parent node didn’t solve any of the problems I mentioned though.
Using _physics_process instead of _process seems that helps for the 2 problems(the android problem didn’t change).
Seems that the choppy animation and the tile overlapping is fine now(at least for about 15 minutes of testing), but tweens speed up every minute.

dancaer69 | 2021-04-23 07:40

:bust_in_silhouette: Reply From: dancaer69

Because of the problems I mentioned I cannot use proccess, so the Raycast2D didn’t help.
I tried different things and the only way I found to get an acceptable result was the above function which runs every time 3 tiles match:

func tile_shift():
	var fpos=first_tile.global_position
	var spos=sec_tile.global_position
	var tpos=third_tile.global_position
	for fruit in $Fruits.get_children():
		#if fpos.x != spos.x and spos.x != tpos.x:
		if fruit.global_position.x == fpos.x and fruit.global_position.y < fpos.y:
			fruit.global_position = Vector2(fruit.global_position.x, fruit.global_position.y + step)
		if fruit.global_position.x == spos.x and fruit.global_position.y < spos.y:
			fruit.global_position = Vector2(fruit.global_position.x, fruit.global_position.y + step)
		if fruit.global_position.x == tpos.x and fruit.global_position.y < tpos.y:
			fruit.global_position = Vector2(fruit.global_position.x, fruit.global_position.y + step)

The above function basically works but there are 2 problems.

  1. When the 3 tiles are the one below the other:
    Then the tile(or tiles) above them which need to move, move by 1 step, so there is an empty space
  2. When 2 tiles are one below the other and the 3rd is in a different place. For example:
    -A --------------------- A
    -B ---------or ------------- B
    ------ C -------------------- C

Then again works but need an adjustment by about ~ +10pixels for the tile which is above those 2 tiles.
I tried to solve this with some different ways but I always end to make it worst.
So, any ideas or help to improve the function to include those cases?