So... Working on a SRPG battle system - and I keep finding more things I need temporary variables for, and it just feels like I've made some kind of monster, I've got something like:
20 variables holding specific values
3 menu objects
a map object (containing 2 different obstruction arrays)
an array of people objects (for drawing)
an array of characters (with stats etc)
an index array into both of the above arrays
an object holding the output of a path finding function
And the whole thing just looks like this: https://youtu.be/Bp4tGTNNi1I?t=1m10s
Is there a method anyone can suggest to avoid this?
Start refactoring. Figure out if you can break individual parts into cleaner functions, see if you can make a better way to handle the functions, see if you can use a library like Link.js to handle locating array values and such.
Avoiding complexity is hard when you're just diving in, but code is easy to change, so just go back and tinker with it every now and then to see if you can make it more elegant.
I guess subdividing is probably the way forward, whilst I push the animating and drawing of characters and menus and the pathfinding into separate functions almost everything else is in one massive 640 row function and it's probably only about half written... That said, my function to animate & draw people is 350 rows and will grow further but that isn't so bad as it basically works by looping down and an array of objects and everything it's doing relates to properties of those objects so there aren't many other variables hanging around.
Whereas the battle system as it's working with so many different things is just..... Well maybe you watched the video...
It might help in your animation function to break it down into individual functions where you only have to pass in the properties of the object, that way it's not so big and ugly and is instead a lot of individual steps.
I modularize everything as much as I can. A separate file for healthbars, stats, attacks, etc.
At the end of the day, battle systems are going to be huge, there's not a lot you can do to minimize that. However, with the right mix of modules, many complicated bits can be made less confusing. At the end of the day, it's all about the cyclomatic complexity (https://en.wikipedia.org/wiki/Cyclomatic_complexity). Generally, the "flatter" your code, the better (usage of less nested scopes).
I'll put some of my cents in. I'm not sure if this will be helpful.
The first organization of code that I do is state vs representation. The state says what is currently in the game/battle system, while the representation shows the graphics and sound. The representation parts never modify the state, and are idempotent (running it twice gives the same output both times), and the output is determined by the state. The last required part is the code that updates the state. It only modifies the state based on the current state and user input. In programming speak, this is the model-view-controller idea.
Second, when making a battle system, you have to determine if you need a scripting engine or not. In some cases you do, but most cases not so much. In an engine it's possible to have multiple actions happen at once (for example, multiple people moving at the same time in the default map engine), but there's added complexity with the control flow. An active battle system like FF6, should be in an engine since a monster can attack while the player is in a menu, while a turn based system like Dragon Quest can be done without one. Without an engine, the battle loop goes through the players and enemies running the DoTurn(character) functions until victory or defeat, and the control flow is much easier to follow. In an engine, the engine is constantly running and you're queuing events to happen n units of time later, which breaks the control flow, but is needed. In short engines are asynchronous, so only create one if you need it.
Third, don't be afraid of globals. You're making a game by yourself, it's not a web application. I could give a long speech about what is a global, what is not a global, and what types of globals there are, but in short for this, the rules change according to what the program has to do and how many people are working on it.
Fourth, get a non-moving spec in place for what the battle system has to do before anything else. Once you're fine with what you have to make, start with the most abstract layers and lay them out, and work your way down through the abstraction until you're done.
Thanks for the comments everyone, further to the above I have now got the basic functions of the battle system working, though there are several things that need more work.
I do have an issue I think with having mixed up some elements of my update/state code and render/representation code and it would probably be a worthwhile exercise to go through separating this at some point - it started with the fact that before making a battle system I made a character animation engine - call the function and it checks if anyone on screen ought to be moving, or animated in any way, makes them move if necessary, checks what frame should be showing for each person and then draws them all.
I've then used this engine (including its built in animation queue for each character) as a key aspect of my combat system - but it is both updating locations and drawing which may have a been a mistake; I then had situations such as:
- I need the characters locations updated before doing X
- but I need to draw Y before I draw the characters...
Additionally my menu code has one function to both update the menu and draw it; perhaps I should split this menu function and the character engine function each into two functions then perhaps I could make a more logical flow; I'm not sure if it will help or not though.
Actual functionality that's still needed:
1. accuracy and evasion stats need to do something...
2. techniques need to exist (at the moment it's "Attack" only)
3. the system needs to check if you've won or lost - I've not made any kind of victory/defeat handler - the only exit method is hitting escape
4. The AI needs to be a lot better...
This is an old topic, but I felt it was worthwhile to mention that there's a very good reason you're not supposed to update things in a render handler: the engine can skip it. Frameskip determination is done during flip processing, and if the engine determines the next frame needs to be skipped to make up for lost time, it won't run any rendering code that frame. Including your render script.
If you're doing updates based on time between frames then the skipping won't be a problem, but you then get other issues like jerky animations, drift due to floating point error, etc. plus the map engine itself is synced to the FPS and you can't avoid that.
Long story short, the engine for the most part guarantees you will get as many update calls per second as your FPS, so updates are 100% predictable. Renders are not.