How to simulate Electricity in Tile-based game

Good point. I think it just depends on how you process the node tree. My plan was originally (before I thought of using a much simplified model) to go through the tree from consumers to producers (“upstream” if you like). Each move up the tree I would check the incoming energy (which may be from multiple sources/blocks) and outgoing energy (also possibly from multiple sources/blocks), and make some “smart” decision about that.

[quote=“Springrbua,post:20,topic:51560”]
If consumer(1) knows about both Generator(1) and Generator(2) then a rule could for example be that it will take 50% from generator (1) and 50% from generator(2), or more if any of the generators is unable to supply 50%.

[quote=“Springrbua,post:20,topic:51560”]
Same as the above. I was thinking of doing this by moving all energy one “step” from generators to consumers during one update of the network. The interval between updates would then influence how fast energy would move. With electricity, however, this is pretty much instant, so maybe it will not work well then.

But when you step from consumer to producer, the consumer does not know how much power the generator produces. Also the nodes between the generator and the consumer don’t know the “power-level” of the network, except the node right next to the generator and the generator itself.
Also, as you are processing backwards, you only know about the next (or previous as it is up or backstream) nodes power-level, but not about other nodes, which may consume from that node, so you don’t know the exact power you will receive.

A posible solution i had in mind, before reading the tree-node solution, had more or less the same problem:
You have the electricity layer, as the op said. If you add or change an electric element, check all its neighbors on the electricity layer and if there is any other electric component (generator, consumer, switch etc.) and update them. Do the same for all those nodes.
So if you add a generator (for example) check its neighbor tiles.
If there is one or more connection or consumer, add the generators “power level” (or part of its “power level”) to the connection/consumers “power level”. If the neighbor is a consumer, you can stop, as a consumer does not affect other nodes. If it is a connection, update its neighbors with the new power level.

Just think of it this way:
One node system has energy storage that is the energy storage of all things connected to this system combined.
A consumer can request energy from the system, and if it does, the system has to decide how: There are a couple of possible options. (We’ll get to this in the example)
A producer simply produces energy and stores that energy in it’s local energy storage.

So for example, you have consumer 1 and consumer 2, as well as producer 1 and 2 connected to the same network.
producer 1 and 2 have a 20k energy storage. So the system has 40k energy storage in total.
When one of the consumers request 40 energy, the system could do 2 different things: It could drain the energy storage of producer 1 by 40 energy, or split the energy request to all the energy sources and take 20 energy of each, though this might be harder since you can’t always drain all the generators (if one is a little empty for example). (Like Grunnt sugessted).

You could also make this configureable for the user. So they tell you which energy sources should be drained first, etc.

I wouldn’t implement that with any node-tree system. My system would simply be implemented with two arrays containing the Consumers and Producers:


public class EnergySystem {
  private final ArrayList<Consumer> consumers;
  private final ArrayList<Producer> producers;
}

And if you build a wire that is not connected to anything, that creates a new EnergySystem.
If you connect a wire to a wire, that wire is going to take the EnergySystem of the wire it’s connected to.
If you connect a wire to two or more wires, that wire merges the EnergySystem of all the wires it was connected to.
If you connect a consumer or producer to a wire, it’s added to the array of the EnergySystem.
If you remove a wire, you need to split the Energy system. Thats the only thing that might be a little tricky :slight_smile:

[quote=“matheus23,post:23,topic:51560”]
Yeah that’s precisely what I’m doing. Splitting energy systems is indeed a bit of an issue, but it’s pretty easy to update the networks using a flood fill search.

Wow a real simple approach, but it is not applicable in the situation, where you want to have energy-loss over the way.
So lets say every 5 tiles the enery-level falls by 1, the way the energy takes would matter and therefore you cannot have a network with energy produced and consumed, but you need to store the energy for every part of that network.
Also with this simple approach it wouldn’t be possible (or at least not easy) to have a network with diodes (or One-Way cables), which would allow the network part of one side to affect the networkpart at the other side, but not vice versa.

Anyways, i really like this approach, it will be working for many (or even most) energysystems. The splitting of the network will need some calculations (worst case: recalculate the whole network), but i guess it is stil easier then implementing a tree-node system :stuck_out_tongue:

Wow you guys put some thought into that :stuck_out_tongue:

Edit:Could someone please tell me how to put code snippets in my posts, i tried some html tags (code, pre), but none worked :confused:
I want my posts to look cleaner.

[quote]There is nothing wrong with recursion in itself, it can be a quite elegant solution to many problems. However, the issue with recursion is that for each recursive call, some things get stored on the stack (a piece of memory where local variables are stored). So if you do many recursive calls (e.g. because you are parsing a large tiled grid using this approach) you may run out of stack memory and get exceptions.

So if you want to use recursion, you should be aware of this and ensure that there is an acceptable maximum “depth” of recursion. This means that the size of electricity networks must be limited somehow.
[/quote]
I heard of the stack issue but never thought that i would be an actual issue, as i thought it would be very hard to actually run out of memory. Do you know some numbers, or a way to check how much is possible?
Also, a node tree is of what i understood, An object (parent), that contains (one, two, or more) children, and the children have children again etc.
To me it seems like composition of objects.

So if i had an interface which every electric component implements, let’s say with the method impulse(): To run through the components i just had to call =>

Battery-> impulse child -> impulse child -> and so on, it would be the same method name, but not really recursion(it would be the implemented method of another object), since in fact i would just run through the objects in a direct manner, and the method in the Battery component would not be calling itself again.
In this case, this seems like the most optimal way to ‘flood-fill’ the circuit. There would be basically no wasted method calls at all, depending on how it is done.

And this way I could easily implement an internal mapping/rules, of where the impulse should flow to, based on states etc.
So it would be easy to add new features, and even a bit more complex stuff like ‘internal circuits’(ic’s);
Is there any issue with the stack memory then? (Like in the next example)
Edit: I read a little about heap,stack etc: If there are no local variables (which I avoid 99.999% in methods), there would/should be no problem in in recursive methods, even if they run thousands of times. Or am i wrong?(Memory, is still totally alien for me :confused: )

(Please excuse my pseudo code)
Update circuit => Battery.emitImpulse() -> Battery.cableNode.impulse() -> Cable.switchNode.impulse() -> Switch.ConsumerNode.impulse() -> etc

I dont know how it could be more efficient, plus, it could easily be saved until the next iteration, and only had to be overwritten while passing impulses around.(if desired)

I like the idea of all your methods, (and btw thank you for sharing it and beeing patient ^^), especially that you keep track of the differrent objects in different arrays.
I will also implement a method to acces/save different object/component types in different arrays, because i will eventually need to order them by type.

And what i havent understood, or simply didnt see it in all your answers(excuse me if that is the case), how do you actually iterate your components, as you said a flood-fill, since you would use array, are you connecting it via meta-objects(like nodes) or by index or something ? :stuck_out_tongue:

In this case i though a tilemap would make it easier, but as it seems, for once, a tile map actually makes it harder :stuck_out_tongue: (At least for me)

Thank you guys again very, very much for the help and suggestions! <3
(Including answering some of my noob questions => going to read up some java memory/stack stuff)

Well, as i take a look at the solutions we came up with here, i see, that some of them face different kinds of electricity networks (at least 2).

Think about minecrafts redstone, which is some kind of electricity. The signal strength goes down every block, until it reaches zero.
With @matheus23 energysystem method that wouldn’t be possible.

Now instead think about a lossless system, where every generator/producer feeds the whole network and every consumer takes energy from the network.
This is not possible with @JJengineering mehtod, as the tree is monodirectional. Take the case i wrote before:

There the Consumer(1) one would not know about the Generator(2), as it is connected to a childnode of Consumer(1)s parent and you iterate from parent to child.
So this network would result in something like:
Generator(1) feeds Consumer(1)
Generator(1) feeds Consumer(2) if the connection (*) allowes it (is it a child or a parent of the previous connection?)
Generator(2) feeds Consumer(2) only.


public class Wire {
	public final Node a, b;

	public Wire(Node a, Node b) {
		this.a = a;
		this.b = b;
		a.wires.add(this);
		b.wires.add(this);
	}

	public void cut() {
		a.wires.remove(this);
		b.wires.remove(this);
	}
}


import java.util.ArrayList;
import java.util.List;

public class Node {
	public int energy;
	public int capacity;

	public List<Wire> wires = new ArrayList<>();

	public void tick() {
		if (energy == 0 || wires.isEmpty())
			return;

		while (true) {
			Node target = null;
			for (Wire wire : wires) {
				Node remote = (wire.a != this) ? wire.a : wire.b;
				if (remote.energy == remote.capacity)
					continue; // remote node is full
				if (remote.energy >= this.energy)
					continue; // cannot spread against a voltage potential
				if (target == null || remote.energy < target.energy)
					target = remote; // we found a new target
			}
			if (target == null)
				return;

			this.energy -= 1;
			target.energy += 1;
		}
	}
}

A generator is a Node:


public class Generator extends Node {
   public int production = 100;

   public void tick() {
      energy = Math.min(energy + production, capacity);

      super.tick();
   }
}

A consumer is a Node:


public class Consumer extends Node {
   public int demand = 33;

   public void tick() {
      int taken = Math.min(demand, energy);
      energy -= taken;
      if(taken < demand) {
         // make something crash and burn
      }

      super.tick();
}

Generate, spread & consume electricity:


for(Node node: world.nodes) {
   node.tick();
}

@Springrbua I see what issue you are pointing out.

You are certainly right about that, and what i would do about it is a little more complex than a simple iteration from Parent to child on each node.

I think of each component, to have inputs and outputs. (which is the part of the hole thing im trying to figure out atm)
Also, i’ll have to limit impulses in case where for instance: a generator is connected to another generator over a cable.
I’ll map a generator’s output to a cable and then define that cable node as ‘input’ and the other side as output as needed, if the outputs of two generators are connected through one cable, thats is for instance a case where nothing should happen, or some sort of event (fire, breaking components etc).

When other people play my game, they cant know what works and what doesnt, that makes it all even worse.

So i will need a mapping of inputs and outputs.

So you are absolutely right, these are some issues aswell (pretty big ones even), but i think when one has the right data structure of classes and mapping of the components and all the different cases, that should be doable.( I wich i could brainstorm and just throw an adjsuted technique in here, but for that i need some hours with a pen and paper :stuck_out_tongue: )

The ‘beauty’ of my design is that it models reality (although in reality it converges to a solution much quicker), is trivial, and just works, no matter how complex your scene.

I don’t like the crash and burn part though. Is it possible to send the energy back somehow? Or just let it be in the storage of the producer (that storage would need to be added though).

Btw, how would a storage be implemented then, Riven?

No energy consumption in ‘crash and burn’:


public class Consumer extends Node {
   public int demand = 33;

   public void tick() {
-     int taken = Math.min(demand, energy);
-     energy -= taken;
-     if(taken < demand) {
+     if(demand <= energy) {
+        energy -= demand;
         // up and running!
      }

      super.tick();
}

Implementing a storage (a battery):


import java.util.ArrayList;
import java.util.List;

public class Node {
   public int energy;
   public int capacity;

   public List<Wire> wires = new ArrayList<>();

   public void tick() {
      if (energy == 0 || wires.isEmpty())
         return;

      while (true) {
         Node target = null;
         for (Wire wire : wires) {
            Node remote = (wire.a != this) ? wire.a : wire.b;
            if (remote.energy == remote.capacity)
               continue; // remote node is full
-            if (remote.energy >= this.energy)
-               continue; // cannot spread against a voltage potential
            if (target == null || remote.energy < target.energy)
               target = remote; // we found a new target
         }
         if (target == null)
            return;

         this.energy -= 1;
         target.energy += 1;
      }
   }
}

@Riven: I guess, there is a problem again:
As a Wire can only be connected with a Node but a wire is not a Node, Wires can’t be connected with each other, making complex, splited networks imposible.
As a Node cannot be connected to a Node, a “Network” of Generator+Consumer (for example Battery+Light-source) needs at least 3 Tiles (Generator, Wire, Consumer).

You connect a wire to a wire (and them some) by connecting them both to the same Node. I don’t see why that would be a problem. It models reality, as no sane person would connect high-power wires (in a knot). Something small or big will hold them together (a Node).

Generator ---------- Pole --------- Pole --------- Consumer | | Consumer

@Riven

Hi Riven :slight_smile:

Thats about what i had in mind, just wasnt sure about the implementation. This way it’s easy to add new components.

I like the way you implemented the wires within the Nodes, but that is something i will probably change, but then again, hooking up the wires and components in a tile map would be more complicated again. I think i need the wires to be a Node also, but that isn’t much of a problem.

But from what the structure is in general, i like it alot.

Thank you very much for the snippet :stuck_out_tongue:

Btw, can someone please tell me the html tag for the code snippets? Can’t seem, to find the right one Oo

Well i think about it like for example the redstone in minecraft. A wire is 1 “Block” (or Tile) of redstone. So the connection between 2 nodes can be done over many Wires, every wire fills up one Tile on the Electricity Layer.
EDIT: So the “pole” is some kind of “connection node”, makes sence :slight_smile:

[ code]System.out.println("p0wer!");[ /code]

Pole == Node, as every Node is a “connection node” (after all it knows which wires it is connected to), I just named it “Pole” to show how it models reality.

[quote=“JJengineering,post:35,topic:51560”]
I wouldn’t do that. A wire is conceptually very different from a Node. Making a Wire a Node will lead to all kinds of workarounds and hacks, as it doesn’t match reality - and reality is the easiest to wrap your head around.

@ Riven
Thank you very much for the tag, i’m glad i can post some code now :stuck_out_tongue:


glGenerateTrees();
glDrawTrees();
System.out.println("Ahh finally");

EDIT: [quote]
JJEngineering: I think i need the wires to be a Node also, but that isn’t much of a problem.
Riven: I wouldn’t do that. A wire is conceptually very different from a Node. Making a Wire a Node will lead to all kinds of workarounds and hacks, as it doesn’t match reality - and reality is the easiest to wrap your head around.
[/quote]
Now where you point it out once more, I see how right you are, i’ll try that in code the next few days :slight_smile:
After all, i try to implement and do things the most ‘conceptual’ way, but that didnt seem so easy to me a few days ago :slight_smile:
But now i’m definitely advancing with my project, instead of stalling because i try to force a concept/design that doesnt fit the case.

@ Springrbua
Connection nodes used like that really make sense, but it depends on who uses i guess :stuck_out_tongue:

@Everybody
You guys all helped me so much, im finally on the right path, but i need to go over it for some days, to know how far i want to go and what suits the game best.
I can’t thank you enough :slight_smile:

[quote=“Riven,post:37,topic:51560”]

So when is a node created, in say, a Minecraft electricity mod? So you have the wire block and when you put them one after another, nothing happens, but when you connect a wire to multiple other wires it becomes a node?

@matheus23

As far as i understood, it works like this.

A Node: has a list of wire objects(can be none, or a few), the wires are the ‘connection’(i.e reference) this node has with another node.

A Wire: has two instances of Node object, as Riven put it, Node ‘a’ and Node ‘b’.
Now comes the clever part, when you create a wire, you pass the two Nodes as parameters TO the wire, you want to be ‘connected’ (referenced).

So now both Nodes have a pointer to a wire, and the wire has two pointers to both nodes.

So to create the ‘connection’:


Step 1) Create: new Generator(extends Node) object
Step 2) Create: new Light(extends Node) object
Step 3) Create: new Wire(generatorNode, lightNode) object (also adds itself to the wire list in the referenced nodes!)

Now, the Generator has the wire in its list AND the Light has the wire in its list, the SAME,
and the wire simply knows about the two Nodes that are referenced to it.

Thats a great idea in fact, but now i’m looking at how i can figure out an easy way to map this, since every wire is passed to two (possibly more) Nodes.

Then you can just iterate the nodes and update them (or even tick/impulse the generators and let it run its way thorugh the nodes by itself, which by now, seems to me like the bad approach for this technique)

And now, i need to find a proper way to apply this beast into the tile based map :stuck_out_tongue:

Credits to Riven