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);
}
}