Beautifl - Flash Gallery

Thumbnail : [Box2D] Spring Ball
[Box2D] Spring Ball
paq 2010-12-24 see code comments

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

package
{
    import Box2D.Common.b2Color;
    import Box2D.Common.Math.b2Math;
    import Box2D.Common.Math.b2Vec2;
    import Box2D.Dynamics.b2Body;
    import com.actionsnippet.qbox.objects.CircleObject;
    import com.actionsnippet.qbox.QuickBox2D;
    import com.actionsnippet.qbox.QuickObject;
    import com.bit101.components.PushButton;
    import flash.display.Graphics;
    import flash.display.MovieClip;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import net.hires.debug.Stats;
    
    /**
     * @see http://personal.boristhebrave.com/project/controller-grab-pack
     * @author paq89
     */
    [SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="60")]
    public class Main extends Sprite
    {
        // view
        private var _canvas:MovieClip;
        private var _shape:Shape;
        
        private var _qbox:QuickBox2D;
        private var _balls:Vector.<SpringBall>;
        
        public function Main():void
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            
            // background
            var g:Graphics = graphics;
            g.beginFill(0xFFFFFF, 1);
            g.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            
            _balls = new Vector.<SpringBall>();
            
            // canvas
            _canvas = new MovieClip();
            addChild(_canvas);
            
            // segment
            _shape = new Shape();
            addChild(_shape);
            
            // quickbox2d
            _qbox = new QuickBox2D(_canvas);
            _qbox.mouseDrag();
            _qbox.start();
            _qbox.createStageWalls({lineAlpha: 0});
            
            // create ball
            _balls.push(new SpringBall(_qbox, _shape, 4, 4, 2));
            _balls.push(new SpringBall(_qbox, _shape, 11, 4, 2));
            
            // ui
            new PushButton(this, stage.stageWidth - 100, 0, "HIDE", function():void {
                _shape.visible = !_shape.visible;
                var ball_len:int = _balls.length;
                for (var i:int = 0; i < ball_len; i++)
                {
                    _balls[i].centerCircle.userData.visible = _shape.visible;
                    
                    var circle_len:int = _balls[i].circles.length;
                    for (var k:int = 0; k < circle_len; k++ )
                    {
                        var c:CircleObject = _balls[i].circles[k];
                        c.userData.visible = _shape.visible;
                    }
                }
            });
            
            // debug
            addChild(new Stats());
            
            // main loop
            addEventListener(Event.ENTER_FRAME, loop);
        }
            
        private function loop(e:Event):void
        {
            var len:int = _balls.length;
            _shape.graphics.clear();
            for (var i:int = 0; i < len; i++)
            {
                _balls[i].update();
            }
        }
    }
}

// ---------------------------------------------------------------------------------

import com.actionsnippet.qbox.objects.CircleObject;
import com.actionsnippet.qbox.QuickBox2D;
import com.actionsnippet.qbox.QuickObject;
import flash.display.DisplayObject;
import flash.display.Graphics;
import flash.display.Shape;

internal class SpringDraw extends Shape
{
    public function SpringDraw():void
    {
        super();
    }
    
    public function clear():void
    {
        this.graphics.clear();
    }
    

}

internal class SpringBall extends Object
{
    public var qbox:QuickBox2D;
    public var canvas:Shape;
    public var x:Number;
    public var y:Number;
    public var radius:Number;
    
    private var _centerCircle:QuickObject;
    public function get centerCircle():QuickObject { return _centerCircle; }
    
    private var _springs:Vector.<b2SpringController>;
    public function get springs():Vector.<b2SpringController> { return _springs; }
    
    private var _circles:Vector.<CircleObject>;
    
    public function get circles():Vector.<CircleObject> { return _circles; }
    
    public function SpringBall(qbox:QuickBox2D, canvas:Shape, x:Number = 0, y:Number = 0, radius:Number = 2):void
    {
        _circles = new Vector.<CircleObject>();
        _springs = new Vector.<b2SpringController>();
        
        this.qbox = qbox;
        this.canvas = canvas;
        this.x = x;
        this.y = y;
        this.radius = radius;
        
        create();
    }
    
    public function update():void
    {
        var len:int = _springs.length;
        for (var i:int = 0; i < len; i++)
        {
            _springs[i].Step(qbox.timeStep);
            draw(springs[i]);
        }
    }
    
    private function create():void
    {
        _centerCircle = qbox.addCircle( { x:x, y:y } );
        var len:int = 18;
        for (var i:int = 0; i < len; i++)
        {
            var circle:QuickObject = qbox.addCircle( { x:Math.sin(i * (360 / len) * Math.PI / 180) * radius + x,
                                                        y:Math.cos(i * (360 / len) * Math.PI / 180) * radius + y,
                                                        radius:0.1} );
            circle.shape.m_radius = 0.3;
            var spring:b2SpringController = new b2SpringController();
            spring.SetBody1(_centerCircle.body);
            spring.SetBody2(circle.body);

            spring.length = radius;
            spring.damping = 0;
            spring.k = 100;

            _springs.push(spring);
            _circles.push(circle);
            
            if (i != 0) qbox.addJoint( { type:QuickBox2D.DISTANCE, a:_circles[i-1].body, b:circle.body } );
        }
        
        qbox.addJoint( { type:QuickBox2D.DISTANCE,a:_circles[0].body, b:_circles[len-1].body } );
        
        //for (i = 0; i < len; i++)
        //{
            //circle = qbox.addCircle( { x:Math.sin(i * (360 / len) * Math.PI / 180) * (radius-0.8) + x,
                                        //y:Math.cos(i * (360 / len) * Math.PI / 180) * (radius-0.8) + y,
                                        //radius:0.1 } );
            //_circles.push(circle);
            //
            //qbox.addJoint( { type:QuickBox2D.DISTANCE, a:center.body, b:circle.body } );
            //if (i != 0) qbox.addJoint( { type:QuickBox2D.DISTANCE, a:_circles[len+i-1].body, b:circle.body } );
        //}
        //
        //qbox.addJoint( { type:QuickBox2D.DISTANCE,a:_circles[len].body, b:_circles[_circles.length-1].body } );
    }
    
    public function draw(spring:b2SpringController):void
    {
        //Number of bends the spring makes
        var kinks:Number = 10;
        //Stub at either end that is unkinked
        var stub:Number = 0.05;
        //Kink width, as fraction of length
        var kinkWidth:Number = 0.05;
        //Set kink width s.t. kinks are at right angles at natural length
        kinkWidth = (1-2*stub)/kinks/2;
        //Color of spring
        var color:Number = 0x333333;

        var world1:b2Vec2 = spring.m_body1.GetWorldPoint(spring.m_anchor1);
        var world2:b2Vec2 = spring.m_body2.GetWorldPoint(spring.m_anchor2);

        var d:b2Vec2 = b2Math.SubtractVV(world2, world1);
        var dlen:Number = d.Normalize();
        var nX:Number = d.y * kinkWidth * spring.length * 4;
        var nY:Number = -d.x * kinkWidth * spring.length * 4;
        var p2:b2Vec2 = new b2Vec2(world1.x * (1 - stub) + world2.x * stub, world1.y * (1 - stub) + world2.y * stub);
        drawSegment(world1,p2,color);
        var prevp:b2Vec2 = p2;
        for (var i:int = 0; i <= kinks; i++)
        {
            var alt:Number = i % 2 == 0 ? -1:1;
            var pi:b2Vec2 = new b2Vec2(
                            world1.x + d.x * dlen * (stub + (1 - 2 * stub) * i / kinks) + nX * alt,
                            world1.y + d.y * dlen * (stub + (1 - 2 * stub) * i / kinks) + nY * alt
                        );
            drawSegment(prevp, pi, color);
            prevp = pi;
        }
        pi = new b2Vec2(world2.x * (1 - stub) + world1.x * stub, world2.y * (1 - stub) + world1.y * stub);
        drawSegment(prevp,pi,color);
        drawSegment(pi,world2,color);
    }
    
    private function drawSegment(p1:b2Vec2, p2:b2Vec2, color:Number):void
    {
        var g:Graphics = canvas.graphics;
        g.lineStyle(1, color, 1);
        g.moveTo(p1.x * 30, p1.y * 30);
        g.lineTo(p2.x * 30, p2.y * 30);
    }
}

// ---------------------------------------------------------------------------------

/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

import Box2D.Dynamics.*;
import Box2D.Common.Math.*;
import Box2D.Common.*;

/// Base class for controllers. Controllers are a convience for encapsulating common
/// per-step functionality
internal class b2Controller
{
    public var m_next:b2Controller;
    public var m_prev:b2Controller;
        
    public function GetNext():b2Controller{return m_next;}
    public function GetPrev():b2Controller{return m_prev;}
    
    public virtual function Step(timestep:Number):void {}
        
    public virtual function Draw(debugDraw:b2DebugDraw):void {}
}

/// Base class for controllers. Controllers are a convience for encapsulating common
/// per-step functionality
internal class b2PairController extends b2Controller
{
    public var m_body1:b2Body;
    public var m_body2:b2Body;
    
    /// Get the anchor point on body1 in world coordinates.
    public virtual function GetAnchor1():b2Vec2{return null};
    /// Get the anchor point on body1 in world coordinates.
    public virtual function SetAnchor1(v:b2Vec2):void{};
    /// Get the anchor point on body2 in world coordinates.
    public virtual function GetAnchor2():b2Vec2{return null};
    /// Set the anchor point on body1 in world coordinates.
    public virtual function SetAnchor2(v:b2Vec2):void{};
    
    
    /// Get the first body attached to this joint.
    public function GetBody1():b2Body
    {
        return m_body1;
    }
    
    /// Get the first body attached to this joint.
    public function SetBody1(b:b2Body):void
    {
        m_body1 = b;
    }
    
    /// Get the second body attached to this joint.
    public function GetBody2():b2Body
    {
        return m_body2;
    }
    /// Get the second body attached to this joint.
    public function SetBody2(b:b2Body):void
    {
        m_body2 = b;
    }
}

/// Applies Hooke forces between a pair of bodies
internal class b2SpringController extends b2PairController
{
    /// Spring constant
    public var k:Number = 1;
    /// Damping constant
    public var damping:Number = 0;
    /// Natural length of spring
    public var length:Number = 0;
        
    public var m_anchor1:b2Vec2 = new b2Vec2();
    public var m_anchor2:b2Vec2 = new b2Vec2();
    
    /// Get the anchor point on body1 in world coordinates.
    public override function GetAnchor1():b2Vec2{
        return m_body1.GetWorldPoint(m_anchor1);
    }
    /// Get the anchor point on body1 in world coordinates.
    public override function SetAnchor1(v:b2Vec2):void{
        m_anchor1.SetV(m_body1.GetLocalPoint(v));
    }
    /// Get the anchor point on body2 in world coordinates.
    public override function GetAnchor2():b2Vec2{
        return m_body2.GetWorldPoint(m_anchor2);
    }
    /// Set the anchor point on body1 in world coordinates.
    public override function SetAnchor2(v:b2Vec2):void{
        m_anchor2.SetV(m_body2.GetLocalPoint(v));
    }
    
    public override function Step(timestep:Number):void{
        //Skip if asleep
        if(m_body1.IsSleeping() && m_body2.IsSleeping())
            return;
        
        var world1:b2Vec2 = m_body1.GetWorldPoint(m_anchor1);
        var world2:b2Vec2 = m_body2.GetWorldPoint(m_anchor2);
        
        var d:b2Vec2 = b2Math.SubtractVV(world2,world1);
        var dlen:Number = d.Normalize();
        
        //Spring force
        var springForce:b2Vec2 = d.Copy();
        springForce.Multiply( (dlen - length) * k );
        m_body1.ApplyForce(springForce, world1);
        m_body2.ApplyForce(springForce.Negative(), world2);
        
        //Damping
        if(damping!=0){
            var v1:b2Vec2 = m_body1.GetLinearVelocityFromWorldPoint(world1);
            var v2:b2Vec2 = m_body2.GetLinearVelocityFromWorldPoint(world2);
            var v:b2Vec2 = b2Math.SubtractVV(v2,v1);
            var dampingForce:b2Vec2 = d.Copy();
            dampingForce.Multiply(b2Math.b2Dot(v,d) * damping);
            m_body1.ApplyForce(dampingForce, world1);
            m_body2.ApplyForce(dampingForce.Negative(), world2);
        }
        
    }
    
    /// Draws a spring in a typical zig-zagging fashion
    public override function Draw(debugDraw:b2DebugDraw):void
    {
        //Number of bends the spring makes
        var kinks:Number = 10;
        //Stub at either end that is unkinked
        var stub:Number = 0.05;
        //Kink width, as fraction of length
        var kinkWidth:Number = 0.05;
        //Set kink width s.t. kinks are at right angles at natural length
        kinkWidth = (1-2*stub)/kinks/2;
        //Color of spring
        var color:b2Color = new b2Color(0xB8/255,0x86/255,0x0B/255);
        
        var world1:b2Vec2 = m_body1.GetWorldPoint(m_anchor1);
        var world2:b2Vec2 = m_body2.GetWorldPoint(m_anchor2);
        
        var d:b2Vec2 = b2Math.SubtractVV(world2,world1);
        var dlen:Number = d.Normalize();
        var nX:Number=d.y*kinkWidth*length;
        var nY:Number=-d.x*kinkWidth*length;
        var p2:b2Vec2 = new b2Vec2(world1.x*(1-stub)+world2.x*stub,world1.y*(1-stub)+world2.y*stub);
        debugDraw.DrawSegment(world1,p2,color);
        var prevp:b2Vec2=p2;
        for(var i:int=0;i<=kinks;i++){
            var alt:Number = i%2==0?-1:1;
            var pi:b2Vec2 = new b2Vec2(
                            world1.x+d.x*dlen*(stub+(1-2*stub)*i/kinks)+nX*alt,
                            world1.y+d.y*dlen*(stub+(1-2*stub)*i/kinks)+nY*alt
                        );
            debugDraw.DrawSegment(prevp,pi,color);
            prevp=pi;
        }
        pi = new b2Vec2(world2.x*(1-stub)+world1.x*stub,world2.y*(1-stub)+world1.y*stub);
        debugDraw.DrawSegment(prevp,pi,color);
        debugDraw.DrawSegment(pi,world2,color);
        
        
    }
}