How did you tackle it?
This is a bit of a dead thread, but, hey, you did ask and sharing is caring!
The most complex system I have built was for a simple 2D/UI turn-based strategy game I was making. Noting that this was just me, and my mighty coding chops of having done a couple of courses off gamedev.
I was building an upgrade system. The player:
-can click on a thing to open a menu.
-then click on a slot to choose from a selection of upgrades, which each have a cost (in two currencies)
-the upgrade then influence the players income on various currencies
-and they can be removed, too
-changing the player’s income affects various UI bits and displays
-and each upgrade had pictures and flavour text and such
I had a pretty clear idea in my head of what I wanted to do, and what the dependencies were. I outlined it pretty carefully. What made it so difficult was:
a) I kinda didn’t know how best to solve the problem. I used the event system, which was cool, but caused problems (I didn’t know that all listeners react at at the same time).
b) in an early attempt, I used .enabled = false to turn off UI elements and game objects that were off of the player’s view at any time. This was a bad mistake, because it screwed up various dependencies.
c) speaking of which, I didn’t map my dependencies well
so yeah, it was a great leaning experience, but it didn’t really work as a game. I also made some poor judgements in game design, too.
I will probably return to it again soon.
I guess it would have to be my Unreal Engine blueprint system “Classic Single Player FPS Game Framework” at Classic Single Player FPS Game Framework in Blueprints - UE Marketplace which took me more than a year.
- Now, the most complex system I worked on, on a team of over 100:
…was quite a bit bigger, ran on more processors (this was pre-cloud. We had two computers, a huge supercomputer and a Sun Enterprise Server E10K (this one was smaller, only one ton!) as the front end. (The supercomputer cabinet had a Windows NT box attached, but that was for running the cooling system and such, not actual computation).
My part involved microcoding (very painful) but also some C and perl and bash scripts (and attending a ton of meetings, being kicked by my boss for dozing off). Normally an engineer would do that but this was a mathematical algorithm so mathematicians did a lot of microcoding for the system.
Not ever having done microcoding before, I first made sure I understood the mathematical algorithm. Then I wrote it in C and tested it thoroughly.
Then I refactored the C so it had the same dataflow that could be done in microcode, same register values at each tick and all. This part was important.
Then I finally wrote and optimized the microcode (which only implemented part of my C algorithm, as other mathematicians wrote other parts in microcode). I could verify it by stopping a Verilog simulator at various points and ensuring the register values had exactly the numbers the C program predicted it would. (That was important: getting the right answer wasn’t enough. It was one of these situations where subtle errors would still give the right answer but it would take 100x as long or worse…think of implementing A* wrong; might find a path but do it the hard way)
I was happy when we finally deployed to real hardware, it worked perfectly.
- Another mathematician wasn’t so lucky.:
… He was young, and his programming style was “I proved it worked, so no testing needed”.
Famous last words because when we put the system together, something made it give wrong answers.
So, I had the C program and I used it to figure out where it was wrong. I finally found it:
“Hey, when it gets to this step in your subroutine, this register is supposed to have X but with your code it has Y instead!” (So, the C program methodology paid off!)
He studied the code and found the problem. His “proof of correctness” assumed a certain 32 bit register was a 64 bit register. After all, that’s what the documentation said. But he had missed the meeting where it was decided that because we were reaching power/area/capacitance limits on the silicon, we had to make some compromises, and it was decided the “counter register” should never need more than 32 bits. We didn’t know he’d use the counter register as temporary storage for an actual data number…
But he was upset. How dare the documentation lie to him!!! To me the lesson was, test your code, but he just didn’t work that way! He eventually left the company. A bad fit, he thought we were idiots, we thought he was stubborn and refused to follow best practices.
- And a story on how heavy the Sun E10K was
We were bringing it in, using a ramp the engineers built themselves to roll it up a step-up to get it to the correct position.
As they were rolling it (too expensive, 6 million dollars, to trust to hired hands, engineers did the lugging!) the wheels on one side went off the ramp. I panicked because I was envisioning a 6-million dollar machine crashing into the concrete and I had invested too much work in programming that thing already. So, I got on the side under where it was tilting and pushed as they manhandled it back onto the ramp. Save!
But then I started thinking…weighs a ton…I got under it…it was in real danger of falling…
Now, the moral is, think before doing something like that!
Fortunately, these days when we need something as powerful as a Sun E10k, all we need to do is pull it out of our shirt pocket.
I still remember fondly, the IBM System/36 we had at my High School. The terminals (I think it was 6 or 8 terminals) shared 128k of Ram, which we thought was probably overkill. You definitely had to code differently in those days. Clock cycles mattered, and and writing to the wrong ram address didn’t give you a blue screen of death, it could ruin all of your fellow student’s days as well.
After watch Ryan Hipple’s Game Architecture with Scriptable Objects from Unite Austin 2017
I thought this was a cool thing to have in every project. Which reminds me I need to go back and update the Git Hub Page with the new version that I use. I did a major rehual of the system. The biggest use is the Reference Variables because it fires both Game Events and C# Events when a value changed which helped with greatly reducing the dependencies of objects. I.e. my UI did not need to know anything about the player or the health it just listened for an event and updated its values when things changed. The custom attributes come in handy with creating custom Inspectors without having to write a custom editor window for all of my classes.
The hardest part about doing the custom attributes was making mine work in conjunction with Unity’s built in ones, I almost just resigned to not having them work together.
I came across Bit Cake Studio’s BitStrap
I implemented their solution Property Drawer Helper, Option.cs, and copied all of Unity’s built in properties from
and
I added my Property Drawer Helper to all of Unity’s Properties.