public class Game1 : Microsoft.Xna.Framework.Game
{
readonly GraphicsDeviceManager graphics;
SpriteBatch _spriteBatch;
private const float scale = .01f;
private Texture2D _boxTexture;
private World _physicsWorld;
/**
* Keeps track of the positions of all our boxes
*/
private List<Body> _boxBodies;
private Body _groundBody;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
// Frame rate is 30 fps by default for Windows Phone.
TargetElapsedTime = TimeSpan.FromTicks(333333);
// Pre-autoscale settings.
graphics.PreferredBackBufferWidth = 480;
graphics.PreferredBackBufferHeight = 800;
graphics.IsFullScreen = true;
}
protected override void Initialize()
{
_physicsWorld = new World(new Vector2(0, 10), true);
_boxBodies = new List<Body>();
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
_spriteBatch = new SpriteBatch(GraphicsDevice);
_boxTexture = Content.Load<Texture2D>("box64x64");
CreateGroundAndWalls();
CreateBoxStacks();
}
private static readonly Random Random = new Random();
/**
* Create the Boxes, Random Location
*/
private void CreateBoxStacks()
{
var bodyDef = new BodyDef {type = BodyType.Dynamic};
var bodyShape = new PolygonShape();
bodyShape.SetAsBox(32*scale, 32*scale);<h4></h4>//box is 64,64. Half is 32,32 and scale it to box2d
var bodyFixture = new FixtureDef {shape = bodyShape, restitution = 0.4f, density = 1.5f};
for(var i=0;i<6;i++)
{
var body = _physicsWorld.CreateBody(bodyDef);
body.CreateFixture(bodyFixture);
body.Position = new Vector2((float)Random.NextDouble()*4.0f + .32f, (float)Random.NextDouble()+.20f);
_boxBodies.Add(body);
}
}
/*
* Creates the boundries for us notice the scale used is still 1/100
*/
private void CreateGroundAndWalls()
{
var grounDef = new BodyDef { type = BodyType.Static };
var groundFix = new FixtureDef { restitution = 0.0f, density = 0.0f };
var groundShape = new PolygonShape();
groundShape.SetAsEdge(new Vector2(0, 8f), new Vector2(4.8f, 8f));
_groundBody = _physicsWorld.CreateBody(grounDef);
groundFix.shape = groundShape;
_groundBody.CreateFixture(groundFix);
groundShape.SetAsEdge(new Vector2(0, 0), new Vector2(0f, 8.0f));
var leftBody = _physicsWorld.CreateBody(grounDef);
groundFix.shape = groundShape;
leftBody.CreateFixture(groundFix);
groundShape.SetAsEdge(new Vector2(4.8f, 0), new Vector2(4.8f, 8.0f));
var rightBody = _physicsWorld.CreateBody(grounDef);
groundFix.shape = groundShape;
rightBody.CreateFixture(groundFix);
groundShape.SetAsEdge(new Vector2(0, 0), new Vector2(4.8f, 0));
var topBody = _physicsWorld.CreateBody(grounDef);
groundFix.shape = groundShape;
topBody.CreateFixture(groundFix);
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
_physicsWorld.Step(1/60f, 10, 10);
HandleMouseClicks();
base.Update(gameTime);
}
private MouseState _prevState;
private MouseJoint _joint;
Body _choosenBoxBody = null;
private void HandleMouseClicks()
{
var state = Mouse.GetState();
//this makes sure that the user hasn't let go of the mouse and is still holding it down
if(state.LeftButton==ButtonState.Pressed && _prevState.LeftButton==ButtonState.Pressed)
{
var mousePosition = new Vector2(state.X*scale, state.Y*scale);
FindAndMoveBoxes(mousePosition);
}
//when we know the mouse button has been released, we need to null and destroy the joints
if(state.LeftButton==ButtonState.Released && _prevState.LeftButton==ButtonState.Released)
{
DestroyJoints();
}
_prevState = state;
}
private void DestroyJoints()
{
if (_joint == null) return;
_physicsWorld.DestroyJoint(_joint);
_joint = null; //very important to null it, other wise if a user clicks on empty space, then lets go. The joint wont be null,
//then when box2d trys to destroy the same joint over again it will throw an exception since the joint had been destroyed previously
_choosenBoxBody = null;
}
private void FindAndMoveBoxes(Vector2 position)
{
if (_choosenBoxBody == null)
{
//create a little box
var aabb = new AABB
{
upperBound = new Vector2(position.X + .001f, position.Y + .001f),
lowerBound = new Vector2(position.X - .001f, position.Y - .001f)
};
_physicsWorld.QueryAABB(found =>
{
if (found.GetBody().GetType() == BodyType.Dynamic)
{
if (found.TestPoint(position))
{
_choosenBoxBody = found.GetBody();
return true;
}
}
return false;
}
, ref aabb);
}
if (_choosenBoxBody == null) return;
if (_joint == null)
{
var mouseJointDef = new MouseJointDef
{
collideConnected = true,
bodyA = _groundBody,
bodyB = _choosenBoxBody,
target = position,
maxForce = 10000*_choosenBoxBody.GetMass()
};
_joint = (MouseJoint)_physicsWorld.CreateJoint(mouseJointDef);
}
else
{
_joint.SetTarget(position);
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
_spriteBatch.Begin();
foreach (var boxBody in _boxBodies)
{
_spriteBatch.Draw(_boxTexture, boxBody.Position/scale, null, Color.White, boxBody.Rotation,
new Vector2(32, 32), 1, SpriteEffects.None, 0);
}
_spriteBatch.End();
base.Draw(gameTime);
}
}