I've just started implementing bullet into my Ogre project. I follows the install instructions here: http://www.ogre3d.org/tikiwiki/OgreBullet+Tutorial+1
And the rest if the tutorial here:
http://www.ogre3d.org/tikiwiki/OgreBullet+Tutorial+2
I got that to work fine however now I wanted to extend it to a handle a first person camera. I created a CapsuleShape and a Rigid Body (like the tutorial did for the boxes) however when I run the game the capsule falls over and rolls around on the floor, causing the camera swing wildly around.
I need a way to fix the capsule to always stay upright, but I have no idea how
Below is the code I'm using.
(part of) Header File
OgreBulletDynamics::DynamicsWorld *mWorld; // OgreBullet World
OgreBulletCollisions::DebugDrawer *debugDrawer;
std::deque<OgreBulletDynamics::RigidBody *> mBodies;
std::deque<OgreBulletCollisions::CollisionShape *> mShapes;
OgreBulletCollisions::CollisionShape *character;
OgreBulletDynamics::RigidBody *characterBody;
Ogre::SceneNode *charNode;
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
Ogre::RenderWindow* mWindow;
main file
bool MinimalOgre::go(void)
{
...
mCamera = mSceneMgr->createCamera("PlayerCam");
mCamera->setPosition(Vector3(0,0,0));
mCamera->lookAt(Vector3(0,0,300));
mCamera->setNearClipDistance(5);
mCameraMan = new OgreBites::SdkCameraMan(mCamera);
OgreBulletCollisions::CollisionShape *Shape;
Shape = new OgreBulletCollisions::StaticPlaneCollisionShape(Vector3(0,1,0), 0); // (normal vector, distance)
OgreBulletDynamics::RigidBody *defaultPlaneBody = new OgreBulletDynamics::RigidBody(
"BasePlane",
mWorld);
defaultPlaneBody->setStaticShape(Shape, 0.1, 0.8); // (shape, restitution, friction)
// push the created objects to the deques
mShapes.push_back(Shape);
mBodies.push_back(defaultPlaneBody);
character = new OgreBulletCollisions::CapsuleCollisionShape(1.0f, 1.0f, Vector3(0, 1, 0));
charNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
charNode->attachObject(mCamera);
charNode->setPosition(mCamera->getPosition());
characterBody = new OgreBulletDynamics::RigidBody("character", mWorld);
characterBody->setShape( charNode,
character,
0.0f, // dynamic body restitution
10.0f, // dynamic body friction
10.0f, // dynamic bodymass
Vector3(0,0,0),
Quaternion(0, 0, 1, 0));
mShapes.push_back(character);
mBodies.push_back(characterBody);
...
}
You can lock the angular motion of the capsule in order to prevent it from tipping over. Ogre doesn't expose this functionality directly, but you should be able to access the underlying bullet rigid body to accomplish what you need:
characterBody->getBulletRigidBody()->setAngularFactor(btVector3(0.0f,1.0f,0.0f));
This would lock rotation on the xaxis and zaxis, preventing the capsule from tipping over, but allowing rotation around the yaxis, so that the character can still turn.
At some point you may want to looking into using a kinematic character controller, but that's an answer to a different question.
Related
I am using Box2D and SFML to create a simple game. However, my object (ball) does not completely lands after it hits the ground. It seems that 50% of the ball has passed through my border, which looks really awkward. Below are some pictures for illustration.
Ball Before:
Ball After hitting the border at the ground:
As you can see, 50% of the ball has dissapeared (most probably due to offsets or what). Anyone know how to fix it?
Below are my code for the object creation:
circ_ = sf::CircleShape(radius);
circ_.setOrigin(sf::Vector2f(size.x/2,size.y/2));
circ_.setFillColor(sf::Color(255, 255, 255, 255));
circ_.setOutlineThickness(1);
circ_.setOutlineColor(sf::Color::Black);
bodyDef_.position = b2Vec2(position.x/PIXEL_PER_METER, position.y/PIXEL_PER_METER);
bodyDef_.type = b2_staticBody;
bodyFixtureDef_.density = 1.0f;
bodyFixtureDef_.friction = 0.3f;
bodyFixtureDef_.restitution = 0.8f;
Where on my SFML code, I have created the Box2D object using:
Ball basketBall(world, basketBallSize, basketBallPos, 0.0, basketBallRadius, false);
Where radius = 32.
Anybody could help me with this? Thanks.
Box2d uses the center of a circle/polygon shape as position while SFML uses the top left corner of the sprite/shape as position, so you need to take that into account when translating between SFML and Box2d positions. Also keep in mind Box2d uses meters instead of pixles and radians instead of degrees.
Just do like that:
#include <cmath> // for M_PI define
Sprite.setPosition(sf::Vector2f(b2BallBody->GetPosition().x * PIXEL_PER_METER - Sprite.getGlobalBounds().width * 0.5f,
b2BallBody->GetPosition().y * PIXEL_PER_METER - Sprite.getGlobalBounds().height * 0.5f));
Sprite.setRotation(b2BallBody->GetAngle() * (float)(180.0 / M_PI));
Until lately I've been just changing the x coordinate of my sprite on each update and I was happy with it. But yesterday when being in the debugDraw mode, I found out that after certain speed physics body wouldn't align correctly with the sprite ,like this:
Later I got told that, (by Birkemose in cocos2d forum) the preferred way to move a physics body from A to B is to apply impulse to it. But I have no idea how to achieve constant speed this way. This is the code I used to move it without applying any impulse:
-(void)update:(CCTime)delta{
rollingHero.position=ccp(rollingHero.position.x+scrollSpeed*delta,
rollingHero.position.y);
physicsNode.position=ccp(physicsNode.position.x-scrollSpeed*delta,
physicsNode.position.y);
}
So to create a feeling of moving I scroll the physics node and the hero in opposite directions with the same scrolling speed.
I tried lots of different variants of applying impulse, but I never got it moving with constant speed. The speed accelerates and the hero gets offscreen. I would appreciate it very much if someone would post a sample code.
The reason impulse isn't working to keep your character at a constant speed is because impulse translates directly into a change in momentum (and thus a change in velocity). So if you were to try to maintain a constant velocity through impulse, you would have to check your sprite's velocity first, and although you could get pretty close to a constant velocity, it wouldn't be truly constant.
static const float kRollingHeroMoveSpeed = 10.f;
static const float kRollingHeroAccelConstant = 10.f;
-(void)update:(CCTime)delta {
// check velocity of sprite
if(_rollingHero.physicsBody.velocity.x < kRollingHeroMoveSpeed) {
// if velocity is under limit, push character
[_rollingHero.physicsBody applyImpulse:ccp(kRollingHeroAccelConstant, 0)];
}
}
The better way to do this is to step into the C level of the Chipmunk2D physics engine that powers Cocos2D physics.
-(void)onEnter {
[super onEnter];
// tell physics engine to use our C function to update physics body
_rollingHero.physicsBody.body.body->velocity_func = playerUpdateVelocity;
}
static void playerUpdateVelocity(cpBody *body,
cpVect gravity,
cpFloat damping,
cpFloat dt) {
// check validity of cpBody
cpAssertSoft(body->m > 0.0f && body->i > 0.0f, "Body's mass and moment must be positive to simulate. (Mass: %f Moment: %f)", body->m, body->i);
// update velocity and angular velocity
body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));
body->w = body->w*damping + body->t*body->i_inv*dt;
// reset force vector
body->f = cpvzero;
// reset torque
body->t = 0.0f;
// set body's velocity to desired velocity
body->v.x = kRollingHeroMoveSpeed;
}
Here's cpBody.h on Github.
EDIT 2: Problem solved! I can´t promise it will work with different settings, but by putting my block´s body density to 0, the stack of blocks did not fall when new blocks are added.
I´m sorry about the poor title of the question, I´ll explain my problem closer here:
So, I´ve used Box2D and cocos2D to setup a simple project where two boxes stacks on top of each other (I´m planning to expand to 8-10 boxes). Right now, using a friction of 10.0f on each box, the box at the top still moves around a little. If I would add more boxes, the "tower" would fall and I don´t want that.
I want the boxes to use the gravity to move down, but I never ever want them to change there start x-value.
So, how could I prevent my tower of boxes to fall over or prevent my boxes from moving in x-direction?
EDIT: Posting some code
This code creates on of the boxes, the other one just have a different sprite file.
CCSprite *block = [CCSprite spriteWithFile:#"red.png"];
block.position = ccp(200,380);
[self addChild:block];
//Body definition
b2BodyDef blockDef;
blockDef.type = b2_dynamicBody;
blockDef.position.Set(200/PTM_RATIO, 200/PTM_RATIO);
blockDef.userData = block;
b2Body *blockBody = _world->CreateBody(&blockDef);
//Create the shape
b2PolygonShape blockShape;
blockShape.SetAsBox(block.contentSize.width/PTM_RATIO/2, block.contentSize.height/PTM_RATIO/2);
//Fixture defintion
b2FixtureDef blockFixtureDef;
blockFixtureDef.shape = &blockShape;
blockFixtureDef.restitution = 0.0f;
blockFixtureDef.density = 10.0f;
blockFixtureDef.friction = 10.0f;
_redBlockFixture = blockBody->CreateFixture(&blockFixtureDef);
Nothing fancy.
Regards.
You could setup a 2 (1 pixel wide) walls in box2D to the left and right of the block. Here's some sample code for the left wall. To create the right wall, just copy and past the code and change the variable names and the position of the BodyDef.
// Constant you'll need to define
float wallHeight;
// Create wall body
b2BodyDef wallBodyDef;
wallBodyDef.type = b2_dynamicBody;
wallBodyDef.position.Set(200 - block.contentSize.width/PTM_RATIO/2, 0);
b2Body *wallBody = _world->CreateBody(&wallBodyDef);
// Create wall shape
b2PolygonShape wallShape;
wallShape.SetAsBox(1, wallHeight);
// Create shape definition and add to body
b2FixtureDef wallShapeDef;
wallShapeDef.shape = &wallShape;
wallShapeDef.density = 100.0f;
wallShapeDef.friction = 0.0f;
wallShapeDef.restitution = 0.0f;
b2Fixture *wallFixture = wallBody->CreateFixture(&wallShapeDef);
I solved this problem by adjusting the restitution (bounce) of the static surface upon which the blocks are stacked. For example, if the floor has a restitution of .2, a stack of five blocks will look like they are compressing into each other, and eventually topple:
Set the restitution of the floor to 0, and the blocks stay stacked the way you would expect:
I'm working with Java3d under eclipse Indigo in windows. After finally modifying the StlLoader example and ObjLoad classes to get my STL files to load up, I get a result that looks like the below (I think from other questions these are definitely bad vector normals). Does anybody know why I might be having this problem? I am using SolidWorks to save the STL as an ASCII file and using a modification of the code for loading STL files given on java3d.org. Although I have only changed some appearance properties and fixed broken imports etc. I have confirmed that the facet normals put into "normList" below definitely match those from the file.
Example of Result:
Snippet of StlFile.java from http://www.java3d.org :
private SceneBase makeScene()
{
// Create Scene to pass back
SceneBase scene = new SceneBase();
BranchGroup group = new BranchGroup();
scene.setSceneGroup(group);
// Store the scene info on a GeometryInfo
GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_STRIP_ARRAY);
// Convert ArrayLists to arrays: only needed if file was not binary
if(this.Ascii)
{
coordArray = objectToPoint3Array(coordList);
normArray = objectToVectorArray(normList);
}
gi.setCoordinates(coordArray);
gi.setNormals(normArray);
gi.setStripCounts(stripCounts);
// Setting the Material Appearance
Appearance app = new Appearance();
// Coloring Attributes
ColoringAttributes catt = new ColoringAttributes();
catt.setShadeModel( ColoringAttributes.NICEST );
app.setColoringAttributes(catt);
Material mat = new Material(new Color3f(0.6f, 0.6f, 0.6f), // ambient
new Color3f(0, 0, 0), // emissive
new Color3f(0.6f, 0.6f, 0.6f), // diffuse
new Color3f(0.6f, 0.6f, 0.6f), // specular
10); // shininess
app.setMaterial(mat);
// Put geometry into Shape3d
Shape3D shape = new Shape3D(gi.getGeometryArray(), app);
group.addChild(shape);
scene.addNamedObject(objectName, shape);
return scene;
} // end of makeScene
If some areas on the surface are really black (0x000000), I would guess some of the normals are actually pointing inwards the model rather than to the outside.
You may check if vertices v1,v2,v3 for all the triangles are defined in right-hand order (just test if det(v1,v2,v3) > 0 ) and reorder points accordingly. Alternatively, detect the "opposite" normals and multiply them by -1
I'm having a lot of trouble detecting collisions in a zero-G space game. Hopefully this image will help me explain:
http://i.stack.imgur.com/f7AHO.png
The white rectangle is a static body with a b2PolygonShape fixture attached, as such:
// Create the line physics body definition
b2BodyDef wallBodyDef;
wallBodyDef.position.Set(0.0f, 0.0f);
// Create the line physics body in the physics world
wallBodyDef.type = b2_staticBody; // Set as a static body
m_Body = world->CreateBody(&wallBodyDef);
// Create the vertex array which will be used to make the physics shape
b2Vec2 vertices[4];
vertices[0].Set(m_Point1.x, m_Point1.y); // Point 1
vertices[1].Set(m_Point1.x + (sin(angle - 90*(float)DEG_TO_RAD)*m_Thickness), m_Point1.y - (cos(angle - 90*(float)DEG_TO_RAD)*m_Thickness)); // Point 2
vertices[2].Set(m_Point2.x + (sin(angle - 90*(float)DEG_TO_RAD)*m_Thickness), m_Point2.y - (cos(angle - 90*(float)DEG_TO_RAD)*m_Thickness)); // Point 3
vertices[3].Set(m_Point2.x, m_Point2.y); // Point 3
int32 count = 4; // Vertex count
b2PolygonShape wallShape; // Create the line physics shape
wallShape.Set(vertices, count); // Set the physics shape using the vertex array above
// Define the dynamic body fixture
b2FixtureDef fixtureDef;
fixtureDef.shape = &wallShape; // Set the line shape
fixtureDef.density = 0.0f; // Set the density
fixtureDef.friction = 0.0f; // Set the friction
fixtureDef.restitution = 0.5f; // Set the restitution
// Add the shape to the body
m_Fixture = m_Body->CreateFixture(&fixtureDef);
m_Fixture->SetUserData("Wall");[/code]
You'll have to trust me that that makes the shape in the image. The physics simulation works perfectly, the player (small triangle) collides with the body with pixel perfect precision. However, I come to a problem when I try to determine when a collision takes place so I can remove health and what-not. The code I am using for this is as follows:
/*------ Check for collisions ------*/
if (m_Physics->GetWorld()->GetContactCount() > 0)
{
if (m_Physics->GetWorld()->GetContactList()->GetFixtureA()->GetUserData() == "Player" &&
m_Physics->GetWorld()->GetContactList()->GetFixtureB()->GetUserData() == "Wall")
{
m_Player->CollideWall();
}
}
I'm aware there are probably better ways to do collisions, but I'm just a beginner and haven't found anywhere that explains how to do listeners and callbacks well enough for me to understand. The problem I have is that GetContactCount() shows a contact whenever the player body enters the purple box above. Obviously there is a rectangular bounding box being created that encompasses the white rectangle.
I've tried making the fixture an EdgeShape, and the same thing happens. Does anyone have any idea what is going on here? I'd really like to get collision nailed so I can move on to other things. Thank you very much for any help.
The bounding box is an AABB (axis aligned bounding box) which means it will always be aligned with the the Cartesian axes. AABBs are normally used for broadphase collision detection because it's a relatively simple (and inexpensive) computation.
You need to make sure that you're testing against the OBB (oriented bounding box) for the objects if you want more accurate (but not pixel perfect, as Micah pointed out) results.
Also, I agree with Micah's answer that you will most likely need a more general system for handling collisions. Even if you only ever have just walls and the player, there's no guarantee that which object will be A and which will be B. And as you add other object types, this will quickly unravel.
Creating the contact listener isn't terribly difficult, from the docs (added to attempt to handle your situation):
class MyContactListener:public b2ContactListener
{
private:
PlayerClass *m_Player;
public:
MyContactListener(PlayerClass *player) : m_Player(player)
{ }
void BeginContact(b2Contact* contact)
{ /* handle begin event */ }
void EndContact(b2Contact* contact)
{
if (contact->GetFixtureA()->GetUserData() == m_Player
|| contact->GetFixtureB()->GetUserData() == m_Player)
{
m_Player->CollideWall();
}
}
/* we're not interested in these for the time being */
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{ /* handle pre-solve event */ }
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{ /* handle post-solve event */ }
};
This requires you to assign m_Player to the player's fixture's user data field. Then you can use the contact listener like so:
m_Physics->GetWorld()->SetContactListener(new MyContactListener(m_Player));
How do you know GetFixtureA is the player and B is the wall? Could it be reversed? Could there be an FixtureC? I would think you would need a more generic solution.
I've used a similar graphics framework (Qt) and it had something so you could grab any two objects and call something like 'hasCollided' which would return a bool. You could get away with not using a callback and just call it in the drawScene() or check it periodically.
In Box2D the existence of a contact just means that the AABBs of two fixtures overlaps. It does not necessarily mean that the shapes of the fixtures themselves are touching.
You can use the IsTouching() function of a contact to check if the shapes are actually touching, but the preferred way to deal with collisions is to use the callback feature to have the engine tell you whenever two fixtures start/stop touching. Using callbacks is much more efficient and easier to manage in the long run, though it may be a little more effort to set up initially and there are a few things to be careful about - see here for an example: http://www.iforce2d.net/b2dtut/collision-callbacks