PDA

Просмотр полной версии : [Box2D] Можно ли сделать просчет пересечения точнее?


Fintch
09.03.2012, 14:29
Здравствуйте!

Я написал небольшое демо на box2D и меня беспокоит, что иногда можно уловчиться и перетащить один физический объект в другой. Причем сделать это довольно просто.

Можно ли сделать просчет пересечений точнее? В идеале, чтобы любое тело не могло пересекаться с другими.

Ссылка (http://artfintch.kodingen.com/box2d/) на на демо.

Код

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;

}

}

}

Помогите кто чем может)
Сам не могу разобраться(

Fintch
09.03.2012, 18:27
to Ohcysp Regit

Ну что я могу сказать код ты зря приложил.
Почему?

А вообще не совсем я понимаю о чем ты говоришь, если о том что тело проскакивает одно через другое.
То маус очень большой форс задает телу из за чего одно и проскакивает через другое.
Попробуй с реальной моделью управления объектами, без мауса этого и такой ситуации в принципе не будет возникать.
Как минимум у меня таких проблем не возникает
Мне необходимо перетаскивать объекты мышью. Да, сила действительно большая, но иначе объект начинает болтаться.

Ну а более конкретно посмотри в сторону ConcatListener'a утверждать не буду но возможно в пресолв приходит событие даже если объекты проскакивают( ну и не только пресолв ). И ты можешь дополнительно "не дать объектам" проходить друг через друга
Попробую разобраться конечно. Но хотелось бы получить более подробный ответ.

Спасибо.