и меня беспокоит, что иногда можно уловчиться и перетащить один физический объект в другой. Причем сделать это довольно просто.
Можно ли сделать просчет пересечений точнее? В идеале, чтобы любое тело не могло пересекаться с другими.
Код AS3:
package {
//-----------------------------------
import Box2D.Collision.b2AABB;
import Box2D.Collision.Shapes.b2MassData;
import Box2D.Collision.Shapes.b2PolygonShape;
import Box2D.Collision.Shapes.b2Shape;
import Box2D.Common.Math.b2Vec2;
import Box2D.Dynamics.b2Body;
import Box2D.Dynamics.b2BodyDef;
import Box2D.Dynamics.b2DebugDraw;
import Box2D.Dynamics.b2Fixture;
import Box2D.Dynamics.b2FixtureDef;
import Box2D.Dynamics.b2World;
import Box2D.Dynamics.Joints.b2MouseJoint;
import Box2D.Dynamics.Joints.b2MouseJointDef;
import flash.display.Sprite;
import flash.events.Event;
import General.Input;
//-----------------------------------
/**
* @langversion ActionScript 3
* @playerversion Flash 11.1.0
* @timecreation 07.03.2012 10:55
* ...
* @author artFintch
*/
public class App extends Sprite {
private const PHYS_SCALE:Number = 30;
private const TIME_STEP:Number = 1.0 / 30.0;
private const _mVelocityIterations:int = 10;
private const _mPositionIterations:int = 10;
private var _mInput:Input;
private var _mSprite:Sprite;
private var _mWorld:b2World;
private var _mouseXWorldPhys:Number;
private var _mouseYWorldPhys:Number;
private var _mouseXWorld:Number;
private var _mouseYWorld:Number;
private var _mMouseJoint:b2MouseJoint;
private var _mousePVec:b2Vec2 = new b2Vec2();
public function App() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
initWorld();
//////
addSomebody(10, 10, 50, 50);
addSomebody(20, 40, 200, 200);
addSomebody(60, 60, 400, 400);
//////
addEventListener(Event.ENTER_FRAME, updatePhysics, false, 0, true);
}
private function addSomebody(w:Number, h:Number, x:Number, y:Number):void {
var fixtureDef:b2FixtureDef = new b2FixtureDef();
var bodyShape:b2PolygonShape = new b2PolygonShape();
var bodyDef:b2BodyDef = new b2BodyDef();
var body:b2Body;
bodyDef.type = b2Body.b2_staticBody;
bodyDef.bullet = true;
fixtureDef.density = 0.1;
fixtureDef.friction = 10;
fixtureDef.restitution = 0;
bodyDef.fixedRotation = true;
fixtureDef.shape = bodyShape;
var sWidth:Number = stage.width;
var sHeight:Number = stage.height;
bodyDef.position.Set(x / PHYS_SCALE / 2, y / PHYS_SCALE / 2);
bodyShape.SetAsBox(w / PHYS_SCALE, h / PHYS_SCALE);
body = _mWorld.CreateBody(bodyDef);
body.CreateFixture(fixtureDef);
var massData:b2MassData = new b2MassData();
massData.mass = 0.01;
body.SetMassData(massData);
}
private function initWorld():void {
_mSprite = new Sprite();
addChild(_mSprite);
_mInput = new Input(_mSprite);
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-1000.0, -1000.0);
worldAABB.upperBound.Set(1000.0, 1000.0);
var gravity:b2Vec2 = new b2Vec2(0.0, 0.0);
var doSleep:Boolean = false;
_mWorld = new b2World(gravity, doSleep);
_mWorld.SetWarmStarting(true);
var dbgDraw:b2DebugDraw = new b2DebugDraw();
dbgDraw.SetSprite(_mSprite);
dbgDraw.SetDrawScale(30.0);
dbgDraw.SetFillAlpha(0.3);
dbgDraw.SetLineThickness(1.0);
dbgDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
_mWorld.SetDebugDraw(dbgDraw);
var wall:b2PolygonShape= new b2PolygonShape();
var wallBd:b2BodyDef = new b2BodyDef();
var wallB:b2Body;
var width:Number = stage.stageWidth;
var height:Number = stage.stageHeight;
// Left
wallBd.position.Set( 0 / PHYS_SCALE, height / PHYS_SCALE / 2);
wall.SetAsBox(4 / PHYS_SCALE, height / PHYS_SCALE / 2);
wallB = _mWorld.CreateBody(wallBd);
wallB.CreateFixture2(wall);
// Right
wallBd.position.Set((width) / PHYS_SCALE, height / PHYS_SCALE / 2);
wallB = _mWorld.CreateBody(wallBd);
wallB.CreateFixture2(wall);
// Top
wallBd.position.Set(width / PHYS_SCALE / 2, 0 / PHYS_SCALE);
wall.SetAsBox(width / PHYS_SCALE / 2, 4 / PHYS_SCALE);
wallB = _mWorld.CreateBody(wallBd);
wallB.CreateFixture2(wall);
// Bottom
wallBd.position.Set(width / PHYS_SCALE / 2, (height) / PHYS_SCALE);
wallB = _mWorld.CreateBody(wallBd);
wallB.CreateFixture2(wall);
}
private function updatePhysics(e:Event):void {
_mSprite.graphics.clear();
Input.update();
updateMouseWorld()
mouseDestroy();
mouseDrag();
_mWorld.Step(TIME_STEP, _mVelocityIterations, _mPositionIterations);
_mWorld.ClearForces();
_mWorld.DrawDebugData();
}
public function updateMouseWorld():void {
_mouseXWorldPhys = (Input.mouseX) / PHYS_SCALE;
_mouseYWorldPhys = (Input.mouseY) / PHYS_SCALE;
_mouseXWorld = (Input.mouseX);
_mouseYWorld = (Input.mouseY);
}
public function mouseDrag():void {
// mouse press
if (Input.mouseDown && !_mMouseJoint) {
var body:b2Body = getBodyAtMouse(true);
if (body) {
if (body.GetType() != b2Body.b2_dynamicBody) body.SetType(b2Body.b2_dynamicBody);
var md:b2MouseJointDef = new b2MouseJointDef();
md.bodyA = _mWorld.GetGroundBody();
md.bodyB = body;
md.target.Set(_mouseXWorldPhys, _mouseYWorldPhys);
md.collideConnected = true;
md.maxForce = 10000.0;
_mMouseJoint = _mWorld.CreateJoint(md) as b2MouseJoint;
}
}
// mouse release
if (!Input.mouseDown) {
if (_mMouseJoint) {
_mMouseJoint.GetBodyB().SetLinearVelocity(new b2Vec2(0, 0));
_mMouseJoint.GetBodyB().SetType(b2Body.b2_staticBody)
_mWorld.DestroyJoint(_mMouseJoint);
_mMouseJoint = null;
}
}
// mouse move
if (_mMouseJoint) {
var p2:b2Vec2 = new b2Vec2(_mouseXWorldPhys, _mouseYWorldPhys);
_mMouseJoint.SetTarget(p2);
}
}
public function mouseDestroy():void {
// mouse press
if (!Input.mouseDown && Input.isKeyPressed(68)) {
var body:b2Body = getBodyAtMouse(true);
if (body) {
_mWorld.DestroyBody(body);
return;
}
}
}
public function getBodyAtMouse(includeStatic:Boolean = false):b2Body {
// Make a small box.
_mousePVec.Set(_mouseXWorldPhys, _mouseYWorldPhys);
var aabb:b2AABB = new b2AABB();
aabb.lowerBound.Set(_mouseXWorldPhys - 0.001, _mouseYWorldPhys - 0.001);
aabb.upperBound.Set(_mouseXWorldPhys + 0.001, _mouseYWorldPhys + 0.001);
var body:b2Body = null;
var fixture:b2Fixture;
// Query the world for overlapping shapes.
function getBodyCallback(fixture:b2Fixture):Boolean {
var shape:b2Shape = fixture.GetShape();
if (fixture.GetBody().GetType() != b2Body.b2_staticBody || includeStatic) {
var inside:Boolean = shape.TestPoint(fixture.GetBody().GetTransform(), _mousePVec);
if (inside) {
body = fixture.GetBody();
return false;
}
}
return true;
}
_mWorld.QueryAABB(getBodyCallback, aabb);
return body;
}
}
}