I have a ground object and a spear shaped object(dynamic). When a button is pressed, a linear velocity is applied to the spear. It works fine but sometimes, it gets stuck on the ground. This happens most of the time (not always) when the side opposite of spear hide collides straight down with the ground. I am attaching some images so you guys get the picture:
Here my code:
#import "HelloWorldLayer.h"
#define PTM_RATIO 32
@implementation HelloWorldLayer
+(CCScene *) scene{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
-(id) init {
if( (self=[super init])) {
isSimulating = NO;
CGSize winSize = [CCDirector sharedDirector].winSize;
self.isAccelerometerEnabled = YES;
self.isTouchEnabled = YES;
// Create sprite and add it to the layer
_spear = [CCSprite spriteWithFile:@"image_SPEAR.png"];
_spear.position = ccp(40, 30);
[self addChild:_spear];
label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:20];
CGSize size = [[CCDirector sharedDirector] winSize];
label.position = ccp( size.width /2 , size.height/2 );
[self addChild: label];
CCMenuItem *starMenuItem = [CCMenuItemImage
itemFromNormalImage:@"ball.png" selectedImage:@"ball.png"
target:self selector:@selector(starButtonTapped:)];
starMenuItem.position = ccp(60, 250);
CCMenu *starMenu = [CCMenu menuWithItems:starMenuItem, nil];
starMenu.position = CGPointZero;
[self addChild:starMenu];
// Create a world
b2Vec2 gravity = b2Vec2(0.0f, -20.0f);
bool doSleep = true;
_world = new b2World(gravity, doSleep);
// Create edges around the entire screen
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0,0);
b2Body *groundBody = _world->CreateBody(&groundBodyDef);
b2PolygonShape groundBox;
b2FixtureDef boxShapeDef;
boxShapeDef.shape = &groundBox;
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
groundBody->CreateFixture(&boxShapeDef);
groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);
groundBox.SetAsEdge(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, winSize.h开发者_高级运维eight/PTM_RATIO));
groundBody->CreateFixture(&boxShapeDef);
groundBox.SetAsEdge(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, 0));
groundBody->CreateFixture(&boxShapeDef);
boxShapeDef.friction = 0.3f;
[self setup];
}
return self;
}
- (void)setup {
NSLog(@"Setting up...");
//set the sprite's initial position
_spear.position = ccp(40, 30);
_spear.rotation = 0.0f;
//row 1, col 1
int num = 7;
b2Vec2 verts[] = {
b2Vec2(-36.0f / PTM_RATIO, -2.7f / PTM_RATIO),
b2Vec2(20.1f / PTM_RATIO, -2.1f / PTM_RATIO),
b2Vec2(24.4f / PTM_RATIO, -4.6f / PTM_RATIO),
b2Vec2(36.7f / PTM_RATIO, -1.4f / PTM_RATIO),
b2Vec2(23.9f / PTM_RATIO, 2.7f / PTM_RATIO),
b2Vec2(20.7f / PTM_RATIO, 0.0f / PTM_RATIO),
b2Vec2(-36.0f / PTM_RATIO, -0.5f / PTM_RATIO)
};
// Create spear body and shape
b2BodyDef spearBodyDef;
spearBodyDef.type = b2_dynamicBody;
spearBodyDef.position.Set(40.0/PTM_RATIO, 30.0/PTM_RATIO);
//spearBodyDef.angle = 45.0 * (180.0f/b2_pi);
spearBodyDef.userData = _spear;
_spearBody = _world->CreateBody(&spearBodyDef);
b2PolygonShape spearShape;
spearShape.Set(verts, num);
b2FixtureDef spearShapeDef;
spearShapeDef.shape = &spearShape;
spearShapeDef.density = 0.75f;
spearShapeDef.friction = 0.2f;
spearShapeDef.restitution = 0.2f;
_spearBody->CreateFixture(&spearShapeDef);
}
- (void)starButtonTapped:(id)sender {
if (isSimulating) {
NSLog(@"Not simulating now...");
[self unschedule:@selector(tick:)];
_world->DestroyBody(_spearBody);
_spearBody = NULL;
[self setup];
} else {
NSLog(@"Simulating now...");
[self schedule:@selector(tick:)];
float angle = _spearBody->GetAngle();
b2Vec2 force;
force.Set(cos(angle) * 15.0f , sin(angle) * 15.0f);
_spearBody->SetLinearVelocity(force);
}
isSimulating = !isSimulating;
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (!isSimulating) {
UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
float angleRadians = atanf((float)location.y / (float)location.x);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
_spear.rotation = -1 * angleDegrees;
_spearBody->SetTransform(_spearBody->GetPosition(), angleRadians);
[label setString:[NSString stringWithFormat:@"Angle: %f X: %f Y:%f", angleDegrees, location.x, location.y]];
NSLog(@"%@", @"touched");
}
}
- (void)tick:(ccTime) dt {
_world->Step(dt, 10, 10);
for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *ballData = (CCSprite *)b->GetUserData();
ballData.position = ccp(b->GetPosition().x * PTM_RATIO,
b->GetPosition().y * PTM_RATIO);
ballData.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
- (void) dealloc {
delete _world;
_world = NULL;
[super dealloc];
}
@end
I am guessing it has to do with friction and restitution but I have tried a lot of values and nothing makes this behavior go away. Thanks.
**UPDATE:**I figured out what's causing this. Everytime it gets stuck, it's when the spear goes outside of groundBody. Everytime. But, why would it go outside of groundBody in the first place? Here's an image showing this. At the bottom, the spear is outside of body:
Try turning off sleeping...
bool doSleep = false;
_world = new b2World(gravity, doSleep);
I had a similar problem in one of my box2d based games and this "feature" is what caused it.
note that in the latest version of Cocos2D, you need to use the following to prevent that sticking behaviour:
_world->SetAllowSleeping(false);
Your spear shape is not convex. I highly recommend you use Box2D's debug draw feature to check things every now and then. http://www.iforce2d.net/b2dtut/debug-draw
Here is what the polygon really comes out like - the lines are what you specified, the shaded area is what you got:
Actually box2D has an iterative solver. So the quality of the simulation directly depends on iterations quantity. Try increasing position and/or velocity iterations, when making Step
. Also check you are using fixed time step (usually it gives better results). And also you your spear moves rapidly try enabling continuous physics and setting your spear body as bullet (b2BodyDef property).
精彩评论