0

I'd really like to get to the bottom of why this code causes intermittent response to touch input... Even with NSLog as the first instruction...

I've just made a new project in cocos2d with Box2d for a game that at this stage needs to just a few simple things...

A basket that appears in the centre of the screen. It must be a b2Fixture and fall onto a surface. Then if the user touched the screen, I want the basket to zoom to the touch point, and from there the user can drag it around the screen.

When the user lets go, the basket drops... I have this working right now...

However the BUG is that touching the screen doesn't always work... It intermittently responds to touches, and therefore intermittently calls the methods.

As you will see below, I have used NSLog to check when each methods are being called. The result is that sometimes you have to lift your finger off the screen and then back on several times, and then "seemingly at random", it will decide to run the code....

Heres what I got...

My touch methods....

-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Multi Touch Moved...");
    if (_mouseJoint == NULL) return;

    UITouch *myTouch = [touches anyObject];
    CGPoint location = [myTouch locationInView:[myTouch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];
    b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);

    _mouseJoint->SetTarget(locationWorld);
}

-(void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
    NSLog(@"\nThe touch was CANCELED...");
}

-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    NSLog(@"Single Touch Moved...");
}

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *myTouch = [touches anyObject];
    CGPoint location = [myTouch locationInView:[myTouch view]];
    location = [[CCDirector sharedDirector] convertToGL:location];
    b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);

    NSLog(@"\n\nTouch did begin...");

    if (_mouseJoint != NULL)
    {
        _mouseJoint->SetTarget(locationWorld);
        NSLog(@"The IF statment was met...");
        return;
    }

    NSLog(@"The IF statment was NOT met...Running _mouseJoint setup...");

    b2MouseJointDef md;
    md.bodyA = _groundBody;
    md.bodyB = _body;
    md.target = _body->GetPosition();
    md.collideConnected = true;
    md.maxForce = 100000000.0f * _body->GetMass();
    _mouseJoint = (b2MouseJoint *)_world->CreateJoint(&md);
    _body->SetAwake(true);

    _mouseJoint->SetTarget(locationWorld);
}

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (_mouseJoint != nil) {
        _world->DestroyJoint(_mouseJoint);
        _mouseJoint = nil;
    }
}

And this is the interface that some of the code refers to...

@interface HelloWorldLayer : CCLayerColor
{
b2World *_world;
    b2Body *_body;
    b2Fixture *_bodyFix;
    b2MouseJoint *_mouseJoint;
    b2Body *_groundBody;
}

The only idea another member helped me determine is, that because I'm working within a single scene, and I have/had a CCMenu and a CCLabelTTF on the screen, is it possible that the CCMenu is still intercepting touches, and if so, how can I destroy the CCMenu after my animation has finished?

Pressing the only button item simply CCmoves the title and label(CCMenuItem) off the screen vertically... But the object still exists...

phpN00b
  • 138
  • 13
  • 1
    have you tried both simulator and device? And device works fine with other apps? Are you perhaps tapping in the control center / notification area (bottom/top row of screen)? Do you have another finger (or other object interpreted as touch) on the screen but multi touch is not enabled? – CodeSmile May 27 '14 at 07:04
  • Nope, it's none of that... I've tried simulator and real devices. Am defiantly in the near center of the screen. – phpN00b May 27 '14 at 07:06
  • 1
    try to reproduce it in a blank cocos2d project with just the touches methods and logs. I wager it 's got something to do with how the scene is setup, ie other nodes receiving and swallowing touches. – CodeSmile May 27 '14 at 07:08
  • It's a brand new project with only a single main. Got the std intro layer, and helloworldlayer. There's nothing amazing on there, if u like, I'd send u the project file. – phpN00b May 27 '14 at 07:11
  • OOOOOO..... Idea, you might be close! I am working within a single scene, and I have/had a CCMenu and a CCLabelTTF on the screen... Pressing the only button item simply CCmoves the title and label(CCMenuItem) off the screen vertically... Is it possible that the CCMenu is still intercepting touches, and if so, how can I destroy the CCMenu after my animation has finished? – phpN00b May 27 '14 at 18:23
  • You are using the singular (touch) and plural (touches) versions of these methods together. It's been a while, but I have a feeling you're not supposed to do that. btw in ccTouchesMoved and ccTouchesEnded, you should check that one of the touches was actually the one for the mouse joint before doing anything to it. – iforce2d May 27 '14 at 18:27
  • Yes your right @iforce2d, it used to cause a problem, but I think the iOS handles it better these days. In any case, I only added the singular versions for debugging this incase I was loosing touches somewhere, however the behaviour didn't change. As for checking for the mouse joint relevance, my intention is to get the basket to move to where the users finger lands on the screen. Perhaps I'm not doing the right thing? I'm totally new to Box2d and still very new to cocos2d. I've only done a simple tile game previously, and could use any advice you can give tbh. Can you explain your advice. ty – phpN00b May 27 '14 at 18:31
  • What you have will work fine as long as the user only ever touches one finger at a time. But if while dragging the basket they touch with another finger and release, the joint will be destroyed even though the dragging touch still exists. Probably not related to your question but I thought I would mention it since you'll want to address that at some point. – iforce2d May 27 '14 at 18:36
  • I really appreciate you bringing things like this to my attention. I personally don't believe in the unspoken rule of "keeping to the topic", because what you said might have been something i overlook to its release! But nevertheless, I just built it to my phone after implementing the below answer that @LearnCocos2D 'nudged' me in to thinking of, and I can safely say that my 2nd and 3rd touches are ignored and the basket remains at the 1st touch, seemingly unaffected... For now... lol – phpN00b May 27 '14 at 18:45

1 Answers1

1

The problem here was that my CCMenu was still receiving touches (I assume in parts of the screen where the CCMenuItems where formed).

The solution was to declare my CCMenu in my @implementation rather than in my init scene setup.

@implementation HelloWorldLayer
{
    CCLabelTTF *label;
    CCLabelTTF *startTheGameLabel;
    CCSprite *theCattery;
    CCMenu *_menu;
}

Then in my init, rather than declaring it there, i simply assign to the one in the @implementation.

-(id) init { if( (self=[super initWithColor:ccc4(50, 180, 220, 255)]) )
{
    //.. Other "irrelevant to question" scene setup stuff here...//

    // Start the game button
    startTheGameLabel = [CCLabelTTF labelWithString:@"Save Some Kitties!" fontName:@"Zapfino" fontSize:20];
    CCMenuItemLabel *startTheGameLabelItem = [CCMenuItemLabel itemWithLabel:startTheGameLabel target:self selector:@selector(startGameStub:)];

    // Push the menu
    _menu = [CCMenu menuWithItems: startTheGameLabelItem, nil];
    [self addChild:_menu];

    //.. Other "irrelevant to question" scene setup stuff here...//
}

This gives me access to the CCMenu throughout my class, so I can later disable touch input once the user has made a selection.

-(void) startGameStub:(id)sender
{
    CGSize size = [[CCDirector sharedDirector] winSize];

     // Clear the labels off the screen
    CMoveTo *moveTheTitleLabelAction = [CCMoveTo actionWithDuration:1.0 position:ccp(label.position.x, size.height + label.boundingBox.size.height)];
    CCMoveTo *moveTheStartLabelAction = [CCMoveTo actionWithDuration:1.0 position:ccp(startTheGameLabel.position.x, size.height + startTheGameLabel.boundingBox.size.height)];

    // Commit actions
    [label runAction:moveTheTitleLabelAction];
    [startTheGameLabel runAction:moveTheStartLabelAction];

    // LIFE SAVING MESSAGE!!!
    [_menu setTouchEnabled:NO]; // This is what fixes the problem
}
phpN00b
  • 138
  • 13