
//begin
//
//
package logic
{
//
//
//
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.media.Video;
//
import flash.geom.Rectangle;
import flash.geom.ColorTransform;
//
A ColorTransform a színtranszformációhoz kell, mert a változásokat egyre halványuló zöld négyzetekkel szeretnénk jegyezni, és a halványításnak ez a legegyszerűbb módja. A Rectangle osztályt pedig a BitmapData használja téglalap kijelölésekhez.
//
//
//
public class MotionDetectorLogic
{
//
//
//
private var root:Object;
//
private var difColTR:ColorTransform;
private var actBMP:BitmapData;
private var oldBMP:BitmapData;
private var difBMP:BitmapData;
private var myBMP:Bitmap;
private var myVID:Video;
//
private var SENSITIVITY:int = 700000;
private var BLOCKSIZE:int = 10;
Az actBMP az aktuális, míg az oldBMP az eggyel előző állapotát tárolja a Videónak, a difBMP-be pedig az eltérést rajzoljuk. A SENSITIVITY a mozgásdetekció érzékenysélge, a BLOCKSIZE pedig a felbontása.
//
//
//
public function MotionDetectorLogic ( myRoot:Object ):void
{
//
root = myRoot;
//
difColTR = new ColorTransform( 1 , 1 , 1 , .7 , 0 , 0 , 0 , 0 );
//
actBMP = new BitmapData( 320 , 240 , false , 0x000000 );
oldBMP = new BitmapData( 320 , 240 , false , 0x000000 );
difBMP = new BitmapData( 320 , 240 , true , 0x000000 );
//
addLog( "new MotionDetectorLogic " );
//
}
//
//
//
public function setVideo ( vidOBJ:Video ):void
{
//
myVID = vidOBJ;
//
addLog( "MotionDetectorLogic.setVideo " + vidOBJ );
//
}
//
//
//
public function setBitmap ( bmpOBJ:Bitmap ):void
{
//
myBMP = bmpOBJ;
myBMP.bitmapData = difBMP;
//
addLog( "MotionDetectorLogic.setBitmap " + bmpOBJ );
//
}
Ezek értelemszerűek, illetve annyi érdekesség van, hogy a difBMP-nek kell egyedül transzparensne k lennie, ezért lett true a transzparencia, illetve itt a Bitmap "classunk" üresen jött létre a vezérlőkódban, így itt kell hozzárendelnünk a BitmapData - t.
//
//
//
public function getPoints ( ):Array
{
//
actBMP.draw( myVID );
//
var diffPoints:Array = [ ];
//
for ( var a:int = 0 ; a < actBMP.width ; a += BLOCKSIZE )
for ( var b:int = 0 ; b < actBMP.height ; b += BLOCKSIZE )
{
//
var oldPx:uint = oldBMP.getPixel( a , b );
var newPx:uint = actBMP.getPixel( a , b );
//
if ( ( oldPx - SENSITIVITY ) > newPx || ( oldPx + SENSITIVITY ) < newPx )
diffPoints.push( { x:a , y:b } );
//
}
//
oldBMP = actBMP.clone( );
drawDifference( diffPoints );
//
//addLog( "MotionDetectorLogic.getPoints " + diffPoints );
//
return diffPoints;
//
}
Ez a függvény végzi a tényleges melót, első lépésként "leképezem" a videót azt actBMP-re, és végigpörgetem a pontjait a megadott lépésközzel, ott pedig megnézem, hogy az oldBMP-hez képest a vizsgált pontok változása tűréshatáron belül-e van ( a tűréshatár nélülözhetetlen, lévén a fény meglehetősen analóg jelenség :) ), és ha igen, akkor berakom a tömbömbe a többi pont mellé. Mielőtt visszatérnék, még fölrajzolom a pontokat a difBMP-be.
//
//
//
public function drawDifference ( diffPoints:Array ):void
{
//
difBMP.colorTransform( difBMP.rect , difColTR );
//
for ( var a:int = 0 ; a < diffPoints.length ; ++a )
{
//
var p:Object = diffPoints[a];
var rect:Rectangle = new Rectangle( p.x , p.y , BLOCKSIZE , BLOCKSIZE );
difBMP.fillRect( rect , 0xff00ff00 );
//
}
//
//addLog( "MotionDetectorLogic.drawDifference" );
//
}
Először halványítok egyett a differencia Bitmap-en, aztán simán végigpörgök a detektált pontokon, és kihányok a difBMP-re egy lépésköz*lépésköz-ös zöld négyzetet.
//
//
//
public function addLog ( logText:String ):void
{
//
this.root.addLog( logText );
//
}
//
//
//
}
//
//
//
}
//
//
//end
FootballGame.as:
//begin
//
//
package
{
//
//
//
import flash.media.Camera;
import flash.media.Video;
import flash.display.Bitmap;
import flash.display.MovieClip;
import flash.display.Loader;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.media.Sound;
import flash.net.URLRequest;
import flash.events.*
import flash.utils.*;
//
import logic.MotionDetectorLogic;
import logic.InteractivePointLogic;
import flash.display.Sprite;
Na itt aztán van mit importálni, kelleni fog nekünk Kamera, Videó, az új MotionDetector logikánk, meg még az előző cuccok.
//
//
//
public class FootballGame extends Sprite
{
//
//
private var moveTimer:Timer;
//
private var hasSkin:Boolean;
private var hasSound:Boolean;
private var ballSkinLO:Loader;
private var ballSkinSP:Sprite;
private var ballPopSND:Sound;
private var ballPoint:InteractivePointLogic;
//
public var RADIUS:Number = 20;
public var WIDTH:int = 320;
public var HEIGHT:int = 240;
//
private var xspeed:Number;
private var yspeed:Number;
private var oldx:Number;
private var oldy:Number;
//
private var motDetOBJ:MotionDetectorLogic;
private var movieVID:Video;
private var movieBMP:Bitmap;
private var movieCAM:Camera;
Fölvettem a szükséges változókat a Videohoz, Kamerához és Bitmap-hez, továbbá új konstansokat RADIUS, WIDTH, HEIGHT névvel, ugyanis már sok helyen használom őket, sőt, az InteractivePointLogic is kinyúl értük.
//
//
//
public function FootballGame ( )
{
//
stage.frameRate = 25;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP;
//
movieVID = new Video( );
movieBMP = new Bitmap( );
movieCAM = Camera.getCamera( );
movieVID.attachCamera( movieCAM );
addChild( movieVID );
addChild( movieBMP );
//
motDetOBJ = new MotionDetectorLogic( this );
motDetOBJ.setVideo( movieVID );
motDetOBJ.setBitmap( movieBMP );
//
loadSkin( );
loadSound( );
//
addLog( "new FootballGame" );
//
}
A konstruktorból kivettem a háttérrajzolást, a Videó fogja őt helyettesíteni, és inicializálom a MotionDetectorLogic-ot.
//
//
//
public function loadSkin ( ):void
{
//
ballSkinSP = new Sprite( );
addChild( ballSkinSP );
//
var urlRequest:URLRequest = new URLRequest( "soccerball.gif" );
ballSkinLO = new Loader( );
ballSkinLO.contentLoaderInfo.addEventListener( Event.COMPLETE , skinLoaded );
ballSkinLO.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR , ioErrorHandler );
ballSkinLO.load( urlRequest );
ballSkinSP.addChild( ballSkinLO );
//
addLog( "FootballGame.loadSkin" );
//
}
//
//
//
public function loadSound ( ):void
{
//
var urlRequest:URLRequest = new URLRequest( "pop.mp3" );
ballPopSND = new Sound( );
ballPopSND.addEventListener( Event.COMPLETE , soundLoaded );
ballPopSND.addEventListener( IOErrorEvent.IO_ERROR , ioErrorHandler );
ballPopSND.load( urlRequest );
//
addLog( "FootballGame.loadSoun" );
//
}
//
//
//
public function ioErrorHandler ( eventOBJ:Event ):void
{
//
addLog( "ioError: " + eventOBJ );
//
}
//
//
//
public function skinLoaded ( eventOBJ:Event ):void
{
//
ballSkinLO.x = -RADIUS;
ballSkinLO.y = -RADIUS;
ballSkinLO.width = 2*RADIUS;
ballSkinLO.height = 2*RADIUS;
hasSkin = true;
initLogic( );
//
addLog( "FootballGame.skinLoaded" );
//
}
//
//
//
public function soundLoaded ( eventOBJ:Event ):void
{
//
hasSound = true;
initLogic( );
//
addLog( "FootballGame.soundLoaded" );
//
}
//
//
//
public function initLogic ( ):void
{
//
if ( hasSkin && hasSound )
{
//
ballPoint = new InteractivePointLogic( this );
ballPoint.xpos = 20;
ballPoint.ypos = 20;
ballPoint.xspeed = Math.random( )*5;
ballPoint.yspeed = Math.random( )*5;
ballPoint.setSkin( ballSkinSP );
ballPoint.setSound( ballPopSND );
//
moveTimer = new Timer( 25 );
moveTimer.addEventListener( TimerEvent.TIMER , step );
moveTimer.start( );
//
}
//
addLog( "FootbalGame.initLogic " + hasSkin + " " + hasSound );
//
}
//
//
//
public function step ( eventOBJ:Event ):void
{
//
var diffARR:Array = motDetOBJ.getPoints( );
//
for ( var a:int = 0 ; a < diffARR.length ; ++a )
{
//
var dx:Number = ballPoint.xpos - diffARR[a].x;
var dy:Number = ballPoint.ypos - diffARR[a].y;
var dr:Number = Math.sqrt( dx*dx + dy*dy );
//
if ( dr < RADIUS )
{
//
ballPoint.xspeed = dx;
ballPoint.yspeed = dy;
break;
//
}
//
}
//
ballPoint.step( );
//
}
A másik lényeges dolgot a step függvény végzi el, lekérdezi a válozásokat a MotionDetector-tól, majd csinál egy primitív ütközésvizsgálatot: megnézi a labda középpontja és a különbségpontok közötti távolságot, és ha a táv kisebb mint a labda sugara, akkor ütközés van: átadja a pointLogic-nak x és yspeed értékeket, majd leállítja a for ciklust: fölösleges tovább pörgetni, és életszerűbb a hatás is.
//
//
//
public function dragBall ( ):void
{
//
addEventListener( MouseEvent.MOUSE_MOVE , moveBall );
moveTimer.stop( );
//
addLog( "FootbalGame.dragBall" );
//
}
//
//
//
public function releaseBall ( ):void
{
//
removeEventListener( MouseEvent.MOUSE_MOVE , moveBall );
ballPoint.xspeed = xspeed;
ballPoint.yspeed = yspeed;
moveTimer.start( );
//
addLog( "FootbalGame.releaseBall" );
//
}
//
//
//
public function moveBall ( eventOBJ:MouseEvent ):void
{
//
ballPoint.xpos = mouseX;
ballPoint.ypos = mouseY;
ballPoint.updateSkin( );
//
xspeed = mouseX - oldx;
yspeed = mouseY - oldy;
//
oldx = mouseX;
oldy = mouseY;
//
addLog( "FootbalGame.moveBall" + mouseX + " " + mouseY );
//
}
//
//
//
public function addLog( logText:String ):void
{
//
trace( logText );
//
}
//
//
//
}
//
//
//
}
//
//
//end
A többi pedig megmaradt múltkorról. InteractivePointLogic:
//begin
//
//
package logic
{
//
//
//
import flash.display.Sprite;
import flash.display.Loader;
import flash.media.Sound;
import flash.events.*;
//
//
//
public class InteractivePointLogic
{
//
//
//
private var root:Object;
private var gravity:Number = 0.5;
private var skinSP:Sprite;
private var ballSND:Sound;
//
public var xpos:Number;
public var ypos:Number;
public var xspeed:Number;
public var yspeed:Number;
//
//
//
public function InteractivePointLogic ( myRoot:Sprite )
{
//
root = myRoot;
addLog( "new InteractivePointLogic" );
//
}
//
//
//
public function setSkin ( mySP:Sprite ):void
{
//
skinSP = mySP;
skinSP.addEventListener( MouseEvent.MOUSE_DOWN , mouseDownHandler );
skinSP.addEventListener( MouseEvent.MOUSE_UP , mouseUpHandler );
//
addLog( "InteractivePointLogic.setSkin " + mySP );
//
}
//
//
//
public function updateSkin ( ):void
{
//
skinSP.x = xpos;
skinSP.y = ypos;
skinSP.rotation += xspeed;
//
//addLog( "InteractivePointLogic.updateSkin" );
//
}
//
//
//
public function setSound ( mySND:Sound ):void
{
//
ballSND = mySND;
//
addLog( "InteractivePointLogic.setSound " + mySND );
//
}
//
//
//
public function step ( ):void
{
//
yspeed += gravity;
//
if ( xpos + xspeed > root.WIDTH - root.RADIUS )
{
//
ballSND.play( );
xspeed *= -.9;
//
}
//
if ( xpos + xspeed < 0 + root.RADIUS )
{
//
ballSND.play( );
xspeed *= -.9;
//
}
//
if ( ypos + yspeed > root.HEIGHT - root.RADIUS - 20 )
{
//
ballSND.play( );
yspeed -= gravity;
yspeed *= -.9;
//
}
//
if ( ypos + yspeed < 0 + root.RADIUS )
{
//
ballSND.play( );
yspeed *= -.9;
//
}
//
xpos += xspeed;
ypos += yspeed;
//
updateSkin( );
//
//addLog( "InteractivePointLogic.step" );
//
}
//
//
//
public function mouseDownHandler ( eventOBJ:MouseEvent ):void
{
//
root.dragBall( );
//
}
//
//
//
public function mouseUpHandler ( eventOBJ:MouseEvent ):void
{
//
root.releaseBall( );
//
}
//
//
//
private function addLog ( logText:String ):void
{
//
root.addLog( logText );
//
}
//
//
//
}
//
//
//
}
//
//
//end
Itt nem sok változás történt: bekerültek a apaosztálybeli konstansok. ( a father változót root-ra neveztem, mivel ezek már "sima", nem DisplayObjectből származtatott osztályok, így nincs ütközés ) Élesben itt látható: motionballForrás: motionballHa túl érzékeny/nem érzékel semmit a kód, akkor MotionDetectorLogic SENSITIVITY konstansát kell birizgálni. Ha frankó az érzékenység, akkor ki lehet kommentezni a MotionDetectorLogic osztály getPoints függvényéből a drawDifference-t, és mehettek "vakon" :) Jó szórakozást, nekem a fejelés már profin megy :) /hmm, most látom csak, hogy a vezérlőosztály függvényeit jobb lett volna privátként értelmezni az egéresemények kivételével, most már mindegy :) / MilGra
Harder
Profil