dasPoda

now with 12% more Poda

Navigating within a loop

No comments

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; 
        };
    }
}

Written by dasPoda

Tuesday 31 March 2009 at 9:41 pm

Posted in flash

Used tags: , ,

No comments

Leave a Reply

(optional field)
(optional field)
Remember personal info?
Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.