ボールの動作にはAPEパッケージを使用しています。

TransparentBall.as (メインクラス)
package {
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;   
    import flash.geom.Rectangle;
    import flash.filters.DisplacementMapFilter;
    import org.cove.ape.APEngine;
    import org.cove.ape.CircleParticle;
    import org.cove.ape.Group;
    import org.cove.ape.Vector;
    
    [SWF(width='550',height='400',backgroundColor='0x0',frameRate='40')]

    public class TransparentBall extends Sprite{
        [(source="bg_grid.png")]
        private var IMG:Class;
        
        private const WIDTH:Number = stage.stageWidth;
        private const HEIGHT:Number = stage.stageHeight;
        private var wall:Wall;
        private var objGroup:Group = new Group();
        private var objAry:Array = new Array();    
        private var sprAry:Array = new Array();
        private var bmpAry:Array = new Array();
        private var background:Bitmap;
        private static const RADIUS:int = 80;//must be tuned
    
        public function TransparentBall(){
            background = new IMG();
            addChild(background);
            APEInit();
            addEventListener(Event.ENTER_FRAME, run);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, createBall);
        }
        
        private function createBall(e:MouseEvent):void{
            var xPos:Number = mouseX;
            var yPos:Number = mouseY;
            
            //for near-walls
            if (xPos < RADIUS){
                xPos = RADIUS;
            }
            else if (xPos > WIDTH - RADIUS){
                xPos = WIDTH - RADIUS;
            }
            if (yPos < RADIUS){
                yPos = RADIUS;
            }
            else if (yPos > HEIGHT - RADIUS){
                yPos = HEIGHT - RADIUS;
            }
            
            var c:CircleParticle = new CircleParticle(xPos,yPos,RADIUS*1.05,false,1,0.6,0.1);
            
            c.setStyle(0,0x0,0,0x0,0);
            objGroup.addParticle(c);
            objAry.push(c);
            
            var spr:Sprite = new Sprite();
            spr.x = c.px;
            spr.y = c.py;
            sprAry.push(spr);
            addChild(spr);
            
            var fMap:Bitmap = new Bitmap();
            fMap.bitmapData = new BitmapData(2*RADIUS,2*RADIUS);
            fMap.bitmapData.copyPixels(background.bitmapData,
                new Rectangle(spr.x-fMap.width/2,spr.y-fMap.height/2,fMap.width,fMap.height),new Point(0,0));
            fMap.x = -fMap.bitmapData.width/2;
            fMap.y = -fMap.bitmapData.height/2;
            spr.addChild(fMap);
            bmpAry.push(fMap);
            
            var lens:BitmapData = createMap(RADIUS);
            var dispFilter:DisplacementMapFilter = new DisplacementMapFilter(
                lens,new Point(0,0),BitmapDataChannel.RED,BitmapDataChannel.BLUE,RADIUS,RADIUS);
            fMap.filters = [dispFilter];
        }
        
        //from "http://yamasv.blog92.fc2.com/blog-entry-100.html"
        private function createMap(r:int):BitmapData{
            var diameter:int = 2*r;
            var bmp:BitmapData = new BitmapData(diameter, diameter, false, 0x808080);
            for(var j:int = 0; j < diameter; j++){
                for(var i:int = 0; i < diameter; i++){
                    var ii:int = i - r;
                    var jj:int = j - r;
                    var distance:Number = Math.sqrt(ii*ii+jj*jj);
                    if(distance < r){
                        var v:Number = r*Math.asin(distance/r);
                        var theta:Number = Math.abs(Math.atan((j-r)/(i-r)));
                        var offsetR:int = (i > r) ? 
                            (v-distance)*Math.cos (theta) : -1*(v-distance)*Math.cos(theta);
                        var offsetB:int = (j > r) ? 
                            (v-distance)*Math.sin(theta) : -1*(v-distance)* Math.sin(theta);
                        var colR:int = 128 + offsetR;
                        var colB:int = 128 + offsetB;
                        bmp.setPixel(i, j, (colR << 16) + colB);
                    }
                }
            }
            return bmp;
        }

        private function APEInit():void{
            var wallThickness:Number = 100;
            
            APEngine.init(0.25);
            APEngine.container = this;
            APEngine.addMasslessForce(new Vector(0,5));
            
            wall= new Wall(WIDTH,HEIGHT,wallThickness);
            wall.addCollidable(objGroup);
            objGroup.collideInternal = true;
            APEngine.addGroup(wall);
            APEngine.addGroup(objGroup);
        }

        private function run(e:Event):void{
            chase();
            APEngine.step();
            APEngine.paint();
        }
        
        private function chase():void{
            var iMax:int = sprAry.length;
            for (var i:int=0; i<iMax; i++){
                var bmp:BitmapData = bmpAry[i].bitmapData;
                var rect:Rectangle = new Rectangle(objAry[i].px-bmp.width/2,objAry[i].py-bmp.height/2,bmp.width,bmp.height);
                bmpAry[i].bitmapData.copyPixels(background.bitmapData,rect,new Point(0,0));
                sprAry[i].x = objAry[i].px;
                sprAry[i].y = objAry[i].py;
            }
        }
    }
}
Wall.as (ステージ下左右の壁)
package{
    import org.cove.ape.RectangleParticle;
    import org.cove.ape.Group;
    
    public class Wall extends Group{
        
        private var rL:RectangleParticle;
        private var rR:RectangleParticle;
        //private var rT:RectangleParticle;
        private var rB:RectangleParticle;
        
        public function Wall(stageWidth:Number,stageHeight:Number,wallThickness:Number){
            rL = new RectangleParticle(-wallThickness/2,stageHeight/2,stageHeight,wallThickness,Math.PI/2,true);
            addParticle(rL);
            rR = new RectangleParticle(stageWidth+wallThickness/2,stageHeight/2,stageHeight,wallThickness,Math.PI/2,true);
            addParticle(rR);
            //rT = new RectangleParticle(stageWidth/2,-wallThickness/2,stageWidth,wallThickness,0,true);
            //addParticle(rT);
            rB = new RectangleParticle(stageWidth/2,stageHeight+wallThickness/2,stageWidth,wallThickness,0,true);
            addParticle(rB);
        }
    }
}
Powered by blog Boreal Kiss 2008.