Too many replies?
Printable View
Too many replies?
It was unstickied to reduce the number of stickies(To allow more first page threads, otherwise there isn't many on it).
It is in the knowledgebase, which holds all the used to be stickies.
I was interested in whether switch was faster than if-else, but the discussion earlier in this thread is almost three years old, and I couldn't find more recent posts discussing this.
I ran Strille's clever timer script, and just wanted to note that switch is decidedly faster than if-else in Flash 8. :)
yeah,switch is faster than if/else.
Then again besides the performance comparison which is good to know (for cases you can easily replace ifs with a switch) the switch/if(/else) comparison isn“t ideal because if/else can be used for more complex evaluations than ones based on single value check based ones,so its a bit like comparing apples with bananas :)
But yup,where you can,go for switch instead of if/else.
If you can also check for number values as switch case clauses rather than having strings as case clauses(strings are slower to evaluate than numbers)
I've never used a switch statement. Boring, but true. Also though, is switch quicker than
?Code:if(condition){
//...
} else {
if(condition2){
//...
} else {
if(condition3){
//... etc.
}
}
}
}
Squize.
That's exactly where switch would be faster Squize, but only really useable if all the conditions are alike (ie if your conditions were someVar==1, someVar==2, etc).
Your if construction might be faster when the first one evaluates to true (haven't tested), but if it's a value somewhere down the tree, it will have to evaluate all the other if's first. So in that case, switch should be faster, because it's more optimized to do that kind of thing.
Anyway, that seems logical to me, haven't done any benchmarks myself though :)
I'd like to see that benchmarked to be honest, 'cause the approach I wrote up above always used to be quicker [ Than switch ], so curious as to whether or not it's changed under 8.
Squize.
Well, I might do a little test then when I get home (in a few hours). You may be right, I was just guessing. I thought switch would actually use the same approach internally, but a bit more optimized - but I'm probably way off :)
Wrote this test for you:Quote:
Originally Posted by Squize
It runs both if..else and switch..case 100000 times and I dont see any practical difference in time between those. I used both Flash8 and Flash9 preview version.Code:var loops = 1000;
var mainLoops = 100;
var iftime = 0;
var switchtime = 0;
this.onEnterFrame = runme;
function runme() {
var startTime = getTimer();
for (var i = 0; i<loops; i++) {
var a = Math.floor(4*Math.random());
if (a == 0) {
var b = 1;
} else if (a == 1) {
var b = 2;
} else if (a == 2) {
var b = 3;
} else if (a == 3) {
var b = 4;
}
}
iftime += (getTimer()-startTime);
var startTime = getTimer();
for (var j = 0; j<loops; j++) {
var a = Math.floor(4*Math.random());
switch (a) {
case 0 :
var b = 1;
break;
case 1 :
var b = 2;
break;
case 2 :
var b = 3;
break;
case 3 :
var b = 4;
break;
}
}
switchtime += (getTimer()-startTime);
mainLoops--;
if (mainLoops<=0) {
trace(iftime);
trace(switchtime);
delete this.onEnterFrame;
}
}
Cheers mate :)
Although... for the if statements I mean this way ( The quicker way )
So when testing, I got for the original code:Code:if (a == 0) {
var b = 1;
} else {
if (a == 1) {
var b = 2;
} else {
if (a == 2) {
var b = 3;
} else {
if (a == 3) {
var b = 4;
}
}
}
}
If - 821
Switch - 886
Second test, using my conditionals above,
If - 803
Switch - 888
So the tests are around +/-5 ( Well, 2 at least in my two tests ) per run, which is usual ( Tested with F8 btw ).
It's still quite a difference between the two ( Kinda thought it would be to be honest, as switch pretty much is the same ( Even on a bytecode level ) as a load of if statements ).
Squize.
Yes, I can see how you optimised it :)
I dont think I ever bothered too much about if..else statements, even if you save 20ms from 100000 loops then I cant see it would speed up any real game.
I tried the example with 10 statements and it didnt change much, if..else is still constantly faster.
I made same example in AS3 to test new AS3VM. And the result with 4 if..else and 4 switch..case statements is:
if..else 4 ms
switch..case 99 ms
I dunno, it went from 800+ to 4 ms. Thats unbelievable, but I cant see any mistakes in my code... If the result is correct, it would mean switch is much slower in AS3 and using if..else would be surely recommended. Still, even switch would be up to 8 times faster then in AS2.
I like this situation. Win or Win more. :pQuote:
Still, even switch would be up to 8 times faster then in AS2.
I've done some testing too, in AS3, and turns out I wasn't completely wrong :)
I made a 40-level nested if (optimized like you proposed Squize), and then the equivalent switch-statement. I'm getting a slightly better time with the switch-version but only if it needs to evaluate all (or a lot of) the conditions. If the if-version evaluates to true somewhere at the beginning, it's a lot faster.
So, I admit, mostly you're better off with nested if's if you're really conserned about performance, but it is still possible to get better speeds with switch in some rare occasions. But really, the difference is minimal so just use the one which seems best for the situation.
Kinda taken this too far haven't we boys, at least we're all agreeing that it's a case of "Doesn't really matter, it's just good to know for sure" :)
Fally babe, I think way back on page 2 of this thread I mentioned about splitting up your conditionals if they're too big, so using your example of 40 ( Wow, you actually copied and pasted that many ? ) you'd first do a check to see if the value is > 20, and then split the checks up from there ( 2 lots of 20 test, rather than 1 of 40 ).
An extra check, so if the first test is true you'll lose, but on average you'll gain.
And again, it's such a tiny saving etc.
Tonypa those speeds seem pretty insane. I could almost look forward to having to learn AS3 :)
Squize.
Yeah, but it was pretty quick (I'm a good copy-paste-and-replacer, you get good at it after years of web development, lol), but if it wouldn't have shown switch can be a bit faster yet, I would have written a script with a loop that traced it with a depth of 100 or more so I could just use that output :)Quote:
Wow, you actually copied and pasted that many ?
Well, yeah, that makes sense off course, and I think I would have thought of that myself if I ever felt that my ifs were getting too slow. But I'm not that concerned with optimizing AS since the bottleneck is usually the rendering for most of the stuff I'm doing.Quote:
Fally babe, I think way back on page 2 of this thread I mentioned about splitting up your conditionals if they're too big, so using your example of 40 [...] you'd first do a check to see if the value is > 20
Agreed.Quote:
it's a case of "Doesn't really matter, it's just good to know for sure"
I'm sorry to not read through 19 pages of tips, but can someone just blatantly tell me what we've all agreed to be the fastest (non-square) hitTest?
Also, someone mentioned the distance hitTest being fast if you leave out the sqrt call. What did (they, you) mean by this?
My latest game has about 35 clips each test against about 40-50 objects, so I need some quite efficent and currently I'm using hitTest. There's major slowdown at 200 clips on screen.
its circle to circle without square root
goes like this:
FASTER:
SLOWER:Code:
var radius1 = (clip1._width * clip1._width)/2
var radius2 = (clip2._width * clip2._width)/2
var radius = radius1 + radius2
onEnterFrame = function(){
clip1._x += 1
var dx = clip1._x - clip2._x
var dy = clip1._y - clip2._y
var dist = dx*dx + dy*dy
if(dist < radius) trace("we hit but its faster")
}
Code:
var radius1 = clip1._width/2
var radius2 = clip2._width/2
var radius = radius1 + radius2
onEnterFrame = function(){
clip1._x += 1
var dx = clip1._x - clip2._x
var dy = clip1._y - clip2._y
var dist = Math.sqrt(dx*dx+dy*dy)
if(dist < radius) trace("we hit but its slower")
}
So that isn't true distance than, right? I don't see where you are "working around" the sqrt. You're just not using it.
EDIT: Wait is that what the radius1 radius 2 part is all about?
yes without the square root the numbers are quite large, therefore the radius has to be large as well
So, the purpose of using radius this way
Instead of thisCode:var radius1 = (clip1._width * clip1._width)/2
var radius2 = (clip2._width * clip2._width)/2
Is cos the first way you are taking the whole formula and making everyhting to the power of 2,Code:var radius1 = clip1._width/2
var radius2 = clip2._width/2
So, its faster cos you have to do this
Only once, out of each hitTest, instead of having an extra step to calculate the sqrt inside each test,right?Code:var radius1 = (clip1._width * clip1._width)/2
var radius2 = (clip2._width * clip2._width)/2
Clever, i wonder if this principle can be used in other things
I may be very dumb, cos i cant understand how you go from this
To thisCode:var radius1 = clip1._width/2
var radius2 = clip2._width/2
I mean, if its all to the power of 2, why its notCode:var radius1 = (clip1._width * clip1._width)/2
var radius2 = (clip2._width * clip2._width)/2
(clip1._width * clip1._width)/ 4
?
Or this power of 2 has nothing to do?
the radius of something is half its circumference
so if a ball has a radius of 10cm its circumference is 20cm
I know that, i dont understand the stuff necessary to drop the sqrt in the distance formula
I dont know if i made something wrong, but please look at this fla
With big clips,in this way
the test start to gives true without them to touch eah other,but thisCode:var radius1 = (clip1._width * clip1._width)/2;
var radius2 = (clip2._width * clip2._width)/2;
var radius = radius1 + radius2;
dontCode:var radius1 = clip1._width/2;
var radius2 = clip2._width/2;
var radius = radius1 + radius2;
radius = radius*radius;
WRONG. It's half the diameter.Quote:
Originally Posted by mr_malee
we all make mistakes :faded:
What's a circumference?
the distance around a circle
Ah, ok :)
Why dont you answer me?
Since noone bother in makes things clear, i am beginning to think there is no such thing as circle hitTest without sqrt, cos this way has a bug
But this dontCode:var radius1 = (clip1._width * clip1._width)/2;
var radius2 = (clip2._width * clip2._width)/2;
var radius = radius1 + radius2;
BUT this way is difficult to use cos you cant calculate the summ of the two radius before any test, cos you dont know what are you going to test, unless you pre calculate all the possible combinations before any hitTest, but with many clips this may be very dificult, and even if more clips are added dynamically?Code:var radius1 = clip1._width/2;
var radius2 = clip2._width/2;
var radius = radius1 + radius2;
radius = radius*radius;
create a circleToCircle hitTest function which accepts two circles and find the radius like that.
Circle to circle collision without a square root is very easy.
function checkCollision(circle1, circle2) {
circle1Radius = circle1._width>>1;
circle2Radius = circle2._width>>1;
xdist = circle2._x-circle1._x;
ydist = circle2._y-circle1._y;
return xdist*xdist+ydist*ydist<Math.pow(circle1Radius+cir cle2Radius, 2);
}
But what is the advantage in drop the sqrt this way since you have to add the stuff to calculate the power of the radius of the circle?
I mean, take out one thing and add another
OR do you mean that calculate this power stuff is faster them to calculate some sqrt?
Well, lemme put it this way:the radius of the balls will never change, so you can precalculate the square of their radii, but the x and y distances will be changing constantly.
thats an interesting way to do circle to circle vengeance, good to know :)
Still didnt get itQuote:
Originally Posted by VENGEANCE MX
The way i see, even if you have the two pre calculated sqrt radius, the distance should be compared to the sqrt of the sum of the two radius, not to the sqrt of one radius plus the sqrt of the another
I mean, sqrt(a + b) its not the same as sqrt(a) + sqrt(b),and so as (a+b)*(a+b) too
http://www.spiritonin.com/radius/collisionTheory.jpg
FASTER HITTEST FOR DOING TONS OF HIT DETECTION FOR PLATFORMS + PHYSICS
see www.spiritonin.com/radius - to see example in action
When doing a platform based game where you are checking collision on lots of blocks, I found it is much faster to do the hitTest(x,y,true) on the movieclip containing all the blocks, than it is to do a mc.hitTest(mc) on every block.
Problem is I have a bunch of physics stuff based on individual block detection.
I tried a method that I think is faster:
You do Two MC's in the same coordinates in the same timeline - "world"(contains all the blocks) and "worldEdges"(contains dynamically created blocks that are a certain amount larger than the "world" blocks, creating an edge around all of them visually You will see this in the game if you look at the example)
The amount larger is based on the size of your sprites, where the size should be a few pixels larger than half the width of the widest sprite (so if you are doing 32x32 sprites, make the edges ~20 pixels wider in each direction) so if you have a 50wx100h block, it should spawn a 90wx140h block that is 20 pixels up and left of the collision block, but in the "worldEdge" mc
Then when you do the hitest you check to see if the center point of the sprites is hitting "worldEdge" then if it is you check collsion on each platfrom in "world".
If you have different sized sprites, you can create more edge clips ("worldEdgeBig", "WorldEdgeMedium" etc...)
You can also do it for different types of platforms or platform groups to cut down on the number of MC's being tested when an edge is penetrated.
Hope that makes sense... It was a bit messy to set up, but the collision seems to work a lot cheaper especially with lots of enemies bouncing around the screen.
If anyone knows a faster way to check a complex set of block for detection, leg me know.
It was also recently proven by several of us that for AS3 at least, circle-to-circle collision detection (without the sqrt call) is significantly faster then anything else. The results are outlined in this thread along with sample code:
http://board.flashkit.com/board/showthread.php?t=710720
Rigth, in the code you posted on that thread you showned that this circle to circle without sqrt you had the collisionRange pre calculated BEFORE any test,in this way
Code:var collisionRange:Number = (heroRadius + enemyRadius) * (heroRadius + enemyRadius);
now that makes sense and that is a lot diferent from this
wich drops the sqrt but got to have a added step of find the pow of(circle1Radius + circle2Radius), so them becomes a matter of what is faster, pow vs sqrtQuote:
Code:function checkCollision(circle1, circle2) {
circle1Radius = circle1._width>>1;
circle2Radius = circle2._width>>1;
xdist = circle2._x-circle1._x;
ydist = circle2._y-circle1._y;
return xdist*xdist+ydist*ydist<Math.pow(circle1Radius+circle2Radius, 2);
}
And is also diferent to this,
wich seems a odd way to precalculate the collisionRange and gives an error, as i shown in the fla i have posted beforeQuote:
Code:var radius1 = (clip1._width * clip1._width)/2
var radius2 = (clip2._width * clip2._width)/2
var radius = radius1 + radius2
So, again, for this to work you have to pre calculate all the combinations of summs of all radius, and even this will not be enough if you will have dynamic things with diferent sizes added at runtime...well...at first i was think it could be very dificult but now maybe you could just build a function that makes the calculation of that and put the result in a array and that is called whenever a new dynamic enemy is created, so it finds the new pow of the summ of the new radius plus any other radius and put on that array...