SIEGE OF OSAKA | Tech Stuff
Tech Breakdown
Disclaimer: I'm not a programmer at all. Somehow this stuff works, but there are probably better ways of doing it.
-----
VFX
So for a long time, I had VFX handled by spawning, animating, and destroying VFX objects - and the StageHandler would draw all VFX via with(). This was an easy target for some optimisation, especially after reading some YYG forums threads on performance experiments in GameMaker - in particular, a post where someone mentioned that doing stuff with a bunch of 1-dimensional arrays every frame turned out to be cheaper than many other solutions.
So I scrapped the VFX object stuff entirely, and gave the StageHandler a series of arrays to handle:
- VFX Sprite
- VFX Frame Max
- VFX Frame Current
- VFX X Position
- VFX Y Position
This also gave me an easy hard upper limit on the number of VFX drawn on screen at any time. Excuse the ugly manual setup of the arrays, with some arrays later on in the project I did use loops in the Create Events to set them up without having to write extra lines. The custom function I'm using to spawn VFX from any Arch_Actor (Projectile, Collider, Samurai, Ninja, etc...) checks for an empty (VFX Sprite being nothing) slot in the array, and, if it can, adds the argument VFX sprite into the array at that point while setting the Frame Max and resetting the Frame Current. You can see that I was previously using a for loop for this, but changed to just use repeat() for some minor optimisation.
And in the StageHandler Step Event, it iterates through all VFX slots and processes them as needed. After each slot is animated if the VFX Sprite for that slot isn't noone, it checks to see if the VFX animation is finished - if so, that slot is cleared.
Then in the StageHandler's Draw Event (on top of BG Tiles, Actors at depths, etc...), arrayed VFX is drawn - again, this was using a for loop and is now using repeat().
-----
Animation & Drawing Behaviour
Early on, I gave all my Arch_Actors script variables for housing the functions they would use to handle:
- Step Event stuff
- Drawing
- Animation
- other stuff, like collision - this wasn't ever a problem since these weren't getting called all the time
Thanks to the Profiler, I discovered script_execute() was absolutely murdering my performance in large quantities. So I got rid of these attachscript_* variables.
And instead, with Drawing as an example, I gave all children of Arch_Actor a simple integer value that I used in a switch statement in a "master" Actor Drawing function - effectively, I still get all the benefits but without calling script_execute() a bunch every frame.
Another easy target for optimisation was getting rid of dot operators that I didn't need. I already had a custom camera shake system built in to the StageHandler, since I prefer applying a yoffset to everything instead of actual camera movements, don't @ me.
And instead of Actors using drawing functions that accessed the StageHandler's yoffset_camshake_current variable via dot operator, the StageHandler just sets all Actors' camera shake value as its own roughly every few frames (the purpose of the b_stage_toggle_fouronthefloor flag - not just a funny name, it also handles flickering things so they can be seen on at least most displays - things that flicker each frame can become invisible on some displays and especially in recorded footage). So, as seen in this particular function, the Actor using this function will not have to access the StageHandler's properties.
-----
Depth Sorting
Fake depth in top-down-with-perspective in retro 2D games will be discussed 'til the end of time. Here's my solution - evolved and optimised from when I did a Tech Breakdown for CHESS IS STUPID. In this iteration, all children of Arch_Actor start with a DepthSort variable (default doesn't matter since it gets set by the StageHandler on Room Start, and at many other times) and the StageHandler has a bunch of useful values. Actors also have a bias offset, in case I need to fudge things for artistic reasons.
For the StageHandler, I knew I was going to constrain all Actors within a certain area in gameplay, so I knew I could start the counting process at 32 pixels below 0. The int_depthsort_denom variable is just accuracy - higher value means more visually-accurate but performance takes a hit. I opted for what seemed to work out as the best balance between the two (especially since actual NES/Famicom games sometimes didn't do the best job of this).
The StageHandler will draw Actors at the right fake-depth by using the drawing master function above - unlike my previous version, this doesn't have any real calculations happening in the Draw Event. Again, you can see evidence of a for loop getting replaced by repeat().
Then I use a function on Actors to set their fake-depth value to the correct amount - this is called whenever the Actor will be moving on the Y axis, or at the start of a stage. This way, static Actors like fortifications will not have to check or change their depth at all, whereas the Ninja Actors that become bouncy balls will call this function roughly every other frame.
Leave a comment
Log in with itch.io to leave a comment.