Argh wrote:Lastly... I am glad that zwzsg is here to argue for his case!
Thanks, I'll continue then. I was getting worried that my insistence might start to sound like I'm flaming, but I really would like to understand what's that "radical improvement" you're talking about in your first post.
Egarwaen wrote:However, single parameterized functions are generally preferred to multiple copy-and-pasted functions.
Agreed. However, parametrised function, while easier to read and maintain, might be slower to run ingame than raw copy'n'pasted function.
Argh wrote:Your method requires a math step (calculating LEG_1_DOWN_ANGLE), and a memory search step(finding all of the values you're storing via Defines), during every operation. This is because you're not feeding it a value right there in the COB step. I'll grant, for the sake of argument, that the math step (the multiplication) is trivial, because it can be done so quickly, even after being interpreted by the COB interpreter and finally run through the virtual machine. However, the memory search, to find the variable name and then get its value... is not trivial, and should be avoided where possible. In general, you want to refer to static variables as infrequently as possible, and pass them from sub-script to another sub-script when it's absolutely necessary...
Just to make sure it's clear, the "#define" are not static-var. They're like copy'n'paste, done by the preprocessor, before even the compilation is done. So something like:
#define ANGLE <20>
turn pieceN to x-axis ANGLE now;
is exactly equivalent to:
turn pieceN to x-axis <20> now;
What I mean by exactly equivalent, is that they output the very same COB, not any byte of difference in the COB.
As proved by : If you take the first, compile it, then un-compile it, you get the second.
Ok you probably knew what are preprocessing commands, but just making sure, because you're talking about a "
memory search, to find the variable name and then get its value, while there is none of this with "#define".
But I agree that caculating the "speed" of my "turn" from complex calculation using that many "#define" propably result in poorly efficient code. For instance, in my Scorpion walkscript, when I write:
BACK_4_LEFT
it's replaced by:
turn leg141 to y-axis 0 - (LEG_41_BACK_ANGLE) speed ((LEG_41_FRONT_ANGLE) - (LEG_41_BACK_ANGLE))*1000/(BACK_TIME);
where all the values in capital letter are replaced by their value
so it really is:
turn leg141 to y-axis 0 - (-7280) speed ( 910 - (-7280) ) * 1000 / 179 * 12;
(You can see that by compiling then uncompiling the bos)
I don't know how much cost doing multiplication and division compared to performing commands like "turn", but all those multiplication and division could be avoided with the animation looking exactly the same. Note that if Scriptor was a good compilator, it would realise everything is constant in these formula, and so would optimise the code by writing the end result in the COB, instead of letting the COB virtual machine do all that calculation everytime the line is run.
Ok, so using that many value calculated from "#define" may be bad performance wise. I did it only because it made writing the code, and mostly tuning it, easier: I change one value at the top, and everything adapt. Maybe, once I have found the timing and angles that result in a good looking animation, I could go and replace every calculation involving only constants with its result, but generally that's too much work for little performance gain, and I don't do it.
But anyway, I'm the only one abusing "#define" 'ed constant like that, and I can do without if I need to, so I don't think this where your optimisation idea lies.
I'd like to avoid the StartMoving() and StopMoving() entirely, but I'm pretty sure that Spring doesn't allow us to get the state of Moving otherwise. If I'm wrong, somebody please enlighten me, because I'd like to clean up all the MotionControl mess with a simple logical state-check, like so [...] ... which would get rid of all of the stupid MotionControls all at once. If anybody knows a way to do that... that won't lock up... I'm completely ready to drop all of those logic checks, and lose a lot of redundant code.
Note sure I understand you, but get a look at my script,
the 2 leg walk script I posted page 3 or
the AmazonZ.bos in this ufo, to be precise. There I use no variable keeping the state of moving, as I simply put the whole walkscript inside the StartMoving(), and stop the walking animation by killing the StartMoving() with a "signal" in the StopMoving() function. Note that this method would have a little bug if you control the unit in first person, as in FPS the Spring engine constantly call the StartMoving function (or so I heard).
Another way I use often (like in the Scorpion), is:
Code: Select all
static-var moving;
WalkScriptFunction()
{
while(1)
{
if(moving)
{
turn ...
....
wait-for... or sleep...
....
...
}
if(!notmoving)
{
....
just don't forget any pause in here
...
}
}
}
StartMoving()
{
moving=TRUE;
}
StopMoving()
{
moving=TRUE;
}
Create()
{
moving=FALSE;
....
start-script WalkScriptFunction();
}
Actually in the scorpion, after every "pose" followed by a "pause", I do a while(NOT moving){sleep 200;}, which allow my Scorpion to suddenly freeze its walking, at every stage of the walk animation, when it stops moving, and later resume the walk animation where it left it.
If you really want to remove StartMoving and StopMoving althogether, well, you could periodically store get PIECE_XZ(base) and check if it changed, but I am sure that it would be a lot more inefficient. I don't see why you want to avoid StartMoving() and StopMoving() entirely, they're only called once when the unit start moving, and once when the unit stop moving (duh!), (save in FPS mode but that's a very special case), I mean, they're not like ever looping function eating CPU at every frame.
Anyway, all I wanted to say, is that I hate the MotionControl mess, and had no trouble never using it. (Ok, one might say that my WalkScriptFunction() is just a merger of MotionControl() and Go(), and that wouldn't be false, but I still find it simpler that way).
Well, I aren't sure this what you asked when you wanted to remove the use of the moving static-var and the MotionControl.
Hmm, on any give frame, my code run even lines fewer than yours.
Again, you're wrong. Your code, as written, has to be parsed in whole, and it's going outside of the Function on a regular basis. So far as I can tell, only things between brackets in a Function are currently running and in memory. This was how Cavedog did things, to reduce the size and memory footprint. That is one of the reasons why they did the IF(TRUE){blahblahblah} stuff in their WalkLegs scripts, etc.... to keep the chunks down to one-frame actions, run it through the parser, and move on. I think that commands between brackets are all being loaded at once into memory, and the it's operating according to the schedule set within that script.
Ok. We need to ask Fnordia how the COB virtual machine really works. I assumed that, just like a processor running machine code, it had a program counter register storing the adress of the line being run, and that it read from the cob and stored in memory one line at a time. Again, we need to ask Fnordia how the COB language is actually implemented in Spring, but it just seem the most logical way. Reading from the COB file and putting in memory everything into { } at once just seem inefficient and useless, and I don't see why the virtual machine would do that, but I'm very glad to hear an interesting theory about why Cavedogs used so many if(TRUE){...}. For very long I wondered why! Xon (formerly ggs) had another theory (he said that in old version of TA, the COB virtual machine could force a pause in script if it had run for too long, but only on "if" statement (or only on { or }, don't remember exactly)). But so far you are the only two people proposing plausible theories! Well, interesting theory as it is, I'll still have doubt on the COB virtual machine reading everything into { } at once until confirmed by Fnordia (or another SY), as I don't see the point in working that way.
I don't see why are you talking about parser, COB being compiled code, it doesn't require parsing, does it?
So, in a sense, you're both right and wrong. Your code's calling very few lines in the main script, then pausing, then continuing. It's feeding operations to the animation side of Spring in short, easily-digested chunks. However, on the BOS interpreter side, it's calling outside the script over and over again during each operational step, instead of staying within itself- this is inefficient.
My script stay as much within itself as it could possibly do! How can you say less inside yourself than by having a single loop in a single function, never returning? You'll to explain that point in more detail to me.
I'm pretty sure Spring do care how many scripts are running simultaneously within a given COB.
We'll look at a proof for that, doing a simple apples vs. apples comparision where we need to accomplish the same task with one script vs., say... 100. I strongly suspect that the single-script solution will run less efficiently. [...] But, based on past experiments, I think that may be the case.
Ahead of you: Already run a comparaison, between 1000 kbots scripted your way, and 1000 kbots scripted my way, everything else equal,
see my post near the bottom of page 3, and don't forget to check
the ufo containing the two test units. Yes, the one thread walkscript used less ressource than the two threads one.
Why? Because I think that there's an upward limit on how far the COB interpreter looks ahead, in terms of commands.
What? "looking ahead, in terms of commands"? What is that nonsense? The COB interpreter execute one line after the other, it doesn't go looking ahead. At least that's what I always believed and assumed. You'll need some very strong argument, or Fnordia's word, to convince me otherwise. Not even the smoothing looks ahead, it just store in the memory that a "now" movement is being smoothed, an immediatly finish it on certain condition.
Unlike what you said, your MotionControl isn't executed every tenth of a second or so, as most of time it's busy waiting for the "go" function to return, but if it were, then it would be really burdensome.
You're joking, right? No, you're probably not. I'll do a proof of
that statement as soon as I get home, as I don't need to put any time into it... just build 499 Archers and have them just... stand there, supposedly killing the processor with their repeating script. I think you're going to be disappointed- that theory doesn't hold any water. A Sleep/NoSleep of a tenth of a second, absent anything else going on... is totally harmless, even multiplied by large numbers. I'm more worried about the fact that it requires so darn many logical state checks to make sure it's really going to sleep.
Ok, I'll assume that you agree about the "
MotionControl isn't executed every tenth of a second or so, as most of time it's busy waiting for the "go" function to return", and only disagree about the other part. Well, guess what, I already ran the experiment (of comparing 1000 kbot standing still, first scripted your way, then scripted your way), and with my script, it was at 0%, with yours, at 13%. If you had bothered reading the
previous page, I wouldn't have had to repeat that.
The main reason I am extremely excited about this whole thing... is that, by utilizing TURN/MOVE and WAIT-FOR-TURN and WAIT-FOR-MOVE... we can get away from static, frame-based animation techniques... and move towards much more dynamic approaches. I'm serious about things like de-tuned animation sequences, and using random number generators in scripts- they'd add a lot more lifelike oomph to existing animation models.
That I agree with.... and I am already using since ... years ago. Basically since my very first TA unit.
Maybe after all the miscomprehension between you and me comes from that, you're comparing your script to Cavedog script, which are very ugly and unoptimised, with lots of messy incomprenhensible code with static and local var to store thing like 'just_moved' and 'somebody_was_playing_with_my_cannon', and which use pages and pages of
turn/move ... now; instead of few
turn/move ... speed .. ;. So yeah, if your standards are Cavedog scripts, it's not hard to do better.
Hmm, while I was typing that, I see more post where posted, such as "cuts the number of loops down to one". I had eventually came to the conclusion that maybe your "radical improvment" was to have each limb animation in its own thread, and now you're moving everything into one thread!
Ok, please, just answer my initial question:
What is the "radical improvement" we were supposed to see in your first post?