0 votes

Hello!

I was wondering if anybody knew how to make a node act and simulate like an actual power cable. I was working on a simulator of being in charge of a electric power plant company and I was able to make wires read from the power plant, using Boolean to tell whether receiving power is true or false. The problem though is that if i remove one of the wires that still receives power from the plant, but connected to other wire nodes, the power is still true to other wires.

I now ran into a bit of a dead end realizing I have no Idea on how power cables work in programming, I wanted to achieve a similar effect on how Minecraft handles Redstone power when one of them can easily disconnect between two other redstones and cause one of them to lose redstone energy.

Here is the code in case anybody is interested:

extends Area2D

# class member variables go here, for example:
# var a = 2
# var b = "textvar"
var mouse_hover = false
var tracking = false
var detect = false
var power = false
export (bool) var debug = false

func _ready():
    # Called every time the node is added to the scene.
    # Initialization here
    self.connect("area_enter",self,"_on_area_enter")
    self.connect("area_exit",self,"_on_area_exit")
    self.connect("mouse_enter",self,"_on_mouse_enter")
    self.connect("mouse_exit",self,"_on_mouse_exit")
    set_fixed_process(true)
    set_process_input(true)
    pass

func _fixed_process(delta):

    if debug == true:
        print(power)
    else:
        pass

    if detect == true:
        var obj = get_overlapping_areas()
        for i in obj:
            if i.is_in_group("Power_Plant"):
                power = true
            elif i.is_in_group("Wire"):
                if i.power == true:
                    power = true
            else:
                power = false
                pass
    else:
        power = false
        pass

    #When the object is clicked, the Fixed Process tells the object to follow the mouse position, Globally.
    if tracking == true:
        self.set_global_pos(get_global_mouse_pos())
        pass
    else:
        pass

    pass

func _input(event):


    #Click on the object to allow the Fixed Process to pick up the object and move, works when "hovered" over
    if (event.is_action_pressed("ui_left_click")):
        if mouse_hover == true:
            tracking = true
            pass
        else:
            pass
        pass

    #When Click is released, it causes the object to stop following.
    elif (event.is_action_released("ui_left_click")):
        tracking = false
        pass
    else:
        pass

    pass

func _on_area_enter(area):
    detect = true
    pass

func _on_area_exit(area):
    detect = false
    pass

#These two functions allows mouse hovering, to allow specific object to click on rather than let all "AREA" objects get
#clicked on.
func _on_mouse_enter():
    mouse_hover = true
    pass

func _on_mouse_exit():
    mouse_hover = false
    pass
in Engine by (203 points)

Your question is quite general, there are tons of ways of making a wire system, or something that acts like it. Details count as well.
Your script also includes input management but I can't tell what you really want by just reading it.

The only advice I can give is, generally, cables conveying power can be represented as a graph (general or grid-based), because it's all about connecting stuff to other stuff.
Then you must choose how it behaves when you switch power: does it traverses the network instantly? Does it have some propagation logic instead? Do you need execution order to prevent concurrent access or endless loops?

In Minecraft, redstone is updated on a grid as a mix of the two:
When a block changes state, it updates its neighbors instantly, which update too in one go, until it reaches some special blocks (repeaters, pistons, whatever) or runs out of power over the distance. These are put in a queue and are dequeued on the next tick, which starts again one more iteration etc until the queue is empty.

In another prototype I made, I handled power differently by representing it with a token that traverses a graph (nodes, grid, whatever). When power is 1, an "on" token is emitted and runs through the graph at each iteration (1 per frame or until it gets to the end). Same goes when power is 0, I send an "off" token. Then the token can change state during its course, like loosing power, increasing power, pick some information, split in two...

Lots of ways to do cables. One thing to avoid though: stack overflows and infinite loops :p

Keep track of what things are connected is called the dynamic graph connectivity problem. A naive solution is to traverse the graph on every update, but this is linear in the number of edges and might be slow for large nets. There are more efficient algorithms that run in log or log^2 (I can't remember) time in the number of edges, but they are significantly more complicated to implement.

2 Answers

0 votes

I think your problem may not be programming but design.

This is just an idea of how to approach the situation:

  • You have a power plant that generates power, and that may be the end of the basic power plant.

  • Now the fun part, wires, wires just define a connection, from A to B, what i understand of your description, A and B could be a power plant or a set of wires, but to the wire it does not matters, it is connected to things that give or receive power.

Then if a wire is removed, all the connected things to A and B should get notified of the change (does not matters if are wires or a power plant) and trigger a cascade of notifications to their connections to update the power supply data.

The same may apply if a connection consume power from the grid, all the grid will have to be updated.

The way you notify changes on the grid will depend on the design, could be signals, notifications, group calls or directly call methods on the connections, the order of the update may be important too (you may have loops and end on a lock).


Regardless of the method you use, do it on paper first, solve the most simple situations, then try more complex ones, attacking all at once will just pile up bugs.


ps: Having a underlying graph representation of the power grid could be better for more complex situations but you will have to study a bit about graph data structures.

by (7,890 points)
+1 vote

It's a broad question that deals with data structures and algorithms. You'll want to study things like directed graphs.

A simplistic approach to your problem, assuming you have a one way flow might look something like this:

extends Node2D

class PowerNode:
    var power_on = false
    var outputs = []

    func add_output(node):
        outputs.append(node)

    func set_state(state):
        power_on = state
        for connection in outputs:
            connection.set_state(state)

    func disconnect():
        set_state(false)

func _ready():
    var a = PowerNode.new()
    var b = PowerNode.new()
    var c = PowerNode.new()
    var d = PowerNode.new()

    a.add_output(b)
    b.add_output(c)
    b.add_output(d)

    printt("Is power on at D?", d.power_on == true, "Is power on at A?", a.power_on == true)

    a.set_state(true)

    printt("Is power on at D?", d.power_on == true, "Is power on at A?", a.power_on == true)

    b.disconnect()

    printt("Is power on at D?", d.power_on == true, "Is power on at A?", a.power_on == true)
by (5,232 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.