0
\$\begingroup\$

I'm having a bit of a logic problem. I have blocks that connect together for power and so when a block comes into contact with a block that is powered, it also becomes powered. It also keeps a list of connected blocks and checks that it's getting power from at least one block.

There are "source" blocks in the scene as well which are always powered and that serves as the starting point.

All of this works fine, unless we get a break in the middle. In that case, even though they aren't connected to a source block anymore the two blocks are connected to eachother and so they stay in the "connected" state.

My question is similar to this question but different in that my objects can attach in any orientation and have any number of connections. In this case, a sort of pathing would work since wire systems aren't going to have more than 10 or 15 connections total and only 1 wire system active at any time.

Here is the code if anyone is interested. Thanks in advance.

public class Conductor : MonoBehaviour
{

public bool isElectrified;
public bool isPowerSource;
public Material inactiveMaterial;
public Material activeMaterial;

private List<Conductor> _conductors;
private Renderer _renderer;


//====
//Unity Functions
//====
void Start()
{
    SetupPrivateVariables();
    CheckPowerSource();
}

void Update()
{
    ProcessConductors();
}

void OnCollisionEnter(Collision collision)
{
    ProcessNewCollision(collision, true);
}

void OnCollisionExit(Collision collision)
{
    ProcessNewCollision(collision, false);
}


//====
//Private Functions
//====
private void ProcessConductors()
{
    if(isPowerSource)
    {
        return;
    }

    bool connectedConductorPower = false;

    foreach (Conductor c in _conductors)
    {
        if (c.isElectrified)
        {
            connectedConductorPower = true;
        }
    }

    if(connectedConductorPower)
    {
        _renderer.material = activeMaterial;
    }
    else
    {
        _renderer.material = inactiveMaterial;
    }

    isElectrified = connectedConductorPower;
}

private void CheckPowerSource()
{
    if (isPowerSource)
    {
        isElectrified = true;
        _renderer.material = activeMaterial;
    }
}

private void SetupPrivateVariables()
{
    _renderer = this.GetComponent<Renderer>();
}

private void ProcessNewCollision(Collision collision, bool doAdd)
{
    if (isPowerSource == false)
    {
        Conductor otherConductor = collision.collider.gameObject.GetComponent<Conductor>();

        if (otherConductor != null)
        {
            if (doAdd)
            {
                _conductors.Add(otherConductor);
            }
            else
            {
                _conductors.Remove(otherConductor);
            }
        }
    }
}

}

Edit: I just found this question, which is similar but I'm not sure how it would handle a disconnect.

Edit 2: I ended up going with the accepted answer and built a "pulse" into the system. Basically power sources pulse down the chain and each object passes the pulse onto the objects they are connected to. If an object doesn't receive a pulse, then it shuts off since it knows it doesn't have power. This system isn't foolproof, and for large networks would slow down the framerate but my networks aren't very large and only a small handful of networks per scene. I went with this system for the accuracy it gives and flexibility. I can have any number of power sources and the network can spider out and loopback on itself without issue.

\$\endgroup\$
1
\$\begingroup\$

It looks like you're not considering the connection state of everything in the chain, meaning that when you process conductor A, which is connected only to B, B may have not yet been updated - meaning that B.isElectrified may still be true, even when its only connection is A.

You could make the check recursive:

public bool isElectrified {
    get {
        return isPowerSource || AnyConnectionIsPowered(null);
    }
}

private bool AnyConnectionIsPowered(Conductor ignored) {
    foreach(Conductor c in _conductors) {
        if(c == ignored) { continue; }
        if(c.isPowerSource || c.AnyConnectionIsPowered(this)) { return true; }
    }
    return false;
}

You could make all of your conductors update based on a pulse sent out by power sources, passing the pulse along to their connections:

private void ProcessConductors() {
    if(isPowerSource) {
        foreach (Conductor c in _conductors) {
            c.Pulse();
        }
        return;
    }
    ...
    isElectrified = false;
}

private void Pulse() {
    isElectrified = true;
    foreach(Conductor c in _conductors) {
        c.Pulse();
    }
}

These are just a couple of suggestions. The most important thing to consider is that you must know the state of everything attached to a Conductor before you can accurately determine that Conductor's state.

\$\endgroup\$
  • \$\begingroup\$ Thank you, I knew it was mostly a logic problem and that I'm thinking about it the wrong way. I was too focused on each item somehow knowing what power state they should have with only the connected nodes as a source of information. I'm going to try to work out the pulse method. My only problem there is I'm not sure how to "turn off" blocks that don't get the pulse but I have some ideas. \$\endgroup\$ – Tyler C Apr 30 at 14:22
  • 1
    \$\begingroup\$ My example simply resets the state after each update - this means it will remain inactive until it receives a new pulse. \$\endgroup\$ – Joe Apr 30 at 14:33
  • 1
    \$\begingroup\$ Because they're double connected, you'll have to figure out how to make your pulse ignore its origin, or you'll wind up in an infinite state - I realise I've omitted that from my answer. \$\endgroup\$ – Joe Apr 30 at 14:35
  • \$\begingroup\$ No worries, I appreciate you taking the time to answer. Not sure why this stumped me so badly. \$\endgroup\$ – Tyler C Apr 30 at 15:00
  • \$\begingroup\$ Ended up going with a pulse more details in edit for anyone who finds this. \$\endgroup\$ – Tyler C May 1 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.