Cocos2d shake/accelerometer issue
So I a little backstory. I wanted to implement a particle effect and sound effect that both last about 3 sec or so when the user shakes their iDevice. But first issue arrived when the build in UIEvent for shakes refused to work. So I took the advice of a few Cocos veterans to just use some script to get "violent" accelerometer inputs as shakes. Worked great until now.
The problem is that if you keep shaking it just stacks the particle and sounds over and over. Now this wouldn't be that big of a deal except it happens even if you are careful to try and not do so. So what I am hoping to do is disable the accelerometer when the particle effect/sound effect start and then reenable it as soon as they finish. Now I don't know if I should do this by schedule, NStimer, or some other function. I am open to ALL suggestions. here is my current "shake" code.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
const float violence = 1;
static BOOL beenhere;
BOOL shake = FALSE;
if (beenhere) return;
beenh开发者_高级运维ere = TRUE;
if (acceleration.x > violence * 1.5 || acceleration.x < (-1.5* violence))
shake = TRUE;
if (acceleration.y > violence * 2 || acceleration.y < (-2 * violence))
shake = TRUE;
if (acceleration.z > violence * 3 || acceleration.z < (-3 * violence))
shake = TRUE;
if (shake) {
id particleSystem = [CCParticleSystemQuad particleWithFile:@"particle.plist"];
[self addChild: particleSystem];
// Super simple Audio playback for sound effects!
[[SimpleAudioEngine sharedEngine] playEffect:@"Sound.mp3"];
shake = FALSE;
}
beenhere = FALSE;
}
UIAcceleration has a timestamp property. I would modify your code to save the current timestamp on a succesful shake in a static variable (perhaps static NSTimeInterval timestampOfLastShake
?). Then modify if (shake)
to if (shake && acceleration.timestamp - 3.0f >= timestampOfLastShake)
resulting code:
static NSTimeInterval timestampOfLastShake = 0.0f;
if (shake && acceleration.timestamp - 3.0f >= timestampOfLastShake ) {
timestampOfLastShake = acceleration.timestamp;
id particleSystem = [CCParticleSystemQuad particleWithFile:@"particle.plist"];
[self addChild: particleSystem];
// Super simple Audio playback for sound effects!
[[SimpleAudioEngine sharedEngine] playEffect:@"Sound.mp3"];
shake = FALSE;
}
You realize that you are doing single axis acceleration checks and you are not ensuring the acceleration is repeated (i.e. shake). In other words, if you drop your phone, your code will think it's someone shaking the device back-and-fourth few times (which is what a shake is) and fire many times a second. So, either apply multi-axis checks against time or simply use the shake UIEvent. All you will need to do is in your UIView (or UIWindow better yet), implement - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
making sure the view becomes first responder. This will take care of all acceleration filtering, etc. and app won't be bombarded by all the acceleration noise (you can drop your phone on the table and it won't mistake that for a shake).
Go here for doc: http://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/MotionEvents/MotionEvents.html
Or:
- (BOOL)canBecomeFirstResponder { return YES; } // Now call [self becomeFirstResponder]; somewhere, say in viewDidAppear of the controller. - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { } - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { if (event.subtype == UIEventSubtypeMotionShake) { // You've got a shake, do something } } - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event { }
精彩评论