Implementation of the electricity circulation in wires and electrical components
-
Hi everybody. I want to develop a game on the topic of electronic (circuits, logic gates, ...). I am using Qt 5.10 on Windows.
Precisely, i want to know what visual (I have an idea on how to implement the logic) technique (Canvas from QML, VPlay, custom component, ...) to use to implement wires and component and secondly how to implement the fact that the electricity is circulating in the wire and/or the components. Please help me. I really have problems to start the visual part.
I want to implement the circulation of the electricity in the wires like on this example :
-
I've taken your image and moved the parts around slightly so that each node in the wiring fits within a grid. (see below)
I'd use the same wire image for all my wiring. It would be a blue line which starts in the middle of the image, and goes to the right edge. The image would be the size of a grid cell, say 32x32 or something.
I'd make a component called WirePart.qml
It would have that image in it, and it would be able to set the image's rotation to 0, 90, 180, or 270. It would also have a variable called "flow", a string, which could have the values "IN", "OUT" or "OFF"If flow == "IN", then I would animate a red ball on top of the image. It would start at the outside edge of the image, and move to the center of the image. It would last 1 second. When it got to the end, it would start over
If flow == "OUT", then I would reverse the animation.
If flow was "OFF" then I would have no animation.
Then I would make another component called WireNode.qml
It would have 4 instances of WirePart, with ids called North, South, East, West
Each one of those instances would rotate the wire image, either 0, 90, 180, or 270WireNode.qml would also have a function called flowIsComingInFrom(direction).
That function would set the flow on the WirePart with id <direction> to "IN".
For example flowIsComingInFrom("North") would set the WirePart with id "North" to "IN".
The rest of the WireParts would get their flow set to "OUT", and if any of them had a neighboring WireNode, then I would call flowIsComingInFrom() on them.WireNode.qml would have another function called flowIsOff() which would set all 4 WirePart's flow to "OFF"
It would also check neighboring cells and call their flowIsOff() function.Instances of WireNode would go into a grid to create the schematic for the wiring.
Whenever a WireNode instance was placed inside the grid, it would have a reference to the grid, and it would look at the cells to the north, south, east, and west of it. If any cell had a WireNode instance in it, then it would turn on the visibility for the corresponding WirePart. It would also turn on visibility for the corresponding WirePart in the neighboring WireNode.
The other electronic parts -- the switch, the bulb, etc. -- would reside on top of the grid, aligned so that they look like they connect with the wiring. Each electronic part would need a reference to the WireNodes that they connect to.
Whenever a switch component is clicked on, then it calls its neighboring WireNode flowIsComingInFrom() function. For example flowIsComingInFrom("West"). This would cause all the WireParts to animate, even though some of them would be invisible. And the animation state would propagate through all the WireNodes.
Hope it helps.
-
@JeTSpice and @Leonardo thank you very much. Waouh !! That's a great technique. I thought that it could be achieved without using a grid system. I give you a little explanation (simplified) of what I have created (it is 100% logical not visual). I created a component called Gate.qml that has the attributes entryA and entryB and output, instances of a class called Entry. The different entries and outputs are connected with instances of a component called Wire and when a wire entry is activated, its output is automatically updated. So my problem was the following : how to represent a certain circuit (with gates, wires, entries, ...) easily. How to display the complete circuit automatically only from a two dimensionnal array for example only by specifying the gates' positions and their relationships (for example GATE_A.output connected to GATE_B.entry) --- the wires have to be generated automatically from these relationships) ?
But, if I use the grid system, do you have an idea on how to divide the black container into small parts of a grid ? How to place a component instance at a specific position of the grid. And how to update the wires' position and layout automatically when logic gates are moved (also the zigzag formed by the wires must be perpendicular and not oblique) ?
-
Wow, I'd totally play this. I love factorio... this could be right up there!
For square lines you can probably just cheap out entirely and use QML Rectangles for straight sections! You could even use radius to smooth the ends etc. Don't forget you can Rotate and add Behavior animations and stuff - you could really make this shine.
I wouldn't think you'd need sprites or predrawn images at all - but maybe that is the answer? I'm not great with visual art so I do tend to use lines and curves.
I also wouldn't think you'd need to use a grid as above. You could still use real / float values for positions and it still work great.
You would only need to know object dimensions and ratios and only expose interfaces to the in / outs.
Internally, you define what component has what and where those whats are. Then when you use the object you set it to whatever size/rotation you like. So you could just say dynamically declare
Circuitry objects as Circuit { from: GATE_A.output; to: GATE_B.entry }Circuit could be a method of using Rectangles if your circuits are always square ended. You could make height and length differences break / change course in it's middle. It's basic AF. Thing doesn't have any collision detection... but that advanced routing stuff would be your fun problem... circuit selection and movement of where the course change occurse could be things on Circuit also like: breakAtX breakAtY or something so they can be positioned finely.
Say component A has 2 entries, if you just define those positions as being on the left. the first 1/4 from top and the second 1/4 from the bottom... it can scale and move easily and still have lines follow and stuff. It's x & y are simple binding formulas.
I think it's a great concept and do let us know how you progress with this... it sounds fun to develop and fun to play.
-
As far as zig-zagging, a good way of doing that is using a* (called "A-star"), a path-finding algorithm. Its more complex than I can describe in this post, but it will redraw the lines of your wires, should you move an electrical component around which has wires attached to it. Maybe there is an example of a* in Qt somewhere. It can be done in qml. It does not have to be in C++. I would stick with perpendicular. Oblique means you have 8 possible orientations for wires, instead of just 4.
I agree with 6thC that rectangles are even better. But I stand by my grid. It does not have to use the Qt Grid class. It can be as simple as a 2d array. In fact, considering that you may be using a*, then I would use a 2d array. The array would keep track of what cells had wires in them. Maybe even use that to keep track of the larger electrical components. For instance, the switch looks like it would always occupy 5x5 cells. Whenever a wire were moved, it would put a -1 (or null) in its old place and a reference to itself (its own id) in the new place in the array. then it would check the position in the array above, below, left, and right, to see if there were components referenced there which needed to update. This "checking for neighboring wires and updating them" is the same technique used to create tiled backgrounds on rpgs. So maybe google a tutorial on how that is done to get a better idea of how the wires can update.
To convert any components' x,y into grid coordinates, just divide by the cell width, then do Math.floor(), and then subtract 1. So a wire at 64, 64 is in cell [1][1] in the 2d array. Because floor(64/32) - 1 is 1. If a player drag-drops a wire onto the screen somewhere, then you can snap it to the nearest grid position by using the same formula. Because floor(77/32) - 1 is also 1. If an electrical component has a width or height that is not quite divisible by 32, you can still get its cell position using the same formula.
Hope it helps.
-
This explains a*
http://archive.gamedev.net/archive/reference/programming/features/astar/index.html
beyond that, i'm out of ideas. Good luck!