We are going to make a very cool and spectacular thing now: we check the camera input for differences continously, and move our bouncing ball from the previous articles based on these differences, so we can hit the ball with our head for example.

We need a motion detector logic first. We have to capture the actual state of the camera input, and compare it to the previous state, searching for color differences. If color difference occurs, there was motion, and we have to store its coordinate. We can't compare every pixel, because it is very cpu-demanding, we have to use a little stepping.

So our first class will be the MotionDetector class. Create it in Flex/Eclipse.

package
{
   
    import flash.geom.Point;
   
    import flash.media.Video;
    import flash.media.Camera;
   
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.display.Bitmap;
   
   
    public class MotionDetector
    {
       

        // the subject of motion detection
        private var video:Video;
       
        // to store previous state
        private var oldData:BitmapData;
       
        // to store actual state
        private var newData:BitmapData;
       
        // stepping blocks
        private var blockSize:Number;
       
        // detection sensitivity
        private var sensitivity:Number;
       
       
        public function MotionDetector ( argVideo:Video ,
                                         argBlockSize:Number ,
                                         argSensitivity:Number )
        {
           
            video = argVideo;
            blockSize = argBlockSize;
            sensitivity = argSensitivity;
           
            oldData = new BitmapData( video.width , video.height , false );
            newData = new BitmapData( video.width , video.height , false );            
           
        }
       
       
        public function getDifferences ( ):Array
        {
           
            // capturing new state

            newData.draw( video );
           
            var differences:Array = [ ];
       
            // looping through points with stepping

            for ( var px:int = 0 ; px < newData.width ; px += blockSize )
            {
               
                for ( var py:int = 0 ; py < newData.height ; py += blockSize )
                {
                   
                    //getting previous and actual pixel color data

                    var oldPixel:uint = oldData.getPixel( px , py );
                    var newPixel:uint = newData.getPixel( px , py );
                   
                    // checking difference threshold

                    if ( Math.abs( newPixel - oldPixel ) > sensitivity )
                    {
                       
                        // if bigger than sensitivity, storing point

                         differences.push( new Point( px , py ) );
                             
                    }
                   
                }
               
            }
           
            // save previous state

            oldData.copyPixels( newData , newData.rect , new Point( 0 , 0 ) );
           
            return differences;
           
        }
       
    }
   
}


Nothing magical happens here, we check every nth pixel of the bitmapdatas, and store differences above threshold.

Let's see the main class. We have to add a lot to the code from the previous examples.

FirstCircle.as :

package
{
   
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.geom.ColorTransform;
   
    import flash.media.Video;
    import flash.media.Camera;
    import flash.events.Event;
   
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;

    public class FirstCircle extends Sprite
    {
       
        // circle to difference point collosion radius
        private static var RADIUS:Number = 20;
        // motion detection stepping
        private static var BLOCKS:Number = 5;
        // motion detection sensitivity
        private static var SENSITIVITY:Number = 700000;
       
        // bitmapdata to show detected differences for better understanding
        private var helperData:BitmapData;
        // colortransform to darken old difference points
        private var helperTransform:ColorTransform;
       
        private var circle:MovingCircle;
        private var detector:MotionDetector;


        public function FirstCircle( )
        {
           
            // default video size

            var video:Video = new Video( 320 , 240 );

            // bitmap to show helperData

            var helper:Bitmap = new Bitmap( );

            // getting default camera

            var camera:Camera = Camera.getCamera( );
           
            helperData = new BitmapData( 320 , 240 , true , 0x000000 );
            helperTransform = new ColorTransform( 1 , 1 , 1 , .7 , 0 , 0 , 0 , 0 );
           
            helper.bitmapData = helperData;
            video.attachCamera( camera );
           
            addChild( video );
            addChild( helper );
           
            detector = new MotionDetector( video , BLOCKS , SENSITIVITY );
           
            stage.addEventListener( Event.ENTER_FRAME , init );
                                   
        }
       
       
        public function init ( event:Event ):void
        {
           
            stage.removeEventListener( Event.ENTER_FRAME , init );
            stage.addEventListener( Event.ENTER_FRAME , step );
           
            circle = new MovingCircle( );
           
            addChild( circle );
           
            circle.init( );
           
        }
       
       
        public function step ( event:Event ):void
        {
           
            var differences:Array = detector.getDifferences( );
            var circlePosition:Point = new Point( circle.x , circle.y );
           
            // loop through difference points

            for ( var a:String in differences )
            {
               
                // check distance from circle

                var dr:Number = Point.distance( circlePosition , differences[a ] );
               
                // if any point is closer than RADIUS

                if ( dr < RADIUS )
                {
                   
                    var dx:Number = circlePosition.x - differences[a ].x;
                    var dy:Number = circlePosition.y - differences[a ].y;
                   
                    circle.xspeed = dx;
                    circle.yspeed = dy;
                   
                    // stop check

                    break;
                   
                }
               
            }
           
            // darkening prevous state of helperData

            helperData.colorTransform( helperData.rect , helperTransform );
           
            // loop through difference points

            for ( var b:String in differences )
            {
               
                var helpRectangle:Rectangle = new Rectangle( differences[b].x ,
                                                             differences[b].y ,
                                                             BLOCKS ,
                                                             BLOCKS );
               
                // drawing a green BLOCKS edge sized rectangle at every point

                helperData.fillRect( helpRectangle , 0xff00ff00 );
               
            }
           
        }

    }

}


As you see we initialized the video object and the camera here in the main class, so MotionDetector is independent from the camera input, or everything else we want to do with the video. We also created a helper bitmap data to make differences visible to human eye.

After init, we use stage's ENTER_FRAME event further : like motion stepping in MovingCircle class, we trigger motion and collosion detection and difference drawing here. If we would like a cleaner code, we should trigger MovingCircle's step function from here, and delete frame listening from inside.

MovingCircle class stays the same, only two new lines needed for our little program : i made the soccerball smaller in the constructor to make the game more "playable".

package
{
   
    import flash.media.Sound;
   
    import flash.events.Event;
    import flash.events.MouseEvent;
   
    import flash.display.Sprite;
    import flash.display.Bitmap;
   
       
    public class MovingCircle extends Sprite
    {
       
        // for realistic movement we use gravity    
       
        public static var gravity:Number = 1;
       
        public var xspeed:Number;
        public var yspeed:Number;
       
        // we want to "throw" the ball, that's why we need previous positions
        // to calculate new speed components
       
        private var oldx:Number
        private var oldy:Number;
       
        // gfx will be our "skin"
        // sfx will be our sound
       
        private var gfx:Bitmap;
        private var sfx:Sound;
       
        // that's how we embed external assets
        // we have to define individual class names for them
       
        [ Embed ( source = "soccerball.gif" ) ] private var soccerGFXClass:Class;
        [ Embed ( source = "pop.mp3" ) ] private var soccerSFXClass:Class;        
       
        public function MovingCircle ( )
        {

            // instantiating embedded assets
           
            gfx = new soccerGFXClass( );
            sfx = new soccerSFXClass( );
           
            addChild( gfx );
           
            // setting gfx smaller
           
            gfx.width = 40;
            gfx.height = 40;
           
            // repositioning skin to middle to make bouncing more precise
           
            gfx.x = - width / 2;
            gfx.y = - height / 2;
           
        }
       
        // initialization, called after parent addChild
       
        public function init ( ):void                    
        {
           
            // x , y and stage are inherited properties
            // watching our width and height not to cross "wall"
           
            x = width / 2 + Math.random( ) * ( stage.stageWidth - width / 2 );        
            y = height / 2 + Math.random( ) * ( stage.stageHeight - height / 2 );
           
            xspeed = 5 + Math.random( ) * 10;
            yspeed = 5 + Math.random( ) * 10;
           
            // starting triggering step function based on enterframe event
           
            addEventListener( Event.ENTER_FRAME , step );
           
            // adding mouseevents to make ourself draggable
           
            addEventListener( MouseEvent.MOUSE_DOWN , dragCircle );
            addEventListener( MouseEvent.MOUSE_UP , releaseCircle );
           
        }
       
        private function dragCircle ( event:MouseEvent ):void
        {
           
            // when mousedown, we starting to listen to mouse movement of the stage
            // to catch stage mouse coordinates
       
            stage.addEventListener( MouseEvent.MOUSE_MOVE , moveCircle );
           
            // we stop stepping during dragging
           
            removeEventListener( Event.ENTER_FRAME , step );
           
        }
       
        private function releaseCircle ( event:MouseEvent ):void
        {
           
            // removeing stage mousemove listening
       
            stage.removeEventListener( MouseEvent.MOUSE_MOVE , moveCircle );                
           
            // start stepping
           
            addEventListener( Event.ENTER_FRAME , step );
           
        }
       
        private function moveCircle ( event:MouseEvent ):void
        {
           
            // storing previous coordinates
           
            oldx = x;
            oldy = y;
           
            x = event.stageX;
            y = event.stageY;
           
            // calculating new speed components
           
            xspeed = x - oldx;
            yspeed = y - oldy;
           
        }
       
        public function step ( event:Event ):void
        {
           
            // setting position
           
            x += xspeed;
            y += yspeed;
           
            // adding gravity to y component
           
            yspeed += gravity;
           
            // rotating for realistic movement
           
            rotation += xspeed;
           
            // bouncing ball at stage edges
           
            if ( x + xspeed > stage.stageWidth - width / 2 )
            {
           
                xspeed *= -1;    
                sfx.play( );    // playing sound
               
            }
            else if ( x + xspeed < width / 2 )
            {
           
                xspeed *= -1;
                sfx.play( );    // playing sound
           
            }
           
            if ( y + yspeed > stage.stageHeight - height / 2 )
            {
           
                yspeed *= -1;
                sfx.play( );    // playing sound
           
            }
            else if ( y + yspeed < height / 2 )
            {
               
                yspeed *= -1;
                sfx.play( );    // playind sound    
               
            }
           
        }
       
    }
   
}


Finally, we have to make our movie's size 320x240. Project menuitem - Properties - Actionscript Compiler - Additional compiler arguments :
-default-size 320 240

Everything should work fine now. Check it under attachments.