Every Wire is passed to exactly two Nodes, not more.
You don’t really have to adjust the algorithm & data structure for a grid based map. Make a Node for every tile, and add Wires during gameplay. Sure, this can be optimized, but make it work first - optimize if it actually turns out to be slow.
[quote]Every Wire is passed to exactly two Nodes, not more.
[/quote]
I might not have it 100% down on the conceptual level, but if i have a tile that leads the electricity from one tile, to the three neighbour tiles (Left -> Up/Down/Right), then i could make a ‘CrossConnection Node’, that has 4 wires, each referenced to the ‘CrossConnection Node’ and the other node it is connected to, would that be the right interpretation of the concept?
It seems to be the simplest thing, and as Riven pointed out, that a ‘Wire’ is best used in the way he explains it, becomes now clear to me. It seems so obvious now
Sorry i misread you post, no i dont want to connect adjacent tiles, at least for now, but with this techniques that would be easy
Having nodes and wires as separate things also enables easy “wireless” game mechanics, i.e. a node over here can send power/etc to a node across the room. In game this may be a “wireless network,” a “force field,” or simply programming convenience, as the “wire” can simply be part of the background/tile image.
Thats right, but I want to implement it in a way, where the whole network is visible, since the game mechanics are based on a destroyed eletricity network.
In fact when i started i wanted to do it wireless, but as i carved out my game mechanics, it was clear to me that i need some kind of electricity that runs over tiles, that are visible and immediately identifiable. (as in Prison Architecht, you look at the ‘electro layer’, and can see relatively fast whats wrong)
OK, assuming a not too extensive power system, here’s how I’d do it;
A hashmap is like a huge array for sparse data and is nearly as fast.
I’d make three hashmaps: ‘generators’, ‘receivers’ and ‘wires’ where the key is the map index (x+y*mapwidth). This gives fast access for any given tile.
These tables will all contain the class;
class PowerNode
{
float availablePower;
int mapIndexNorth;
int mapIndexEast;
int mapIndexSouth;
int mapIndexWest;
}
When the player places a power-related item on a tile I add it to the appropriate table (key=x+ywidth) and link it into the power system by checking neighbouring tiles (key=(x-1)+ywidth &c) for entries in the power lists, and setting the appropriate connections fields. Same for removal of items.
In the game loop to update the power system I’d loop over the ‘generators’ hashmap, get all connected keys and store them in an ‘open’ list, updating their node’s availablePower as I did so.
Next I’d loop over the open list. If it’s a receiver it will reduce the power available. If it’s a wire it just transmits. I add this node to a ‘closed’ list and add any connections not in the ‘closed’ list to the ‘open’ list, updating their power also.
Loop over the open list as above until done.
This would spread the power out from the generators to the receivers pretty efficiently, allow power to be ‘drained’ by the receivers and for receivers to also act as transmitters.
Handy for rendering too as you can find if a tile has power-related graphics pretty quickly, and how much power is there.
Maybe not the most efficient way, but better than scanning a huge array.
PS Not quite sure how this would work if there were closed loops in the wiring!
So in @Rivens solution a wire is not existing on the tilemap right? Instead it is just a connection under the hood, which is used to manage the network.
Therefore a network like Generator-Connection-Consumer would be GeneratorNode-Wire-ConnectionNode-Wire-Consumer but use up only 3 Tiles on the map right?
That sounds great and pretty easy to use.
This method opens a lot of possibilities, so itis possible for the generator to give its power to many Nodes, all over the map, cause it has a list of Wires.
Also a “SwitchNode” wouldn’t be verry hard to implement, it just does not (or does, depending on the Switches status) foreward the energy.
It would also be possible to have some energy loss over a distance.
I like that system, i just thought about it the wrong way (Wire is not a tile, while a Node is a tile).
Great stuff I like the tick-wise solution by Riven, it’s somewhat like the spread of water. Easy to understand.
Here’s what I ended up with (note this is a simple approach where the production, consumption and buffering is handled cumulatively: as in I just add everything up). However, networks that are not connected behave independently. Also, the network graphics give an indication on the state of the network: the left network is empty (buffer and lines are dark), while the right network is full (everything glows more brightly).
Looks cool, i really like that energy system thing, makes it hard for me to focus on my planned project, as this seems verry interesting
Maybe i ll try it out one day
Exactly Thats what i had a hard time with understanding, i thought a wire had to be a tile itself.
Well now it still is but wrapped as a node containing the wires.
@Grunnt
Are you adding the electricity system tiles by code, or during gameplay? And how do YOU iterate the system, iterate the node tiles by calling the tick method?
Btw looking super great there, i wish i was that far
Thanks This thing is progressing quite nicely, but it’s actually the second attempt at a game like this (first one was a design-and -crash-your-own-moonlander-type thing which I didn’t think through good enough and did not work out very well).
On how I do this: here’s some code I use. First of all, I build the energy networks whenever I spawn a new ship (which is based on a design). Also, I will probably have to do this, or something like it, whenever blocks on the the ship are damaged or repaired. producers is an array filled with all generators in the grid (I just do a full scan of the grid to find them). temp is an attribute of the Ship where I store the things that do not need to be saved but can be generated based on the saved data, like the energy networks.
// Build energy networks starting at the generators
while (producers.size > 0) {
Cell producer = producers.pop();
if (producer.temp.eNetwork == null) {
EnergyNetwork eNetwork = buildNetwork(producer);
temp.eNetworks.add(eNetwork);
}
}
Each network is built by doing a flood fill from the selected generator outward. Along the way the total generator output and buffer capacity is calculated:
EnergyNetwork buildNetwork(Cell producer) {
EnergyNetwork eNetwork = new EnergyNetwork();
Array<Cell> queue = new Array<>();
queue.add(producer);
while (queue.size > 0) {
Cell cell = queue.pop();
// Is this an energy cell?
if (cell.temp.eNetwork == null
&& cell.module != null
&& (cell.module.design.eConduit || cell.module.design.epsGenerated > 0f
|| cell.module.design.epsConsumed > 0f || cell.module.design.eBufferSize > 0f)) {
ModuleDesign mDesign = cell.module.design;
// Add surrounding cells to queue to examine whether these are connected as well
addSurroundingCells(queue, cell.gridX, cell.gridY);
// Add to totals of network
if (mDesign.epsGenerated > 0f) {
eNetwork.eGenerators.add(cell);
eNetwork.epsGenerated += mDesign.epsGenerated;
}
if (mDesign.epsConsumed > 0f) {
eNetwork.eConsumers.add(cell);
eNetwork.epsConsumed += mDesign.epsConsumed;
}
if (mDesign.eBufferSize > 0f) {
eNetwork.eBuffers.add(cell);
eNetwork.eBufferSize += mDesign.eBufferSize;
}
cell.temp.eNetwork = eNetwork;
}
}
return eNetwork;
}
And once I have this I update the networks each game loop by determining consumption and calculating the effectiveness of devices that consume energy from the network:
// Update energy production and consumption
for (int i = 0; i < temp.eNetworks.size; i++) {
EnergyNetwork eNetwork = temp.eNetworks.get(i);
eNetwork.epsConsumed = 0f;
for (int j = 0; j < eNetwork.eConsumers.size; j++) {
Cell consumer = eNetwork.eConsumers.get(j);
if (consumer.controlActive) {
eNetwork.epsConsumed += consumer.module.design.epsConsumed;
}
}
eNetwork.eBuffered += eNetwork.epsGenerated * delta;
float consumption = eNetwork.epsConsumed * delta;
if (consumption <= eNetwork.eBuffered) {
eNetwork.eBuffered -= consumption;
eNetwork.effectiveness = 1f;
} else if (consumption > 0f) {
eNetwork.effectiveness = eNetwork.eBuffered / consumption;
eNetwork.eBuffered = 0f;
}
if (eNetwork.eBuffered > eNetwork.eBufferSize) {
eNetwork.eBuffered = eNetwork.eBufferSize;
}
}
Effectiveness is for example used when determining the number and speed of particles generated by thrusters, and the force which thrusters apply to the ship body:
Great approach, can’t say much more than that ^^
I’ll follow your blog for the game (looks awesome already, and love the art to btw)
My project is way to ambitious for the time beeing, but i’ll use the things we discussed here in a newer, simpler project.
And also, thank you all endlessly for helping me so much!! Greetings and all the best