物理体を持つ複数のスプライトがあります。ユーザーは一度に 1 つのスプライトを移動しています。動きをサポートするためにマウス ジョイントが作成されます。Cocos2d V2.0 の使用
マウス ジョイントは、QueryAABB(&callback, aabb) がフィクスチャを報告した後、ccTouchesBegan で初期化されます。Mouse Joint に関する 3 つのメソッド間のロジックの下
インターフェイス内
b2World* world;
GLESDebugDraw *m_debugDraw;
b2MouseJoint *mouseJoint;
b2Body* groundBody;
float _boxHeight;
float _boxWidth;
int sectionW;
b2MouseJoint *m_mouseJoint;
実装
ほとんどの場合、TOUCHES ENDED 内の上記の行に EXC_BAD_ACCESS が表示されます。xcode は、スレッド Thread 1 に次のように表示します。
0 0x0000000
1 b2World::DestroyJoint(b2Joint*)
2 -[matchSprites ccTouchesEnded::withEvent
3 -[NSObject .... more lines reported
上記の 0 ステップで、右側のウィンドウにエラーが表示されます: アドレスには、オブジェクト ファイル内のセクションを指すセクションが含まれていません
これまでに提供された推奨事項に従っていますが、成功していません。この時点では、何が条件を生成しているのかわかりません。テスト時に、オブジェクトを破棄している方法が問題を引き起こしていると考えるようになっています (つまり、そのコードを無効にした場合)はオブジェクトを破棄しています) そのようなエラーはありません。どんな助けでも大歓迎です。
以下の完全なコード
-(id) init
{
if( (self=[super init])) {
self.isTouchEnabled = YES;
// Load physics file
[[GB2ShapeCache sharedShapeCache] addShapesWithFile:@"imagesphysics.plist"];
// Add number images to cache
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"images.plist"];
// init physics
[self initPhysics];
// Tags for the options are based on 500
int numberOfOptions = 2;
CGSize s = [CCDirector sharedDirector].winSize;
sectionW = s.width / numberOfOptions;
for (int i = 0; i < 2; i++) {
// Add target matching Sprites
CCSprite *targetSprite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:@"%d.png",i+1]];
targetSprite.position = CGPointMake(i * sectionW + (sectionW/2.0) ,s.height * 0.75);
[targetSprite runAction:[CCTintBy actionWithDuration:0.2f red:50 green:50 blue:40]];
targetSprite.scale = 0.6f;
[self addChild:targetSprite z:30 tag:i+1];
// Add source matching physics sprites
[self addNewSpriteAtPosition:CGPointMake(i * sectionW + (sectionW/2.0) ,s.height * 0.35) number:i bodyType:b2_dynamicBody];
}
[self scheduleUpdate];
}
return self;
}
// Add Sprites
-(void) addNewSpriteAtPosition:(CGPoint)p number:(int)number bodyType:(b2BodyType)bodyType
{
CCLOG(@"Add sprite %0.2f x %02.f",p.x,p.y);
CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:@"%d.png",number+1]];
sprite.scale = 0.6f;
sprite.position = ccp(p.x,p.y);
[self addChild:sprite z:35 tag:(number+1)+100];
// Define the dynamic body.
b2BodyDef bodyDef;
bodyDef.type = bodyType;
bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
bodyDef.userData = sprite;
b2Body *body = world->CreateBody(&bodyDef);
// Load the fixture using the vertices file generated by Physics Editor
[[GB2ShapeCache sharedShapeCache] addFixturesToBody:body forShapeName:[NSString stringWithFormat:@"%d",number+1] forSprite:sprite];
[sprite setAnchorPoint:
[[GB2ShapeCache sharedShapeCache] anchorPointForShape:[NSString stringWithFormat:@"%d",number+1]]];
}
//Update the physics
-(void) update: (ccTime) dt
{
int32 velocityIterations = 8;
int32 positionIterations = 1;
CGSize s = [CCDirector sharedDirector].winSize;
world->Step(dt, velocityIterations, positionIterations);
world->ClearForces();
// Store objects to be destroyed
std::vector<b2Body *>toDestroy;
CCSprite *currentSprite;
CCSprite *targetSprite;
int currentTag;
for (b2Body *b = world->GetBodyList(); b; b=b->GetNext()) {
if (b->GetUserData() != NULL) {
CCSprite *obj = (CCSprite*)b->GetUserData();
obj.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
obj.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
// Calculate the bounding box for this sprite
_boxHeight = obj.boundingBox.size.height;
_boxWidth = obj.boundingBox.size.width;
currentSprite = (CCSprite *)b->GetUserData();
currentTag = currentSprite.tag;
targetSprite = (CCSprite *)[self getChildByTag:currentTag - 100];
// SPECIFIC - matching sprite is tag + 100 of current userdata sprite for b object
float distX = b->GetPosition().x * PTM_RATIO - targetSprite.position.x;
float distY = b->GetPosition().y * PTM_RATIO - targetSprite.position.y;
if (distX * distX + distY * distY < (_boxWidth * _boxHeight) && b->GetType() == b2_dynamicBody) {
// Destroy object later
toDestroy.push_back(b);
}
} // if b-getuserdata
}
// Destroy objects
std::vector<b2Body *>::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
b2Body *body = *pos2;
if (body->GetUserData() != NULL) {
// Remove target matching
CCSprite *sprite = (CCSprite *) body->GetUserData();
currentTag = currentSprite.tag;
targetSprite = (CCSprite *)[self getChildByTag:currentTag - 100];
[self removeChild:sprite cleanup:YES];
// Remove physics body associated with the Sprite
world->DestroyBody(body);
// This line has been commented then test and the error persist!!!!
[self addNewSpriteAtPosition:CGPointMake(targetSprite.position.x ,s.height * 0.75) number:targetSprite.tag-1 bodyType:b2_staticBody];
}
}
}
//Init physics
-(void) initPhysics
{
CGSize s = [[CCDirector sharedDirector] winSize];
b2Vec2 gravity;
gravity.Set(0.0f, -4.81f);
world = new b2World(gravity);
// Do we want to let bodies sleep?
world->SetAllowSleeping(true);
world->SetContinuousPhysics(true);
m_debugDraw = new GLESDebugDraw( PTM_RATIO );
//world->SetDebugDraw(m_debugDraw);
uint32 flags = 0;
flags += b2Draw::e_shapeBit;
flags += b2Draw::e_jointBit;
flags += b2Draw::e_aabbBit;
//flags += b2Draw::e_pairBit;
//flags += b2Draw::e_centerOfMassBit;
m_debugDraw->SetFlags(flags);
// 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.
b2EdgeShape groundBox;
// bottom
groundBox.Set(b2Vec2(0,0), b2Vec2(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
// top
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// left
groundBox.Set(b2Vec2(0,s.height/PTM_RATIO), b2Vec2(0,0));
groundBody->CreateFixture(&groundBox,0);
// right
groundBox.Set(b2Vec2(s.width/PTM_RATIO,s.height/PTM_RATIO), b2Vec2(s.width/PTM_RATIO,0));
groundBody->CreateFixture(&groundBox,0);
}
//Touches handling
-(void)registerWithTouchDispatcher {
[[[CCDirector sharedDirector] touchDispatcher] addStandardDelegate:self priority:0];
}
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (mouseJoint != NULL) return;
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 p = b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO);
// Make a small box.
b2AABB aabb;
b2Vec2 d;
d.Set(0.001f, 0.001f);
aabb.lowerBound = p - d;
aabb.upperBound = p + d;
// Query the world for overlapping shapes.
QueryCallback callback(p);
world->QueryAABB(&callback, aabb);
if (callback.m_fixture)
{
b2Body* body = callback.m_fixture->GetBody();
b2MouseJointDef md;
md.bodyA = groundBody;
md.bodyB = body;
md.target = p;
md.maxForce = 1500.0f * body->GetMass();
mouseJoint = nil;
mouseJoint = (b2MouseJoint*)world->CreateJoint(&md);
pointer = &mouseJoint;
NSLog(@"Pointer: %p", *pointer);
//mouseJoint = (b2MouseJoint*)world->CreateJoint(&md);
body->SetAwake(true);
}
[self ccTouchesMoved:touches withEvent:event];
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (mouseJoint == NULL) return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
b2Vec2 locationWorld = b2Vec2(location.x / PTM_RATIO, location.y / PTM_RATIO);
mouseJoint->SetTarget(locationWorld);
}
-(void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
if (mouseJoint) {
world->DestroyJoint(mouseJoint); // TODO INVESTIGATE WHY THIS CAUSES A BAD ACCESS ERROR
mouseJoint = nil;
}
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (mouseJoint) {
//CCLOG(@"WORLD is nil %d",world != nil);
//CCLOG(@"MOUSEJOINT is nil %d",mouseJoint != nil);
NSLog(@"Pointer: %p", *pointer);
mouseJoint->SetTarget(b2Vec2_zero);
world->DestroyJoint(mouseJoint); // TODO INVESTIGATE WHY THIS CAUSES A BAD ACCESS ERROR
mouseJoint = NULL;
CCLOG(@"MOUSE JOINT WAS DESTROYED SUCCESSFULLY!!!!!");
}
}
//Query Callback
class QueryCallback : public b2QueryCallback
{
public:
QueryCallback(const b2Vec2& point)
{
m_point = point;
m_fixture = NULL;
}
bool ReportFixture(b2Fixture* fixture)
{
b2Body* body = fixture->GetBody();
if (body->GetType() == b2_dynamicBody)
{
bool inside = fixture->TestPoint(m_point);
if (inside)
{
m_fixture = fixture;
// We are done, terminate the query.
return false;
}
}
// Continue the query.
return true;
}
b2Vec2 m_point;
b2Fixture* m_fixture;
};