One possible solution is as follow:
Fix the rotation angle for the box
Box2D doesn't have angle joints, but setting the body definition with the property fixedRotation = true
allows it to maintain a constant
angle of rotation like the angle joint.
High maximum torque for the motor's joint
The maximum torque for the motor in the revolute joint needs to be relatively high, so that the joint can accelerate or be able to stand the two bodies on the slope. To stop on the slope set the motor speed to zero.
High friction coefficient for the circle
Also a high friction coefficient for the circle allows it to maintain a good grip on the ground, so that it can start to move without drifting.
To test the suggested technique create a new project, then choose the iOS > cocos2d > cocos2d_box2d template.
After creating the project go to HelloWorldLayer.mm and change the init
method like this
-(id) init
{
//...
// bottom
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
//...
}
changes to
-(id) init
{
//...
// bottom
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(.5f*screenSize.width/PTM_RATIO,.25f*screenSize.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0); groundBox.SetAsEdge(b2Vec2(.5f*screenSize.width/PTM_RATIO,.25f*screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
//...
}
look for addNewSpriteWithCoords
method and replace all its content
-(void) addNewSpriteWithCoords:(CGPoint)p
{
//...
}
changes to
-(void) addNewSpriteWithCoords:(CGPoint)p
{
CCSpriteBatchNode *batch = (CCSpriteBatchNode*) [self getChildByTag:kTagBatchNode];
//We have a 64x64 sprite sheet with 4 different 32x32 images. The following code is
//just randomly picking one of the images
CCSprite *circleSprite = [CCSprite spriteWithBatchNode:batch rect:CGRectMake((rand()%4)*32,32,32,32)];
[batch addChild:circleSprite];
circleSprite.position = ccp( p.x, p.y);
// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef circleBodyDef;
circleBodyDef.type = b2_dynamicBody;
//bodyDef.fixedRotation = true;
circleBodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
circleBodyDef.userData = circleSprite;
b2Body *circleBody = world->CreateBody(&circleBodyDef);
// Define another box shape for our dynamic body.
b2CircleShape dynamicCircle ;
dynamicCircle.m_radius = .5f;//These are mid points for our 1m box
// Define the dynamic body fixture.
b2FixtureDef circleFixtureDef;
circleFixtureDef.shape = &dynamicCircle;
circleFixtureDef.density = 1.0f;
circleFixtureDef.friction = 4.0f;
circleBody->CreateFixture(&circleFixtureDef);
//We have a 64x64 sprite sheet with 4 different 32x32 images. The following code is
//just randomly picking one of the images
CCSprite *boxSprite = [CCSprite spriteWithBatchNode:batch rect:CGRectMake((rand()%4)*32,0,32,32)];
[batch addChild:boxSprite];
boxSprite.position = ccp( p.x, p.y);
// Define the dynamic body.
//Set up a 1m squared box in the physics world
b2BodyDef boxBodyDef;
boxBodyDef.type = b2_dynamicBody;
boxBodyDef.fixedRotation = true;
boxBodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
boxBodyDef.userData = boxSprite;
b2Body *boxBody = world->CreateBody(&boxBodyDef);
// Define another box shape for our dynamic body.
b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box
// Define the dynamic body fixture.
b2FixtureDef boxFixtureDef;
boxFixtureDef.shape = &dynamicBox;
boxFixtureDef.density = 1.0f;
boxFixtureDef.friction = 0.3f;
boxBody->CreateFixture(&boxFixtureDef);
b2RevoluteJointDef revoluteJointDef;
revoluteJointDef.bodyA = boxBody;
revoluteJointDef.localAnchorA = b2Vec2(0, -.5);
revoluteJointDef.bodyB = circleBody;
revoluteJointDef.collideConnected = false;
revoluteJointDef.enableMotor = true;
revoluteJointDef.maxMotorTorque = 200;
revoluteJointDef.motorSpeed = CC_DEGREES_TO_RADIANS(0);
world->CreateJoint(&revoluteJointDef);
}
in the tick method add this code just after world->step(…)
-(void) tick: (ccTime) dt
{
//...
world->Step(dt, velocityIterations, positionIterations);
for (b2Joint* j = world->GetJointList(); j; j = j->GetNext())
{
int randomNumber = rand()%40; // choose a random number, ranged between 0 and 39
bool changeMovement = randomNumber == 0; // change movement only when random number is 0, it could be any other arbitrary number
if (changeMovement)
{
b2RevoluteJoint* rj = (b2RevoluteJoint*) j;
rj->GetBodyB()->SetLinearVelocity(b2Vec2(0,0));
int randomNumber = rand()%3; // take the number 0, 1, or 2 at random
randomNumber = randomNumber-1; // convert the random number to either -1, 0 or +1
float angularSpeedInDegrees = randomNumber*2.f*360.f // multiply the random number by a given angular speed, in this case two revolutions per second
rj->SetMotorSpeed(CC_DEGREES_TO_RADIANS(angularSpeed));
}
}
//...
}
replace the file blocks.png for this file

this is the screen capture
http://youtu.be/10WO9tp5p0M