Forked from: HaraMakoto's forked from: Yawaraka Balls diff:17 forked from: forked from: Yawaraka Balls fukt forked:0favorite:1lines:165license : MIT License modified : 2009-11-26 02:37:37 Embed Tweet // forked from HaraMakoto's forked from: Yawaraka Balls // forked from k0rin's Yawaraka Balls package { import flash.display.*; [SWF(width = "640", height = "480", frameRate = "60")] public class Main extends Sprite { public function Main() { main = this; initialize(); } } } import flash.display.*; import flash.events.*; import flash.filters.*; import flash.geom.*; import flash.text.*; var main:Main; var floor:Sprite = new Sprite(); var space:Sprite = new Sprite(); const SCREEN_W:int = 640; const SCREEN_H:int = 480; const FLOOR_Y:Number = 350; class Ball { private var radius:Number; private var x:Number; private var y:Number; private var vx:Number; private var vy:Number; // contact offset point for deformation private var cx:Number = 0; private var cy:Number = 0; private var priority:int = 0; private var body:Shape; private var shadow:Shape; private var shadowFilter:BlurFilter = new BlurFilter(); private static var matrix:Matrix = new Matrix(); function Ball(radius:Number, color:uint) { this.radius = radius; x = random(radius, SCREEN_W - radius); y = random(50, FLOOR_Y - radius); vx = random( -1.5, 1.5); vy = random( 0, 1.5); body = new Shape(); var g:Graphics = body.graphics; matrix.createGradientBox( 0, 0, 0, -radius); g.beginGradientFill(GradientType.RADIAL, [color, color, color], [0.9, 0.8, 0.4], [0, 240, 255], matrix); g.drawRect(0, 0, 100,100); g.endFill(); shadow = new Shape(); g = shadow.graphics; g.beginFill(0xcccccc); g.drawRect(0, 0, 100,100); g.endFill(); floor.addChild(shadow); space.addChild(body); } // 接触点の絶対座標を指定 public function contact(contactX:Number, contactY:Number, priority:int, force:Number):void { var tx:Number = contactX - x; var ty:Number = contactY - y; var angle:Number = Math.atan2(ty, tx); var length:Number = Math.sqrt(tx * tx + ty * ty); vx -= (1 - length / radius) * force * Math.cos(angle); vy -= (1 - length / radius) * force * Math.sin(angle); // 変形のための接触点は1つしか使用できない。床を優先させる。 if (this.priority < priority) { this.priority = priority; cx = tx; cy = ty; } } public function update():void { cx = 0; cy = 0; priority = 0; x += vx; y += vy; if (x - radius < 0) { contact(0, y, 1, 0.125); //x = SCREEN_W+radius; } if (x + radius > SCREEN_W) { contact(SCREEN_W, y, 1, 0.125); //x = radius-10; } if (y + radius > FLOOR_Y) { contact(x, FLOOR_Y, 3, 0.125); } else { vy += 0.005; } // すごい勢いで壁にぶつかったときは即座に反射 //if (x < 0 || x > SCREEN_W) { vx = -vx; } //if (y > FLOOR_Y) { vy = -vy; } // 画面外のボールをこっそり減速して、全体の動きを永続化 if (y < -radius) { vx *= 0.9996; vy *= 0.9996; } } public function hitTest(ball:Ball):void { var dx:Number = ball.x - x; var dy:Number = ball.y - y; var distanceSquared:Number = dx * dx + dy * dy; var contactDistance:Number = radius + ball.radius; if (distanceSquared < contactDistance * contactDistance) { var tx:Number = linearTransform(radius, 0, contactDistance, x, ball.x); var ty:Number = linearTransform(radius, 0, contactDistance, y, ball.y); contact(tx, ty, 2, 0.2); ball.contact(tx, ty, 2, 0.2); } } public function render():void { matrix.identity(); if (priority > 0) { var angle:Number = Math.atan2(cy, cx); var length:Number = Math.sqrt(cx * cx + cy * cy); //matrix.scale(length / radius, 1 + (1 - length / radius)); // 縦方向は適当 //matrix.rotate(angle); } matrix.translate(x, y); body.transform.matrix = matrix; var height:Number = FLOOR_Y - (y + radius); shadow.x = x; shadow.y = FLOOR_Y + height * 0.3; shadow.alpha = linearTransform(height, 0, 300, 0.3, 0); var scale:Number = 1.2 + height * 0.005; shadow.width = body.width * scale ; shadow.height = body.height * scale * 0.2; var blur:Number = linearTransform(height, 0, 200, 3, 25); shadowFilter.blurX = blur; shadowFilter.blurY = blur / 3; shadow.filters = [ shadowFilter ]; } } var balls:Vector.<Ball> = new Vector.<Ball>(); function initialize():void { balls.push(new Ball(60, 0x00ff00)); balls.push(new Ball(45, 0x0000FF)); balls.push(new Ball(30, 0xff0000)); balls.push(new Ball(60, 0x00ff00)); balls.push(new Ball(45, 0x0000FF)); balls.push(new Ball(30, 0xff0000)); var background:Shape = new Shape(); var g:Graphics = background.graphics; var matrix:Matrix = new Matrix(); matrix.createGradientBox(SCREEN_W, SCREEN_H, Math.PI / 2); g.beginGradientFill(GradientType.LINEAR, [0xcccccc, 0xcccccc, 0xcccccc, 0xcccccc, 0xcccccc], null, [0, 150, 168, 170, 255], matrix); g.drawRect(0, 0, SCREEN_W, SCREEN_H); g.endFill(); main.addChild(background); main.addChild(floor); main.addChild(space); main.addEventListener(Event.ENTER_FRAME, enterFrameHandler); } function enterFrameHandler(event:Event):void { for (var i:int = 0; i < 4; i++) { for each (var ball:Ball in balls) { ball.update(); } for (var n:int = 0; n < balls.length; n++) { for (var m:int = n + 1; m < balls.length; m++) { balls[n].hitTest(balls[m]); } } } for each (ball in balls) { ball.render(); } } function random(min:Number, max:Number):Number { return min + Math.random() * (max - min); } function linearTransform(n:Number, s0:Number, s1:Number, d0:Number, d1:Number):Number { return (d0 + (n - s0) * (d1 - d0) / (s1 - s0)); } Code Fullscreen Preview Fullscreen sonson ty tx angle Shape background push scale drawRect Math.min beginGradientFill color hitTest endFill Math.atan2 Matrix blurY blurX Math.max createGradientBox Math.sqrt