In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

collision test

Get Adobe Flash player
by arumajirou 18 Feb 2010
    Embed
/**
 * Copyright arumajirou ( http://wonderfl.net/user/arumajirou )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/ww6G
 */

package {
	import flash.accessibility.Accessibility;
    import flash.display.Sprite;
    import flash.geom.*;
    import flash.events.*;
    import flash.text.*;
    public class FlashTest extends Sprite {
    		public static var tex : TextField;
	    	private var ref : cReferencePosition;
	    	private var task : cCharacterTask;
	    	public static var running : Boolean = true;
	    	public static var marker : Sprite;
	    	
        public function FlashTest() {
            // write as3 code here..
            tex = new TextField();
            var tf : TextFormat = new TextFormat();
            tf.color = 0x01;
            tex.defaultTextFormat = tf;
            tex.autoSize = TextFieldAutoSize.LEFT;
            addChild( tex );
            tex.text = "collision\n";
            
            ref = new cReferencePosition( new Rectangle( 0, 0, stage.stageWidth, stage.stageHeight ) );
            task = new cCharacterTask();
            var ba : ball;
            for( var l : int = 0 ; l < 5 ; l++ )
            {
	            ba = new ball( parent, new Rectangle( 0, 0, stage.stageWidth, stage.stageHeight ) );
	            task.addTask( ba , 0 );
	            ba.addEventListener( "EVENT_COLLISION", this.addCollision );
	        }
            parent.addEventListener( Event.ENTER_FRAME, polling );
//            parent.addEventListener( MouseEvent.MOUSE_UP, mouseUp );
//            parent.addEventListener( MouseEvent.MOUSE_MOVE, mouseMove );
            
            task.addLineCollision( new cLineCollision( new Vector3D( 0, stage.stageHeight, 0, 1 ), new  Vector3D( stage.stageWidth, stage.stageHeight, 0, 1 )  ) );
            task.addLineCollision( new cLineCollision( new Vector3D( stage.stageWidth, 0, 0, 1 ), new  Vector3D( stage.stageWidth, stage.stageHeight, 0, 1 )  ) );
            task.addLineCollision( new cLineCollision( new Vector3D( 0, stage.stageHeight, 0, 1 ), new  Vector3D( 0, 0, 0, 1 )  ) );
            task.addLineCollision( new cLineCollision( new Vector3D( stage.stageWidth, 0, 0, 1 ), new  Vector3D( 0, 0, 0, 1 )  ) );
            
            marker = new Sprite();
            parent.addChild( marker );
        }
        
        public function addCollision( e : Event ) : void
        {
        		task.addCollision( cCollisionEvent(e).colli );
        }
        
        public function mouseUp( e : MouseEvent ) : void
        {
//        		if( running == true ) running = false;
        		if( running == false ) running = true;
        }
        public function mouseMove( e : MouseEvent ) : void
        {
        		if( running == false )
        		{
        			run();
        		}
        }
        public function run() : void
        {
        		marker.graphics.clear();
        		tex.text = "";
        		task.poll( ref );
        }
        public function polling( e : Event ) : void
        {
        		if( running == true )
        		{
        			run();
        		}
        }
    }
}

import flash.events.*;
import flash.geom.*;
import flash.display.*;
class cSubject{	private var observers : Vector.<iObserver>;	public function cSubject()	{	 	observers = new Vector.<iObserver>();	}	public function attach( o : iObserver ) : void	{	 	observers.push( o );	}	public function detach( o : iObserver ) : void	{	 	var result : int = observers.indexOf( o );	 	if( result == -1 ) return;	 	observers.splice( result, 1 );	}	public function notify( o : Object ) : void	{	 	var len : int = observers.length;	 		 	for( var i : int = 0 ; i < len ; i++ )	 	{	 	 	observers[ i ].update( o );	 	}	}}interface iObserver{	function update( o : Object ) : void;}
class cCollisionEvent extends Event
{
	public var colli : iCollision;
	public function cCollisionEvent( t : iCollision = null )
	{
		super( "EVENT_COLLISION" );
		colli = t;
        	
	}
}

class cReferencePosition
{
    private var displayArea : Rectangle;
    private var position : Vector3D;
    
    public function cReferencePosition( a : Rectangle = null )
    {
        displayArea = a;
        update( new Vector3D( 0,0,0,1 ) );
    }
    public function setter( v : Vector3D ) : void
    {
        position = v.clone();
    }
    public function getter() : Vector3D
    {
        return position.clone();
    }
    
    public function update( vec : Vector3D ) : Vector3D
    {
//        return ( position = ( new Vector3D( displayArea.width / 2, displayArea.height / 2, 0, 1 ) ).subtract( vec ) );
        return ( position = ( new Vector3D( 0, 0, 0, 1 ) ).subtract( vec ) );
    }
}

class cCharacterTask
{
    static public const MAX_DEPTH : int = 3;
    private var list : Vector.<Vector.<iCharacter>>;
    private var removes : Vector.<iCharacter>;
    private var collisions : Vector.<iCollision>;
    private var line : Vector.<iCollision>;
    
    
    public function cCharacterTask()
    {
        list = new Vector.<Vector.<iCharacter>>( cCharacterTask.MAX_DEPTH );
        removes = new Vector.<iCharacter>();
        collisions = new Vector.<iCollision>();
        line = new Vector.<iCollision>();
        for( var i : int = 0 ; i < cCharacterTask.MAX_DEPTH ; i++ )
        {
            list[i] = ( new Vector.<iCharacter>() );
        }
    }
    public function addTask( t : iCharacter, depth : int ) : void
    {
        list[ depth ].push( t );
    }
    public function removeTask( t : iCharacter ) : void
    {
        removes.push( t );
    }
    public function addCollision( t : iCollision ) : void
    {
    		collisions.push( t );
    }
    public function addLineCollision( t : iCollision ) : void
    {
    		line.push( t );
    }
    public function poll( pos : cReferencePosition ) : void
    {
        for( var i : int = 0 ; i < cCharacterTask.MAX_DEPTH ; i++ )
        {
            var len : int = list[ i ].length;
            for( var j : int = 0 ; j < len ; j++ )
            {
                list[ i ][ j ].process();
            }
        }
        for each( var ct : iCollision in line )
        {
        		addCollision( ct );
        }
        len = collisions.length;
        var loops : int = 0;
        for( i = 0 ; i < len ; i++ )
        {
        		for( j = i + 1 ; j < len ; j++ )
        		{
        			if( collisions[ i ].hitTest( collisions[ j ] ) == true )
        			{
        				i = 0;
        				j = 0;
        				loops++;
        				continue;
        			}
        		}
			if( loops > 100 ) break;	// 保険
        }
        var v : Vector3D = pos.getter();
        for( i = 0 ; i < cCharacterTask.MAX_DEPTH ; i++ )
        {
            len = list[ i ].length;
            for( j = 0 ; j < len ; j++ )
            {
                list[ i ][ j ].draw( v );
            }
        }
        for each( var t : iCharacter in removes )
        {
            for( i = 0 ; i < cCharacterTask.MAX_DEPTH ; i++ )
            {
                var num : int = 0;
                if( ( num = list[ i ].indexOf( t ) ) != -1 )
                {
                    list[ i ].splice( num, 1 );
                }
            }
        }
        removes.splice( 0, removes.length );
        collisions.splice( 0, collisions.length );
    }
}

interface iCharacter
{
    function process() : void;
    function draw( v : Vector3D ) : void;
}

class cCharacter extends EventDispatcher implements iCharacter
{
    protected var _stage : DisplayObjectContainer = null;
    protected var _visual : Sprite = null;
    protected var _pos : Vector3D = null;
    protected var _oldPos : Vector3D = null;
    public function cCharacter( d : DisplayObjectContainer = null )
    {
        _stage = d;
        _pos = new Vector3D( 0, 0, 0, 1 );
    }
    public function process() : void
    {
    }
    public function draw( v : Vector3D ) : void
    {
    }
}

class cMovableCharacter extends cCharacter
{
    protected var region : Rectangle = null;
    protected var _moves : Vector3D = null;
    protected var hostility : int = -1;
    protected var life : int = 0;
    
    public function cMovableCharacter( d : DisplayObjectContainer = null, r : Rectangle = null )
    {
        super(d);
        region = r;
        _moves = new Vector3D( 15, 0, 0, 0 );
    }
    public override function process() : void
    {
    		_oldPos = _pos.clone();
        _pos = _pos.add( _moves );
        _pos.x = ( _pos.x - region.left + region.width ) % region.width + region.left;
        _pos.y = ( _pos.y - region.top + region.height ) % region.height + region.top;
    }
    public override function draw( v : Vector3D ) : void
    {
        _visual.x = ( _pos.x + v.x + region.width ) % region.width;
        _visual.y = ( _pos.y + v.y + region.height ) % region.height;
    }
}

class ball extends cMovableCharacter implements iObserver
{
	private var colli : cMovingCircleCollision;
	private var onDrag : Boolean;
	private var dragPos : Vector3D;
	private var radius : Number;
	
	public function ball( d : DisplayObjectContainer = null, r : Rectangle = null )
	{
		super( d, r );
		
		_visual = new Sprite();
		d.addChild( _visual );
		radius = 15 + Math.random() * 30;
		const g : Graphics = _visual.graphics;
		g.clear();
		g.lineStyle( 1, 0x00ff00 );
		g.beginFill( Math.random() * 0xffffff );
		g.drawCircle( 0, 0, radius );
		g.endFill();
		_visual.addEventListener( MouseEvent.MOUSE_MOVE, this.move );
		_visual.addEventListener( MouseEvent.MOUSE_DOWN, this.mouseDown);
		_visual.addEventListener( MouseEvent.MOUSE_UP, this.mouseUp );
		_visual.addEventListener( Event.ENTER_FRAME, this.enter );
		
		_pos.x = Math.random() * ( r.width - radius * 2 ) + radius;
		_pos.y = Math.random() * ( r.width - radius * 2 ) + radius;
		onDrag = false;
	}
	public override function process() : void
	{
		var p0 : Vector3D = _pos.clone();
		super.process();
		colli = new cMovingCircleCollision( p0, _pos, radius );
		colli.attach( this );
		var vg : Vector3D = new Vector3D( 0, 0.21, 0, 0 );
		if( onDrag == false )
			_moves = _moves.add( vg );
		dispatchEvent( new cCollisionEvent( colli ) );
	}
	public function mouseDown( e : MouseEvent ) : void
	{
		if( onDrag == true ) return;
		onDrag = true;
		_visual.startDrag( true );
		_moves = new Vector3D( 0, 0, 0, 0 );
	}
	public function mouseUp( e : MouseEvent ) : void
	{
		onDrag = false; 
		_visual.stopDrag();
		_moves = _pos.subtract( dragPos );
	}
	public function move( e : MouseEvent ) : void
	{
		if( onDrag == false ) return;
		dragPos = _pos.clone();
		_pos.x = e.stageX;
		_pos.y = e.stageY;
	}
	public function enter( e : Event ) : void
	{
		if( onDrag == false ) return;
		dragPos = _pos.clone();
	}
	public function update( o : Object ) : void
	{
		if( o.collision == true )
		{
			_pos = o.pos;
			_moves = o.reflection;
			_moves.scaleBy( 0.5 );
			colli.process( o.contact, _pos );
//			FlashTest.tex.appendText( "移動量:" +  _moves.toString() + "\n" );
		}
	}
}
class wall extends cCharacter
{
}
class cVectorUtil
{
	static public function procReflection( l : Vector3D, n : Vector3D ) : Vector3D
	{
		var proj : Vector3D = l.clone();
		proj.scaleBy( -1 );
		var nc : Vector3D = n.clone();
		nc.scaleBy( proj.dotProduct( n ) );
		nc = proj.subtract( nc );
		nc.scaleBy( -2 );
		return proj.add( nc );
	}
}
interface iCollision
{
	function hitTest( c : iCollision ) : Boolean;
}

class cLineCollision extends cSubject implements iCollision
{
	private var p0 : Vector3D;
	private var p1 : Vector3D;
	private var normal : Vector3D;
	private var d : Number;
	
	public function cLineCollision( a : Vector3D = null, b : Vector3D = null )
	{
		p0 = a;
		p1 = b;
		var n : Vector3D = a.subtract( b );
		n.normalize();
		normal = new Vector3D( n.y, n.x, 0, 0 );
		d = -( normal.dotProduct( p0 ) );
//		FlashTest.tex.appendText( "" + normal.toString() + "\n" );
	}
	public function hitTest( c : iCollision ) : Boolean
	{
		return false;
	}
	public function getNormal() : Vector3D
	{
		return normal.clone();
	}
	public function getD() : Number
	{
		return d;
	}
}

class cMovingCircleCollision extends cSubject implements iCollision
{
	private var p : Vector3D;
	private var r : Number;
	private var v : Vector3D;
	
	public function cMovingCircleCollision( p1 : Vector3D = null, p2 : Vector3D = null, rad : Number = 0 )
	{
		r = rad;
		process( p1, p2 );
		const g : Graphics = FlashTest.marker.graphics;
		g.lineStyle( 1, 0xff0000 );
		g.moveTo( p.x, p.y );
		g.lineTo( p.x + v.x, p.y + v.y );
	}
	public function process( p1 : Vector3D, p2 : Vector3D ) : void
	{
		p = p1;
		v = p2.subtract( p1 );
	}
	public function getPos() : Vector3D
	{
		return p;
	}
	public function getMoves() : Vector3D
	{
		return v;
	}
	public function getRadius() : Number
	{
		return r;
	}
	public function hitTestWithLine( c : iCollision ) : Boolean
	{
		const l : cLineCollision = cLineCollision(c);
		const n : Vector3D = l.getNormal();
		const m : Number = v.dotProduct( n );
		if( m >= 0 ) return false;
		const t : Number = -( (n.dotProduct(p)+l.getD()-r) / m );
		if( ( t < 0 ) || ( t > 1 ) ) return false;
		// 接触時の中心座標を算出
		var c0 : Vector3D = v.clone();
		c0.scaleBy( t );
		c0 = c0.add( p );
		// 未処理の運動量を算出
		var en : Vector3D = v.clone();
		en.scaleBy( 1 - t );
		en = cVectorUtil.procReflection( en, n );
		notify( 
		{
			"collision" : true,
			"time" : t,
			"contact" : c0,
			"pos" : c0.add( en ),
			"normal" : n,
			"reflection" : cVectorUtil.procReflection( v, n )
		} );
		return true
	}
	public function hitTestWithMovingCircle( c : iCollision ) : Boolean
	{
		const tc : cMovingCircleCollision = cMovingCircleCollision( c );
		
		const Pq : Vector3D = tc.getPos();
		const Vq : Vector3D = tc.getMoves();
		var A : Vector3D = p.subtract( Pq );
		var B : Vector3D = v.subtract( Vq );
		var AB : Number = A.dotProduct( B );
		var BB : Number = B.dotProduct( B );
		if( BB == 0 ) return false;
		var t : Number = - ( AB / BB );
		if( t < 0 ) t = 0;
		if( t > 1 ) t = 1;
		var d : Number = A.dotProduct( A ) + ( 2 * t * AB ) + t * t *BB;
		var range : Number = r + tc.getRadius();

		if( d > (range*range) ) return false;
		// 判定終了
//FlashTest.running = false;
		// 使わないけど正確な接触時間tを再計算
		t = ( AB * AB ) - ( BB * ( A.dotProduct( A ) - ( range * range ) ) );
		t = Math.sqrt( t );
		t = -AB - t;
		t = t / BB;
		if( ( t < 0 ) || ( t > 1 ) ) return false;
		
		var tv : Vector3D = v.clone();
		tv.scaleBy( t );
		var pt : Vector3D = p.add( tv );
		var tVq : Vector3D = Vq.clone();
		tVq.scaleBy( t );
		var qt : Vector3D = Pq.add( tVq );
		var n : Vector3D = qt.subtract( pt );
		n.normalize();
		var nn : Vector3D = n.clone();
		nn.scaleBy( -1 );
		var c0 : Vector3D = n.clone();
		c0.scaleBy( r );
		c0 = pt.add( c0 );

		// エネルギーを適当に相殺
		var en : Number = tv.dotProduct( tv ) + tVq.dotProduct( tVq );
		en = Math.sqrt( en ) / 2;
		tv.normalize();tv.scaleBy( en );
		tVq.normalize();tVq.scaleBy( en );
		
		// 未処理のエネルギーを算出(てきとー)
		var eTv : Vector3D = v.clone();
		eTv.scaleBy( 1 - t );
		var enn : Number = en - Math.sqrt( eTv.dotProduct( eTv ) );
		if( enn < 0 ) enn = 0;
		eTv.normalize();
		eTv.scaleBy( enn );
		eTv = cVectorUtil.procReflection( eTv, nn );
		var eTvq : Vector3D = eTv.clone();
		eTvq.scaleBy( -1 );
		
		var ref : Vector3D = eTv.clone();
		ref = ref.add( c0 );
		
		const g : Graphics = FlashTest.marker.graphics;
		g.lineStyle( 1, 0x0000ff );
		g.moveTo( c0.x, c0.y );
		g.lineTo( ref.x, ref.y );
		
		notify( 
		{
			"collision" : true,
			"time" : t,
			"contact" : pt,
			"pos" : pt.add( eTv ),
			"normal" : nn,
			"reflection" : cVectorUtil.procReflection( v, nn )
		} );
		tc.notify( 
		{
			"collision" : true,
			"time" : t,
			"contact" : qt,
			"pos" : qt.add( eTvq ),
			"normal" : n,
			"reflection" : cVectorUtil.procReflection( tVq, n )
		} );
				
		return true;
	}	
	public function hitTest( c : iCollision ) : Boolean
	{
		if( c is cMovingCircleCollision ) return hitTestWithMovingCircle( c );
		if( c is cLineCollision ) return hitTestWithLine( c );
		return false;
	}
}