Making a script that thransfer energy to other elements with main Source energy.

I am making a game, where player can create a cubes on touch.
Cubes passing energy from MainCube ( source ). And whenever one of the cube “Died” or “Disabled, I want it to check its neighbours if they have connection to MainCube - if NOT, than they lost their energy and it’s piped got coloured to red. If YES, then they renew their energy and it’s piped got coloured to green.

Example 01 - Everything is fine, everything connected to MainCube ( Green Cube ). Any other cubes are additional cubes, that was created by PLAYER.

Example 02 - This is wrong, because one cube that was connected to MC was deleted\disabled, so any other cube have no connection, and all of they should be RED.

Example 03 - This is right, because cubes, that had access to main source of energy was destroyed.

Example 04 - This is right, because only one element that was connected to main source was connected.

About code:
I already lost my mind over the code, and think it’s wrong. I tried to give a a main source to each new created by PLAYER cube, to the cube it was attached. And then, if someone get disabled, it sends DeathMessage to all it neighbours but MainSource (Neighbour), so who ever was dependent on a Cube that was destroyed, get notified that they lost heir Main Source of Energy, and need to send it to another neighbour, and paint them red, unless they have more than one Source element, after deleted previous.
Then cube with additional source element should send to cubes who lost their energy power to change their main source power and power and paint themselves to green.

My problem is that I lost my mind on this, and not sure how to really implement it.

CODE:

    // TODO: Check if this variable even needed;
    public bool isPowered = false;

    // Cube - neigbour with energy flow
    public List<GameObject> sourceCubes = new List<GameObject>();

    public List<GameObject> neighbours = new List<GameObject>();

    public void CheckingInformationAboutNeigbours(GameObject cube)
    {
        if (cube.name == "MainCube")
        {
            sourceCubes.Add(cube);
            neighbours.Add(cube);

            isPowered = true;

        }

        else
        {
            bool power = cube.GetComponent<EnergyConnectionScript>().isPowered;

            if (power)
            {
                sourceCubes.Add(cube);

                isPowered = true;

                if (neighbours.Count > 6)
                    Debug.LogError("There is more neigbours then it should be");

            }

            neighbours.Add(cube);
        }
    }

    [System.Obsolete]
    public void MyNeigbourDied(GameObject whoDied)
    {

        if (sourceCubes.Contains(whoDied))
        {
            sourceCubes.Remove(whoDied);
            //neighbours.Remove(whoDied);

            if (sourceCubes.Count >= 1)
            {
                //SendAliveMessageToNeigbours();
            }
            else
            {

                GameObject energyPipes = this.transform.GetChild(0).gameObject;

                for (int i = 0; i < energyPipes.transform.childCount; i++)
                {
                    energyPipes.transform.GetChild(i).GetComponent<MeshRenderer>().material.color = Color.red;
                }

                SendDeathMessageToNeigbours();
            }
        }
        else
        {
            //neighbours.Remove(whoDied);
        }

        if (!whoDied.active)
        {
            neighbours.Remove(whoDied);
            //Debug.Log(string.Format("I am {0}, and i remove my neighbour {1}", this.name, whoDied.name));
        }
    }

    public void ChangeSourcCube(GameObject newSourceCube)
    {
        Debug.Log(string.Format("I am: {0}, and my new powerSource is {1}", this.name, newSourceCube.name));
        if (!sourceCubes.Contains(newSourceCube))
            sourceCubes.Add(newSourceCube);

        GameObject energyPipes = this.transform.GetChild(0).gameObject;

        for (int i = 0; i < energyPipes.transform.childCount; i++)
        {
            // TODO: Change to blue if needed, green is just for debugging;
            energyPipes.transform.GetChild(i).GetComponent<MeshRenderer>().material.color = Color.green;
        }

        SendAliveMessageToNeigbours();

    }

    //public bool oneTimeAliveMessage = false;
    public void SendAliveMessageToNeigbours()
    {
        //if(!oneTimeAliveMessage)
        foreach (GameObject obj in neighbours)
        {
            if (!sourceCubes.Contains(obj))
            {
                Debug.Log(string.Format("I am: {0}, and sending message to {1}", this.name, obj.name));
                obj.GetComponent<EnergyConnectionScript>().ChangeSourcCube(this.gameObject);
            }
            //    continue;
            //else
        }
        //oneTimeAliveMessage = true;
    }

    [System.Obsolete]
    public void SendDeathMessageToNeigbours()
    {
        foreach (GameObject obj in neighbours)
        {
            if (obj.name != "MainCube" || !sourceCubes.Contains(obj))
                obj.GetComponent<EnergyConnectionScript>().MyNeigbourDied(this.gameObject);
        }
    }

    [System.Obsolete]
    private void OnDisable()
    {
        //this.GetComponent<EnergyConnectionScript>().enabled = false;
        SendDeathMessageToNeigbours();
    }

Think all you really need to do is a recursive search and keep track of what cubes you’ve visited. Then, if you run out of new cubes to search, you can disable all of the cubes in the Set you were keeping track of. If you find the power source, then you don’t need to do anything.

Well I tried to do something similar, but it doesn’t works as I consider it should.
Usually, when I delete nearest to MainCube Additional Cube, then not everyone lost their source, because they think that someone else has Source.
I think, it because every new source seen their main first cube as a Source Powered.

Just run floodfill, DFS or any other graph traversal algorithm instead of reinventing the wheel. Plenty of tutorials about them. With those sizes (few dozen blocks) it shouldn’t be a problem even if you run it every frame (although you really need it only after removing or adding a block).

There are fancier algorithms which allow dynamically maintaining connectivity information without having to traverse whole graph after each modification, but they are a lot more complicated. No point wasting time trying to understand them, if the size limitations in your usescase allows traversing whole graph after each change.

2 Likes

I think you misunderstood what I was saying, you should be recursively searching for the MainCube, the Green one from your original post.