Problem with global_position(probably)

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

The below code works for some moves but in some point the “new_empty” becomes null and balls stop change position with mouse click.

func valid_move(node):

for pos in all_positions():
	if pos.get_meta("occupied") == false:
		empty_pos = get_position2d(node.global_position)
		print(empty_pos.name)
		if "Red" in pos.name:
			reparenting(node, $RedZone/RedBalls)
		elif "Blue" in pos.name:
			reparenting(node, $BlueZone/BlueBalls)
		elif "Green" in pos.name:
			reparenting(node, $GreenBalls)
		elif "Center" in pos.name:
			reparenting(node, $GreenBalls)
		node.global_position = pos.global_position
		#print(pos.name)
		pos.set_meta("occupied", true)
empty_pos.set_meta("occupied", false)
print(empty_pos.get_meta("occupied"))

func reparenting(child, new_parent):
	var old_parent = child.get_parent()
	var pos = child.global_position
	old_parent.remove_child(child)
	new_parent.add_child(child)
	child.global_position = pos
	child.owner=new_parent
func get_position2d(pos):
	var pos2d
	for i in range(all_positions().size()):
		if pos == all_positions()[i].global_position:
			pos2d = all_positions()[i]
			break
	return pos2d    

I cannot find why this position became null. I’m using position2d to place the balls which aren’t move, but I have 2 platforms which rotated on mouse click 45 degrees. At first I had all positions in MainScene, but I had problems with reparent and the order of nodes(sometimes balls were bellow the platforms), so I have now 8 positions in the one platform, 8 in the other and 9 in the MainScene.
After this change all balls are and go to the correct empty(1 at a time) position2d position. But after some moves the empty position become null. How to debug this to find how this position becomes null? All positions are static and the balls spawned to these positions in _ready.

:bust_in_silhouette: Reply From: Inces

This is a bit complicated and I am not sure if I get it.

newempty is an inside function variable. Every time You run valid_move function You introduce this variable as null, than iterate through all positions and newempty is set during this iteration. So the reason nothing happens after click and newempty is still null must be that all of Your positions meta become “ocupied” at some point.

The problem propably lies in line : set_meta(“occupied”, false) . Try to print it.
Other than that, maybe there is misconception in movement. What is the code for Input of click ? Are all balls moved_valid() in the same time ?

I replaced new_empty with empty_pos which I declared it outside the function. It didn’t make any difference though. I also tried to print the empty_pos.name and the “occupied” meta after set it to false.
Those don’t help because I get the correct positions and “occupied” value(false) until the empty_pos to become null. Then I get error for trying to set_meta in a nil instance(because empty_pos became null). Seems that something happens with the positioning but I don’t see any wrong positioning visually, until I get the null crash.
The on click code has nothing except the valid_move() method.
The balls don’t move together. Every time the clicked ball moves.

Here is the input function:

func _ready():
	for child in all_balls():
		child.connect("input_event", self, "_on_Ball_input_event", [child] )
func _on_Ball_input_event(viewport, event, shape_idx, node):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and not event.is_echo() and event.is_pressed():
			valid_move(node)

dancaer69 | 2021-04-09 06:27

After some more debuging I found that the problem starts in line which I set the empty_pos. There I use a function to get the Position2D on that node’s position. So I added a print statement in this function and I found that in some point(when I get the error) the node’ s position doesn’t match with any of the positions. I also printed the position which doesn’t match.
I don’t know if this is accurate, but I get that position and from the editor on mainScene I added a sprite(just for test) and I give it the non matching position. I found that the position isn’t the same with the Position2d position. I checked 2 of them and the first was 4 pixels right from the Position2d and the second was about 2 pixels right and up
So, seems that at some point the ball’ s global_position isn’t the same with the position2d in which is moved. But, because I print the positions also, until then the old and new position are exactly the same.

EDIT:
Seems that the problem with shifting positions comes from the circular platforms when rotating. I have set the center property on but again the rotation isn’t pefect and because the position2d are children of them after some rotations the positions of them change a bit.
The problem is that I don’t know how to get perfect rotations. I tried to correct the textures and reselect the areas from atlas picture and it’s better now but still not perfect rotation, so the errors occure still.

dancaer69 | 2021-04-09 11:50

After many other things I tried and couldn’t get get rid of the error, I thought that maybe this was to complicated and need to find a simpler way.
So, Instead of use the Position2D positions, I created a sprite with a transparent texture and use this as the empty spot.
Then I just swap the clicked ball position with the empty(transparent) sprite position:

func valid_move(node):
	var nodepos = node.global_position
	var node_parent = node.get_parent()
	var hole_parent = hole.get_parent()
	node.global_position = hole.global_position
	reparenting(node, hole_parent)
	hole.global_position = nodepos
	reparenting(hole, node_parent)

And this works fine. Now just need to find a way to actually define the valid moves.

dancaer69 | 2021-04-10 12:05