tags:

views:

280

answers:

1

I want to detect shake motion in cocos2d for iPad.

I found a promising article about it and tried to implement it but failed. http://www.softvelopment.com/index.php/blogs/2010/03/19/3-adding-shake-recongnition-to-cocos2d-iphone-library-

Specifically, I'm not sure where I should put the listener. And moreover, is there any other good way to make iPad detect shake using cocos2d?

+2  A: 

Maybe the following code helps you. I found it a while back (don't remember where) and cleaned it up. You can tweak the values in didAccelerate, currently at 0.8 and 0.2 to define how sensitive it is to shaking and how stable you must hold the device to be able to shake again.

Header

@protocol ShakeHelperDelegate
-(void) onShake;
@end

@interface ShakeHelper : NSObject <UIAccelerometerDelegate>
{
    BOOL histeresisExcited;
    UIAcceleration* lastAcceleration;

    NSObject<ShakeHelperDelegate>* delegate;
}

+(id) shakeHelperWithDelegate:(NSObject<ShakeHelperDelegate>*)del;
-(id) initShakeHelperWithDelegate:(NSObject<ShakeHelperDelegate>*)del;

@end

Implementation

#import "ShakeHelper.h"


@interface ShakeHelper (Private)
@end

@implementation ShakeHelper

// Ensures the shake is strong enough on at least two axes before declaring it a shake.
// "Strong enough" means "greater than a client-supplied threshold" in G's.
static BOOL AccelerationIsShaking(UIAcceleration* last, UIAcceleration* current, double threshold) 
{
    double
    deltaX = fabs(last.x - current.x),
    deltaY = fabs(last.y - current.y),
    deltaZ = fabs(last.z - current.z);

    return
    (deltaX > threshold && deltaY > threshold) ||
    (deltaX > threshold && deltaZ > threshold) ||
    (deltaY > threshold && deltaZ > threshold);
}

+(id) shakeHelperWithDelegate:(NSObject<ShakeHelperDelegate>*)del
{
    return [[[self alloc] initShakeHelperWithDelegate:del] autorelease];
}

-(id) initShakeHelperWithDelegate:(NSObject<ShakeHelperDelegate>*)del
{
    if ((self = [super init]))
    {
        delegate = del;
        [UIAccelerometer sharedAccelerometer].delegate = self;
    }

    return self;
}

-(void) accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration 
{
    if (lastAcceleration)
    {
        if (!histeresisExcited && AccelerationIsShaking(lastAcceleration, acceleration, 0.8)) 
        {
            histeresisExcited = YES;

            [delegate onShake];
        }
        else if (histeresisExcited && !AccelerationIsShaking(lastAcceleration, acceleration, 0.2))
        {
            histeresisExcited = NO;
        }
    }

    [lastAcceleration release];
    lastAcceleration = [acceleration retain];
}

-(void) dealloc
{
    CCLOG(@"dealloc %@", self);

    [UIAccelerometer sharedAccelerometer].delegate = nil;
    [lastAcceleration release];
    [super dealloc];
}

@end

You use it like this:

[ShakeHelper shakeHelperWithDelegate:self];

Obviously the self object needs to implement the ShakeHelperDelegate Protocol. The message onShake will be sent to the delegate object whenever a shake is detected.

GamingHorror