I tried to set up a prismatic joint, but I get this error upon run time:
Assertion failed: (IsLocked() == false), function CreateBody, file /Users/Aether/Developer/JFRecode/JFRecode/libs/Box2D/Dynamics/b2World.cpp, line 109.
Here is the code for the screen boundaries since I am using it as bodyB.
CGSize s = [CCDirector sharedDirector].winSize;
//define screen boundaries
// Create edges around the entire screen
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
_groundBody = _world->CreateBody(&groundBodyDef);
b2EdgeShape groundBox;
b2FixtureDef groundBoxDef;
groundBoxDef.shape = &groundBox;
groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO, 0));
_bottomFixture = _groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(0,0), b2Vec2(0, s.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(0, s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,
s.height/PTM_RATIO));
_groundBody->CreateFixture(&groundBoxDef);
groundBox.Set(b2Vec2(s.width/PTM_RATIO, s.height/PTM_RATIO),
b2Vec2(s.width/PTM_RATIO, 0));
_groundBody->CreateFixture(&groundBoxDef);
Here is the code for the prismatic joint itself
b2PrismaticJointDef jointDef;
b2Vec2 worldAxis(1.0f,0.0f);
jointDef.collideConnected = true;
jointDef.Initialize(_shipBody,_groundBody,
_shipBody->GetWorldCenter(), worldAxis);
_world->CreateJoint(&jointDef);
isLocked indicates that the physics world is being updated. That means you're running this code during the world step method, likely in or as a result of a contact callback method. Delay executing this code until after the world step.
Related
I'm working on a game in Cocos2d with Box2D. Currently I have a system set up where there are some boundaries. They are for a ball. I want meteors to come in from off the screen and smack the ball.
The boundaries are defined in my init method as follows:
// Define the ground body.
b2BodyDef groundBodyDef;
groundBodyDef.type = b2_staticBody;
groundBodyDef.position.Set(0, 0); // bottom-left corner
// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
b2Body* groundBody = world->CreateBody(&groundBodyDef);
// Define the ground box shape.
b2PolygonShape groundBox;
// bottom
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
// top
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// left
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox,0);
// right
groundBox.SetAsEdge(b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
//Collision filter stuff here. Not working.
b2Filter filter;
filter.groupIndex = -2;
groundBody->GetFixtureList()[0].SetFilterData(filter);
My ball is defined as follows:
//Physics object.
b2BodyDef ballBodyDef;
ballBodyDef.position.Set(ball.position.x/PTM_RATIO, ball.position.y/PTM_RATIO);
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.userData = ball;
ballBodyDef.bullet = true;
ballBody = world->CreateBody(&ballBodyDef);
b2CircleShape ballShape;
ballShape.m_radius = 10.0/PTM_RATIO;
b2FixtureDef ballFix;
ballFix.restitution = 1.1f;
ballFix.density = 0.0f;
ballFix.shape = &ballShape;
ballBody->CreateFixture(&ballFix);
And the meteors are made using two methods, the shorter method places the meteors. The longer one actually creates them using the points given from the shorter one:
-(void)createMeteorAtPoint:(CGPoint)point {
//Create particle sprite representation.
CCParticleMeteor *meteor = [[CCParticleMeteor alloc] initWithTotalParticles:200];
meteor.gravity = ccp(-200,0);
meteor.life = 0.5;
meteor.lifeVar = 0.25;
meteor.position = point;
meteor.tag = 2;
meteor.startSize = 5.0;
meteor.startSizeVar = 3.0;
[self addChild:meteor];
//Make meteor physics body.
b2BodyDef meteorBodyDef;
meteorBodyDef.position.Set(point.x/PTM_RATIO, point.y/PTM_RATIO);
meteorBodyDef.type = b2_dynamicBody;
meteorBodyDef.userData = meteor;
b2Body *meteorBody = world->CreateBody(&meteorBodyDef);
meteorBody->SetBullet(true);
b2CircleShape meteorShape;
meteorShape.m_radius = 7.5/PTM_RATIO;
b2FixtureDef meteorFix;
meteorFix.shape = &meteorShape;
meteorFix.density = 1;
//Give it the same negative group index of the boundaries to prevent collision.
//Not working.
meteorFix.filter.groupIndex = -2;
meteorBody->CreateFixture(&meteorFix);
//Give it a motion.
b2Vec2 F;
F.Set(CCRANDOM_0_1()*2, 0);
meteorBody->SetLinearVelocity(F);
}
//Create a bunch of meteors that will sweep from left to right.
-(void)createMeteors {
for (int i = 0; i < 8*40; i += 20) {
[self createMeteorAtPoint:ccp(-40.0f, i + 2)];
}
NSLog(#"HERE");
}
I can see physics objects pile up on the side of the screen because I have debug flags set up. But one: They are not getting past the boundary despite being the same negative group index. And two: the ball decides it doesn't like the right wall, and goes through it.
If you believe I am missing something crucial please tell me.
Only one of the boundary fixtures is being given the group index of -2 (the bottom). You can loop over all fixtures of a body like this:
for (b2Fixture* f = body->GetFixtureList(); f; f = f->GetNext())
{
//do something with the fixture 'f'
f->SetFilterData(...);
}
I'm not sure why the ball would be ignoring any walls though (unless you are moving it by creating a mouse joint between the ball and the ground body that the walls belong to, and the joint is set to not collide connected bodies... but in that case the ball would ignore all walls, and only while being moved).
I would like to associate the same script to different empty objects I just use as placeholders in the game. The aim is to exploit their positions so that when the user touch a point in the screen, close to one of these objects, a dedicate GUI appears. The problem is that though the two objects are different their scripts seem to influence each other so that when the game is running and I touch one of these two objects both the gui appears. What am I doing wrong?
....
private var check: boolean;
var topCamera : Camera;
var customSkin : GUISkin;
function Update () {
if (Input.GetMouseButtonDown(0)){
if(Input.mousePosition.x > this.transform.position.x - Screen.width*0.20 && Input.mousePosition.x < this.transform.position.x + Screen.width*20){
if(Input.mousePosition.y > this.transform.position.y - Screen.height*0.2 && Input.mousePosition.y < this.transform.position.y + Screen.height*0.2){
check = true;
}
}
}
if(check){
//the camera zooms forward
}else{
//the camera zooms backward
}
}
function OnGUI () {
if (this.check){
var w = Screen.width;
var h = Screen.height;
var bw = 0.083;
var bws = 0.001 *w;
GUI.skin = customSkin;
GUI.Box(new Rect(w*0.6,h*0.3,w*0.38,h*0.45), "Stuff");
customSkin.box.fontSize = 0.04*h;
customSkin.textField.fontSize = 0.08*h;
customSkin.button.fontSize = 0.04*h;
textFieldString = GUI.TextField (Rect (w*0.62, h*0.39, w*0.34, h*0.1), textFieldString);
if (GUI.Button (Rect (w*0.62,h*0.50, w*bw, h*0.1), "+")) {
if (this.check){
this.check=false;
}else{
this.check = true;
}
//...
}
//...
}
This is probably not working, because you are comparing apples with oranges in your Update() function. Input.mousePosition returns the the position in 2D pixel coordinates and transform.position returns the GameObject's position in 3D world coordinates.
To check if you clicked on an object, you need to attach a Collider to the game object in question and test for collisions using a Raycast in your script. Here is the relavant example from the documentation in JavaScript:
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, 100)) {
print ("Hit something");
}
The cool thing about this approach is that we are checking for collisions between the Collider and the ray. If you only want to see if you clicked near the GameObject, just make the Collider larger than the GameObject. No need for messing around with inequalities!
If your objective is to click somewhere close to the object and not only at the object, then you have some configurations (positions of those objects in space) where there are space that are close enough to both objects for their GUI to appear and therefore you need some script to decide which one is closer.
I suggest you to implement a monobehaviour that is a singleton that would track those clicks and measure the distance of all objects, to get the closest.
Reading again your post, I think you want to get the GUI just when you click at the object, and when you do this you get both GUIs. I think that's happening because wrong calculation of the area that makes check to go true.
Can you give more details? Is there some space where there shouldn't have GUI messages when clicked, or is everything filled by those objects?
I am creating the physical body in box2d as below , this si my code
b2BodyDef carBodyDef;
carBodyDef.position.Set(x/PTM_RATIO,y/PTM_RATIO);
carBodyDef.type=b2_dynamicBody; b2Body* carBody=physicsWorld->CreateBody(&carBodyDef);
b2CircleShape carShape;
carShape.m_radius=rad/40.0f;
b2FixtureDef carFixture;
carFixture.shape=&carShape;
carFixture.density = 1.0f;
carFixture.friction = 0.0f;
carBody->CreateFixture(&carFixture);
return carBody ;
When am running the app, its getting crash ,
with the below erro
*Assertion failed: (IsLocked() == false), function CreateBody,*in box2d
That's because you are creating your body during execution of Step() function of b2World. You can't create new bodies while this function is executing
I am trying to make a game in Cocos 2D & Box 2D
but when i try to put a "setAsEdge" it just said me that the function dosn't exist
my code:
// Define the ground body.
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0, 0); // bottom-left corner
// Call the body factory which allocates memory for the ground body
// from a pool and creates the ground box shape (also from a pool).
// The body is also added to the world.
groundBody = world->CreateBody(&groundBodyDef);
// Define the ground box shape.
b2PolygonShape groundBox;
// bottom
groundBox.SetAsEdge(b2Vec2(0,FLOOR_HEIGTH/PTM_RATIO), b2Vec2(screenSize.width*2.0f/PTM_RATIO,FLOOR_HEIGTH/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// top
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width*2.0f/PTM_RATIO,screenSize.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// left
groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox,0);
// right
groundBox.SetAsEdge(b2Vec2(screenSize.width*2.0f/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width*2.0f/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
Error: No member named 'SetAsEdge' in 'b2PolygonShape'. I am using Cocos 2D 1.0.1 Stable
Thanks to everyone
You are working with Box2D 2.2.1 whose API has changed compared to the Box2D version in Cocos2D v1.0.1 (uses Box2D v2.1.2). I take it you're using Cocos2D 2.0 alpha? If so, it supposedly comes with updated Xcode project templates, so you might want to install these and create a project based on the new templates.
Here's how I set the border bounding box by using a body with 4 shapes attached to it:
// for the screenBorder body we'll need these values
CGSize screenSize = [CCDirector sharedDirector].winSize;
float widthInMeters = screenSize.width / PTM_RATIO;
float heightInMeters = screenSize.height / PTM_RATIO;
b2Vec2 lowerLeftCorner = b2Vec2(0, 0);
b2Vec2 lowerRightCorner = b2Vec2(widthInMeters, 0);
b2Vec2 upperLeftCorner = b2Vec2(0, heightInMeters);
b2Vec2 upperRightCorner = b2Vec2(widthInMeters, heightInMeters);
// Define the static container body, which will provide the collisions at screen borders.
b2BodyDef screenBorderDef;
screenBorderDef.position.Set(0, 0);
b2Body* screenBorderBody = world->CreateBody(&screenBorderDef);
b2EdgeShape screenBorderShape;
// Create fixtures for the four borders (the border shape is re-used)
screenBorderShape.Set(lowerLeftCorner, lowerRightCorner);
screenBorderBody->CreateFixture(&screenBorderShape, 0);
screenBorderShape.Set(lowerRightCorner, upperRightCorner);
screenBorderBody->CreateFixture(&screenBorderShape, 0);
screenBorderShape.Set(upperRightCorner, upperLeftCorner);
screenBorderBody->CreateFixture(&screenBorderShape, 0);
screenBorderShape.Set(upperLeftCorner, lowerLeftCorner);
screenBorderBody->CreateFixture(&screenBorderShape, 0);
Alternatively, get Kobold2D Preview 5 (available by tomorrow) and have a look at the Physics-Box2D template project. I made all the necessary changes to run a Box2D v2.2.1 app, including the changes needed for the Box2D debug drawing class. I'm also hosting the latest Box2D API reference.
Use b2EdgeShape instead of b2PolygonShape, for example:
b2EdgeShape groundBox;
groundBox.Set( b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO,0));
use
setAsBox(0,0,b2vec2(0,0),0);
in my app the user is able to move or rotate a box2d fixture. The collision detection works fine. But if I set the fixture as a sensor, with the SetSensor(true) method, the collision detection reacts weird.
In the following picture the red rectangle is the sensor, but a collision is also detected if an other fixture collides with the black border.
Image: http://img851.imageshack.us/img851/7292/rect.png
Is it possible that only the red rectangle reacts as a sensor?
BR
I found the help here:
Box2D Forum
I just forgot to check if the contact is touching (with the IsTouching() method)! Now it works fine!!!
b2BodyDef bodyDef;
bodyDef.type = b2_staticBody;
bodyDef.position.Set(position.x/PTM_RATIO, position.y/PTM_RATIO);
bodyDef.userData = NULL;
b2Body *body = _game.world->CreateBody(&bodyDef);
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(size.x/2/PTM_RATIO, size.y/2/PTM_RATIO);
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicBox;
fixtureDef.isSensor = true;
body->CreateFixture(&fixtureDef);
body->SetTransform(body->GetPosition(), rotatingAngle);