Performance Links
I found these pretty nifty:
replacing TextField and improving performance
http://lab.polygonal.de/2009/04/26/goodbye-textfield/
Round up of ActionScript 3.0 and Flex optimization techniques and practices
http://www.insideria.com/2009/04/51-actionscript-30-and-flex-op.html
Tips on how to write efficient AS3
part 1
part 2
a faster way of tweening (faster than tween max, but who's measuring)
Tweensy
Navigating within a loop
My loop class
I have come up against this a few times, where I needed to create a series of numbers, usually integers, that are in loop. The first time I came across
This was for the salted herring portfolio website. I needed to create these fish/cursors that displayed some basic flocking behaviour. Along with the standard boid setup, they had to face either left or right. They would only point up or down when they were moving that direction. The change in direction also needed to be smooth, which leads us to our problem of averaging angles. If you do the average of 0 and 60 degrees, you can do some simple arithmetic and you get the average of 30. However if you average 350 and 10, trigonometry would give us 0 where as basic arithmetic would give us 180. The reason is that our equation doesn’t know how that 10 is closer to 350 if you go the other direction.
This is how I dealt with that…
I converted both the angles to their x and y components, and averaged those. Then I did an aTan on the averaged x and y values, giving me the average of the two angles.
This is the simplified formula in a function that would get the average of angles a and b (in radians).
private function averageNums($a:Number, $b:Number):Number {
var avg:Number = (Math.atan2( Math.sin($a) + Math.sin($b) , Math.cos($a) + Math.cos($b) ));
return avg;
}
This worked for the fish, but there is a problem with this equation. If you average 0 and 180 degrees you will not get the right average.
I noticed this when I worked on another project that was looping images and I thought I could use this simple system, where instead of using 360 degrees total, I could use the set number of frames I had and round to the closest int. After spending a bit of time with the trig way of doing this, I found a much more versatile way of doing this by simply looking for the value that’s closer and finding the distance. In addition to getting a bit more reliability here, I’m now able to interpolate between the two values.
Here is the code:
/**
* LoopNavigator - stack size has to be assigned
* functions:
* getDistance
* travel
* interpolate
*/
package loopNavigator {
/**
* @author Daniel Poda / 2009
*/
public class LoopNavigator {
private var _stackSize:int;
public function LoopNavigator($stackSize:int) {_stackSize = $stackSize;}
/**
* Get distance from $a to $b
* @param $a
* @param $b
* @return
*/
public function getDistance($a:int, $b:int):int {
// get all distances and find the smallest
var norm$B:int = $b - $a; // normalize
var dist:int;
var dist2:int;
dist = norm$B;
dist2 = _stackSize-((_stackSize - norm$B)%_stackSize);
if (dist == dist2) {
dist2 = (norm$B - _stackSize) % _stackSize;
}
if (abs(dist) > abs(dist2)) { dist = dist2 }
return dist;
}
/**
* Travel $distance from $start
* @param $start - staring int
* @param $dist - direction(+/-) and distance to travel
* @return distance and direction of travel
*/
public function travel($start:int, $dist:int):int {
var b:int = ($start + $dist)%_stackSize;
if (b < 0) { b = _stackSize + b };
return b;
}
/**
* Interpolate the value between $a and $b
* @param $a
* @param $b
* @param $i interpolate value defaults to 0.5 - halfway
* @return interpolated value
*/
public function interpolate($a:int, $b:int, $i:Number=0.5):int {
// get distance
var dist:int = Math.round(getDistance($a, $b) * $i);
return travel($a, dist);
}
// for a small speed boost
private function abs($num:Number):Number {
if ($num < 0) { return -$num }; return $num;
};
}
}
Calling Javascript from Flash
This just in
I was used to sending calls to java from within the flash file using the navigateToURL function. If you look around the Google, you will find a lot of people are doing the same still. In AS3, there is a more reliable alternative - ExternalInterfaceCall
I'm saying more reliable, since I found out that IE6 does not necessarily like calling java from an swf using navigateToURL. (I believe sp1 wasn't liking it but sp2 was OK)
Aside from being more reliable, it is also a bit shorter.
var myData:String = "my data string";
// using navigateToURL
var js:URLRequest = new URLRequest();
js.url = "javascript:sendToJavaScript('" + myData + "')";
navigateToURL(js, '_self');
// using External interface call
ExternalInterface.call("sendToJavaScript", myData);
Un-checking Radio Buttons in AS3
Radio Buttons and Un-checking in AS3
There is no direct way of un-checking a radio burron. However here's a work-around: create an invisible radio button and don't include it as a child but do add it to the radio button group.
Example:
// Let’s say you have a radio button group (RBGroup) and three radio Buttons (RB1, RB2 and RB3) // First thing you need to do is add the RB’s to the group and add them as chilren RB1.group = RBGroup ; RB2.group = RBGroup ; RB3.group = RBGroup ; addChild(RB1) ; addChild(RB2) ; addChild(RB3) ; //To change the selection you would… RBGroup.selection = RB1 ; //And to to check the selection you can do this trace(RB1.selected); // However, 'RB1.selected' This is a read-only parameter, so you couldn’t set all to false to un-check them // Create another radio button and add it to the group RBnone.group = RBGroup; // Then you can change the selection to RBnone RBGroup.selection = RBnone;
And as long as this radio button is NOT ADDED as child (invisible) it will appear to be unselecting all.
crossing lines in AS3
Trying to see if two lines connect or not?
Here's a little class (just barely) I wrote to aid with a little personal project
the idea is that you treat both lines as functions and equate them to one another.
Pa + fa * (Pb - Pa) = Pc + fb * (Pd - Pc);
Each point is made of x and y, so you separate the equation by substituting each point by x and then y; You can then solve for fa and fb;
It is important to solve for both fa and fb because the in both cases you are treating the intersecting line as infinite. (of course, this could be useful in some applications)
If the resulting numbers fall within 0 and 1, they intersect. if the number is infinity, they are parallel. In my code, I'm excluding when this number is 0 or 1. These are the end points, and I don't consider that as crossing.
package
{
import flash.geom.Point;
/**
* ...
* @author Daniel Poda / 2008
*/
package
{
import flash.geom.Point;
/**
* ...
* @author Daniel Poda / 2008
*/
public class pointUtils
{
public function getIntersectingPointF($A:Point, $B:Point, $C:Point, $D:Point):Number {
var A:Point = $A.clone();
var B:Point = $B.clone();
var C:Point = $C.clone();
var D:Point = $D.clone();
var f_ab:Number = (D.x - C.x) * (A.y - C.y) - (D.y - C.y) * (A.x - C.x);
// are lines parallel
if (f_ab == 0) { return Infinity };
var f_cd:Number = (B.x - A.x) * (A.y - C.y) - (B.y - A.y) * (A.x - C.x);
var f_d:Number = (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y);
var f1:Number = f_ab/f_d
var f2:Number = f_cd / f_d
if (f1 == Infinity || f1 <= 0 || f1 >= 1) { return Infinity };
if (f2 == Infinity || f2 <= 0 || f2 >= 1) { return Infinity };
return f1;
}
public function getIntersectingPoint($A:Point, $B:Point, $C:Point, $D:Point):Point
{
var f:Number = getIntersectingPointF($A, $B, $C, $D);
if (f == Infinity || f <= 0 || f >= 1) { return null };
var retPoint:Point = Point.interpolate($A, $B, 1 - f);
return retPoint.clone();
}
}
}