Search code examples
godotgdscript

Merging 2 overlapping Area2D nodes?


I have a node called "Merger" which is an Area2D with a CollisionPolygon2D in it as such:

enter image description here

with the following script:

extends Area2D

onready var shape=$Shape
var is_merging=false


func join(obj): # basically does self shape = overlap_obj shape + self shape
    ...


func merge_in(obj):
    if(is_merging):
        return
    
    if(obj.get_class()==self.get_class()):
        if(obj.is_merging):
            return
        
        is_merging=true
        obj.is_merging=true
        
        join(obj)
        
        is_merging=false
        obj.is_merging=false

        print("deleting=>",obj)
        obj.queue_free()


func _ready():
    self.connect("area_entered",self,"merge_in")
func get_class():
    return "Merger"

But whenever I place 2 instance of these on top of each other instead of merging they both get deleted:

enter image description here

Output on running:

deleting=>Merger:[Area2D:1269]
deleting=>Merger2:[Area2D:1272]

Also I'm trying not to use prioritybecause setting the priority of every instance would be a pain

I'm trying to make a water like object such that if 2 instance of them overlap they become a singular object,
So is something like this possible? or any similar approach that might yield the same results?


Solution

  • Thanks to @hola and @Thearot in the comments I figured it out:

    extends Area2D
    
    onready var shape=$Shape
    var is_merging=false
    
    
    func join(obj): # Merges object shape into self shape
        ...
    
    
    func merge_in(obj):
        if(is_merging):
            return
        
        if(obj.get_class()==self.get_class()):
            if(obj.is_merging):
                return
            
            is_merging=true
            obj.is_merging=true
            
            join(obj)
            
            is_merging=false
    
            print("deleting=>",obj)
            obj.queue_free()
    
    
    func _ready():
        self.connect("area_entered",self,"merge_in")
    func get_class():
        return "Merger"
    

    or simply without having a check variable:

    func merge_in(obj):
        if(self.is_queued_for_deletion()):
            return
    
        if(obj.get_class()==self.get_class()):
            join(obj)
            obj.queue_free()
    

    Edit:

    Turns out the actual "merging" rabbit hole was a bit deeper than I thought
    and using is_merging variable won't cut it, So I made this small algorithm:

    var prime:Array=[]
    
    func merge_in(obj:Area2D):
        if(obj.get_class()!=self.get_class()):
            return
    
        if(self.prime):
            if(obj.prime): # 1 
                if(obj.prime[0]==self.prime[0]):
                    return
                
                self.prime[0].join(obj.prime[0])
                obj.prime[0].queue_free()
                obj.prime[0]=self.prime[0]
            else: # 2
                obj.prime=self.prime
                self.prime[0].join(obj)
                obj.queue_free()
        
        else:
            if(obj.prime): # 3
                self.prime=obj.prime
                obj.prime[0].join(self)
                self.queue_free()
            else: # 4
                self.prime=[self]
                obj.prime=self.prime
                self.join(obj)
                obj.queue_free()
    

    And this should merge any and all overalapping areas:

    enter image description here

    Hope this helps ;)