我有多个精神与物理机构。用户一次移动一个精灵。创建鼠标关节以支持移动。使用Cocos2d V2.0
在QueryAABB(& callback,aabb)报告夹具后,在ccTouchesBegan中初始化鼠标关节。下面三个方法之间的逻辑重新连接鼠标
在界面
中b2World* world;
GLESDebugDraw *m_debugDraw;
b2MouseJoint *mouseJoint;
b2Body* groundBody;
float _boxHeight;
float _boxWidth;
int sectionW;
b2MouseJoint *m_mouseJoint;
实施
我大部分时间都在TOUCHES ENDED上面的行上面有一个EXC_BAD_ACCESS,xcode在线程上显示以下内容 线程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;
};
答案 0 :(得分:0)
你确定这不只是一个错字吗?我在某些地方看到 mouseJoint ,在其他地方看到 MouseJoint 。您测试 MouseJoint ,但是您销毁 mouseJoint 。
我承认,我正试图用鼠标联合解决完全相同的错误,所以我希望在这里找到答案。在我调用DestroyJoint之前,所有符号都指向一个被其他操作删除的关节,以便处理空指针,因此如果 MouseJoint 不是nil而是 mouseJoint 是那么它可能会解释您案件中的错误。
答案 1 :(得分:0)
我试图解决同样的问题。我在代码中有其他地方会在附加的精灵/身体被破坏时破坏鼠标关节等。原来你必须确保只在触摸事件中管理鼠标关节并将其余部分留给Box2D的。
你的代码中是否还有其他地方可能正在修改鼠标关节变量,比如在tick:方法中?
这是我触摸鼠标关节的唯一地方。它似乎也映射到您的用例。我使用的是LevelHelper事件代码,因此方法签名看起来有点不同。做到这一点大大简化了事情。
-(void)touchBegin:(LHTouchInfo*)info {
CGPoint location = [[CCDirector sharedDirector] convertToGL: [info.touch locationInView: [info.touch view]]];
_lastBrickTouched = info.sprite;
_mouseJoint = [lh mouseJointForBody: _lastBrickTouched.body touchPoint: location];
}
-(void)touchMoved:(LHTouchInfo*)info{
CGPoint touchZone = [info.touch locationInView:[info.touch view]];
touchZone = [[CCDirector sharedDirector] convertToGL:touchZone];
b2Vec2 p;
p.Set(touchZone.x/PTM_RATIO, touchZone.y/PTM_RATIO);
if (_mouseJoint != nil)
{
_mouseJoint->SetTarget(p);
}
}
-(void)touchEnded:(LHTouchInfo*)info {
if (_mouseJoint != nil) {
world->DestroyJoint(_mouseJoint);
_mouseJoint = nil;
}
}
答案 2 :(得分:0)
我遇到了与我正在进行的当前项目相同的问题。每次我试图销毁附有mouseJoint的主体时,我都会遇到程序崩溃(touchesEnded中的EXC_BAD_ACCESS :)。
我的touchesEnded:代码与上面类似:
- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
if (mouseJoint != NULL)
{
world->DestroyJoint(mouseJoint);
mouseJoint = NULL;
}
}
Box2d会破坏附着在身体上的关节。但是,我猜Box2d在通过DestroyJoint销毁之后不会使联合指针无效?
无论如何,我阻止程序崩溃的方式是在我的身体破坏功能中,我首先在销毁身体之前销毁了mouseJoint(并将其设置为NULL)。我的破坏物体的代码(如果附加到要删除的物体上,则首先删除mouseJoint)如下:
-(void)destroyActor:(ObjectView *)objectView
{
b2Body* b = (b2Body*)objectView.tag;
// Destroy mouseJoint if attached to body b
b2JointEdge* jl = b->GetJointList();
while (jl)
{
b2Joint* j = jl->joint;
if (j == mouseJoint)
{
world->DestroyJoint(j);
mouseJoint = NULL;
break;
}
jl = jl->next;
}
world->DestroyBody(b);
[objectView removeFromSuperview];
[objectView release];
}
在我的代码中,ObjectView *只是我用来处理actor的UIImageView的子类。
答案 3 :(得分:0)
我遇到了同样的崩溃错误:
Thread 1, Queue : com.apple.main-thread
error: address doesn't contain a section that points to a section in a object file
我通过将 -Obj ** C标志添加到** Other Linker Flags 来修复它。
答案 4 :(得分:0)
我会添加一些建议来检查。我在libGDX中使用box2d。必须通过world.destroyBody()和world.destroyJoint()相应地销毁body和joint。销毁的顺序如下:
另一件需要考虑的事实是,在box2d(libGDX&#39; s)中,mouseJoint就像其他关节有2个身体一样:bodyA&amp; amp; bodyB。但其中一个是虚构的 - 它可能是任何静态的身体。我使用虚构的屏幕外体。删除关节时,您可能会意外删除该身体。所有其他关节都可以正常工作!但是在创建新关节时你确实会遇到异常,因为使用了badptr或null body,这是不可接受的。所以,你必须小心翼翼地摧毁那个虚构的身体。例如,您可以添加一些MouseJointHelper类,如:
class MouseJointHelper
{
Body fictionalBody;
MouseJoint createJoint(...) //here we create joint, using fictional body
void destroyJointAndBodies(MouseJoint joint) //destroy joint and bodyA, assuming that bodyB is the same for all (fictional body)
void dispose() //in destructor method destroy fictional body
};