It’s time to get you guys updated on what has been going with the A-Engine!
Today’s update will be more technical than usual, but it’s a very important one. Sorry about that.
In the past, I’ve admitted that the A-Engine could get really slow when so many objects are on the screen, and I believe I have mentioned that it was mainly because of one particular function, Evaluate(std::string expression). What this function does is take an expression of type string (text type, stuff like “5+3/2-1”), evaluates it, and returns the result as a type float. Now the reason this function is so important is that I use it to get the value of every tag of each frame every object on the screen is at. Consider the following typical frame:
[f=0] # an example attack frame
img= 1 center= 39, 79 delay= 3
set_hitbox[x= 40 y= 44 w= 31 h= 15 damage= 30 strength= 30 x_impact= 10]
set_hurtbox[x= 19 y= 20 w= 30 h= 79-20 ]
There are about 15 values fed to tags in the frame. This means Evaluate(std::string) will be called 15 times in that frame alone. Disregarding the tags used in the health bars’ frames, in the stage’s tags, the hit sparks ..etc, suppose we have 50 characters with that typical frame on the stage at once. 50 x 15, 750 times is the number of times Evaluate(std::string) will have to be called. Such a function’s performance must of course heavily affect the general performance of the game.
Now the reasons as to why the function was too slow is obvious; It’s converting the string we pass to a float on the fly. The conversion from string to float is very slow that if you compare the time difference between using a float directly and using a string but converting it to float when you call it, you will find that its 100s (with string streams) times slower. The other reason is that string manipulation processes, which are necessary to evaluate expressions like “3.4+2*5/4”, are extremely slow, and it’s well-known that they must be avoided during run time.
So what I did is that I wrote a new type, AExpression<T>. The idea was to create a data type which when initialized by passing the expression string, will parse it and arrange it to a performance friendly list of numbers (floats in my case) and operators. When you later use its evaluate() method, it will simply apply the operations on the floats and return the result, eliminating all the string operations in the process. Note that the constructor should try to simplify and evaluate the expression as much as possible beforehand, but I didn’t implement this yet.
Now here are the results of a test to compare between the time Evaluate(std::string) and AExpressions takes evaluating an expression a 1,000,000 (million) times.
It took 1 minute.
Using AExpression to initialize once and evaluate later:
Just 0.28 seconds.
AExpressions does it about 60/0.28= 214.29 times faster than Evaluate(std::string)! I need some cake.
So that’s it for today’s update. Next up on my radar is to implement the AScope class which will be necessary for AExpressions to have registers, functions and variables to work. After that comes replacing all the Evaluate(std::string) calls in the A-Engine’s source with the new AExpression functionality, and changing the types of all the std::string variables which store the values of the tags to AExpression and letting it initialize everything during loading times. Right after that will be changing the coordinate system of the A-Engine as appropriate, and getting perspective projection mode as an option to render things using a perspective matrix (3D-ish) instead of Ortho.
If you have any questions or suggestions, I will be replying to them in the comments.
See you in the next update, and have a nice weekend!
Contact at: email@example.com