Optimized code - Whats the best way to write this?
by Steven Peterson · in Torque Game Engine · 03/06/2006 (6:01 pm) · 7 replies
I'm writing a dynamic weather engine and can't decide on how to make a series of function calls. I'm primarily caught between a "more readable code" and a "more optimized way" way, unless someone can suggest a better compromse. Since this function is called "once every game-hour" which could be defined to be as little as a few seconds, I want to keep the execution-line streamlined. Since this thing is so BIG though organized-readable code is also important.
When the main weatherUpdate() function iscalled it does a switch by season (or DEFAULT case) and then an if, else if to select one of four weather-pressure groups, and then it tests for a special case and then calls a separate "case-function" to make the weather changes specific to that individual case. In all there's 40 such "case-functions" which is why their not inline. Up to this point we've executed 3 or 4 (C++) instructions and made 1 additonal function call.
Now each "case function" has to turn on / off the various weather elements and FX to create the desired weather condition. There's 16 elements on the design board. As a teaser here they are:
- Swirling Wind
- Fog1
- Fog2
- Fog3
- Fractal Clouds
- BMP Clouds
- Rain
- Wet Snow
- Dry Snow
- Precip. Dust
- Volumetric Dust
- Particle Dust
- Lighting
- Thunder
- Particle leaves
- Rainbow
Now i'm going to write thirty-some functions to the effect of:
void swirlingWindOn();
void swrilingWindOff();
void Fog1On();
void Fog1Off();
...
...
etc.
Here's where I'm unsure:
Possibility 1
Each "case-function" can now go right down the list and call the appropriet on/off function for each weather element to create the intended ambiance. This leaves all (40) of the case functions at a consistant 16 lines/function calls.
It would now be the responsibility of each elementOn() / elementOff() function to test if the element is already on/off, make any changes, adjustments, housekeeping, error-handling etc. on it's own, as needed.
This seems to be the cleanest most modular way to write it; but i'm concerned about the large number of function calls every time this thing cycles.
Possibility 2
The alternative is to shift some responsibility out of the elementOn() elementOff() functions and up to the "case-function". say I want rain to be "on". Test if it is already "on" and then only call rainOn() when I need to.
The downside is: that's an additonal 16(elements) * 40(case-functions) = 640 IF statements I have to write. Also I'm not even sure if makeing 6 function-calls(for example) instead of 16, will that make it noticeably easier on the processor?
Other Optimization
The one case I'm deffinitly going to check for in each "case-function" is if this is the exact same weather "case-fucntion" as was choosen last time - in which event I can assume the weather is already correct, and only the most minor tweaks need to be made. Since both "season" and "pressure" changes happen slowly, this is the majority of the cases.
Can anyone off up some wisdom-through-experience on this?
thanks for any advice!
Raven
When the main weatherUpdate() function iscalled it does a switch by season (or DEFAULT case) and then an if, else if to select one of four weather-pressure groups, and then it tests for a special case and then calls a separate "case-function" to make the weather changes specific to that individual case. In all there's 40 such "case-functions" which is why their not inline. Up to this point we've executed 3 or 4 (C++) instructions and made 1 additonal function call.
Now each "case function" has to turn on / off the various weather elements and FX to create the desired weather condition. There's 16 elements on the design board. As a teaser here they are:
- Swirling Wind
- Fog1
- Fog2
- Fog3
- Fractal Clouds
- BMP Clouds
- Rain
- Wet Snow
- Dry Snow
- Precip. Dust
- Volumetric Dust
- Particle Dust
- Lighting
- Thunder
- Particle leaves
- Rainbow
Now i'm going to write thirty-some functions to the effect of:
void swirlingWindOn();
void swrilingWindOff();
void Fog1On();
void Fog1Off();
...
...
etc.
Here's where I'm unsure:
Possibility 1
Each "case-function" can now go right down the list and call the appropriet on/off function for each weather element to create the intended ambiance. This leaves all (40) of the case functions at a consistant 16 lines/function calls.
It would now be the responsibility of each elementOn() / elementOff() function to test if the element is already on/off, make any changes, adjustments, housekeeping, error-handling etc. on it's own, as needed.
This seems to be the cleanest most modular way to write it; but i'm concerned about the large number of function calls every time this thing cycles.
Possibility 2
The alternative is to shift some responsibility out of the elementOn() elementOff() functions and up to the "case-function". say I want rain to be "on". Test if it is already "on" and then only call rainOn() when I need to.
The downside is: that's an additonal 16(elements) * 40(case-functions) = 640 IF statements I have to write. Also I'm not even sure if makeing 6 function-calls(for example) instead of 16, will that make it noticeably easier on the processor?
Other Optimization
The one case I'm deffinitly going to check for in each "case-function" is if this is the exact same weather "case-fucntion" as was choosen last time - in which event I can assume the weather is already correct, and only the most minor tweaks need to be made. Since both "season" and "pressure" changes happen slowly, this is the majority of the cases.
Can anyone off up some wisdom-through-experience on this?
thanks for any advice!
Raven
#2
Thanks buddy, I was going to post back alst night but opted to sleep on this one. I really like the toggle idea, which I would have never thought of!
The "thinking" really isn't all that complex. my inputs are "season"(approx time of year), "time"( approx time of day ie. sunset, sunrise, day, night) and "weatherPressure" which is slowly adjusted each iteration using a random-number generator. After that it's all "switch" or "if, else if" with an occasional random dice-roll to keep things intresting.
The AI book behind me would probably tell me how to use a Finite State Machine to do it, but so far i'm keeping it simple.
Thanks for the help!
ps. If anyone else has further nput, I'm going to be hacking at this class all week, so advise is always appreciated :-)
03/07/2006 (8:06 am)
Josh,Thanks buddy, I was going to post back alst night but opted to sleep on this one. I really like the toggle idea, which I would have never thought of!
The "thinking" really isn't all that complex. my inputs are "season"(approx time of year), "time"( approx time of day ie. sunset, sunrise, day, night) and "weatherPressure" which is slowly adjusted each iteration using a random-number generator. After that it's all "switch" or "if, else if" with an occasional random dice-roll to keep things intresting.
The AI book behind me would probably tell me how to use a Finite State Machine to do it, but so far i'm keeping it simple.
Thanks for the help!
ps. If anyone else has further nput, I'm going to be hacking at this class all week, so advise is always appreciated :-)
#3
The tradeoff would be in how quickly you can update the tables on each iteration but it doesn't sound like anything is updating quickly.
Just my two cents, as I don't yet have a very clear picture of it all.
03/07/2006 (8:36 am)
This seems like something that could really benfit from a table driven architecture, if you can organize the data and conditions appropriately. Tables are easier to document and maintain for one thing and the code has a good chance to be very fast if it can be expressed as combinations of boolean conditions rather than a lot of branches.The tradeoff would be in how quickly you can update the tables on each iteration but it doesn't sound like anything is updating quickly.
Just my two cents, as I don't yet have a very clear picture of it all.
#4
I'm not sure how I would implement it that way though. What exactly do you mean by "Table driven architecture" from a code standpoint?
03/07/2006 (8:49 am)
Intresting that you should say that, for myself I mapped it all out using Truth-Tables in excel, which will probably become part of the docs..I'm not sure how I would implement it that way though. What exactly do you mean by "Table driven architecture" from a code standpoint?
#5
There's no set rule for doing it though other than that the logic be uniform wiht few special cases.
03/07/2006 (9:17 am)
Try to arrange your excel sheets in a way that conveys the logic of the decisions, that is, without any need to know the meaning of any of the variables. If, while playing with that, a structure emerges with most or all of the decisions having the same sequence of comparisons on different data, then your halfway there. This implies that you could implement a common routine that uses pointer indirection to process all of that data by arranging the data in the table(s) appropriately. For example, you might have a case where the sense of the test would be reversed; fix that by exchanging the variables in the table rather using a different method. And so on.There's no set rule for doing it though other than that the logic be uniform wiht few special cases.
#6
The good news is, my program's design as a whole is strong enough that I could throw out this one class and compleletly reimplement it at a later date - and no one would be the wiser. Well hopefully I'd be wiser for the experience but...
Thanks for the hlep guys!
03/08/2006 (9:17 am)
Ok, as follow up, i'm basically using a collection of all of these ideas to get it working for now. I'm reading up on finite-state-machines, which i'd really forgotten about but are coming back to me now. We used them in class to solve all sorts of conceptual problems, but never even mentioned implementing them in code...The good news is, my program's design as a whole is strong enough that I could throw out this one class and compleletly reimplement it at a later date - and no one would be the wiser. Well hopefully I'd be wiser for the experience but...
Thanks for the hlep guys!
#7
First I would not have the huge switch/ifelse statements (although, those aren't inherintly slow btw). Instead I would define a class or structure to represent weather conditions:
Then in you class that handles this weather stuff, you would create instances of the class with all the info defining each season.
So now in you method that changes seasons, we have a really simply state change:
You'd obviously need to write that applyWeatherChanges function, but I assume most of the work that would be in there is already done. The curWeather should contain all the information needed to create this weather in game... if it doesn't you add what you need to the structure.
You could also take this a little further and implement state machines (or similar) so that the weather transitions don't have to go in order, and stuff like that. I would also add a default constructor to the CWeather class, so that you can easily add new data to the class without screwing everything up.
Keep in mind too, I wrote all this in NotePad, so I'm sure there are some silly mistakes in there!
Matt
Edit: Found a few mistakes.
03/08/2006 (10:13 am)
It sounds like you already have a solution by I just kind of like the problem so I'm gonna take a stab at a solution anyway :)First I would not have the huge switch/ifelse statements (although, those aren't inherintly slow btw). Instead I would define a class or structure to represent weather conditions:
class CWeather {
// I'm just guessing at the types here
int ID;
bool SwirlingWind;
float Fog1;
float Fog2;
float Fog3;
bool FractalClouds;
char BMPClouds[128];
bool Rain;
// etc
};Then in you class that handles this weather stuff, you would create instances of the class with all the info defining each season.
// In the header
class CSomeWeatherHandlerClass {
// All you other stuff would be in here too
private:
// An array of all our weather systems
CWeather allSystems[NUM_WEATHERSYSTEMS];
// The current weather system
CWeather curWeather;
};
// In the .cc
CSomeWeatherHandlerClass::CSomeWeatherHandlerClass()
{
// Do everything as usual...
// Now create all our weather systems
// Summer
allSystems[0].ID = 0;
allSystems[0].SwirlingWind = true;
allSystems[0].Fog1 = rand() % 20;
allSystems[0].Fog2 = 0;
allSystems[0].Fog3 = 10;
allSystems[0].FractalClouds = true;
strcpy(allSystems[0].BMPClouds, "MyGame\Data\SomeWickedClouds.bmp");
allSystems[0].Rain = false;
// Fall
allSystems[1].ID = 1;
allSystems[1].SwirlingWind = true;
allSystems[1].Fog1 = rand() % 20 + 40;
// ...
// Do the same for all systems
// Now store our initial weather system
curWeather = allSystems[0];
}So now in you method that changes seasons, we have a really simply state change:
// In your update (or whatever function) // What is the next system? int NextId = curWeather.ID + 1; // Make sure we haven't gone too far if(NextId >= NUM_WEATHERSYSTEMS) NextId = 0; // Now simply assign the new system! curWeather = allSystems[NextId]; // Now we need those changes to actually take effect applyWeatherChanges(curWeather);
You'd obviously need to write that applyWeatherChanges function, but I assume most of the work that would be in there is already done. The curWeather should contain all the information needed to create this weather in game... if it doesn't you add what you need to the structure.
You could also take this a little further and implement state machines (or similar) so that the weather transitions don't have to go in order, and stuff like that. I would also add a default constructor to the CWeather class, so that you can easily add new data to the class without screwing everything up.
Keep in mind too, I wrote all this in NotePad, so I'm sure there are some silly mistakes in there!
Matt
Edit: Found a few mistakes.
Torque Owner Josh Moore
I'm not sure how you're actualy handling the weather "thinking", but wouldn't it be best to use a FSM?