NSBundle *mainBundle = [NSBundle mainBundle];
farSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"farSound" ofType:@"caf"]];
nearSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"nearSound" ofType:@"caf"]];
levelSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"levelSound" ofType:@"caf"]];
一.简介
NSBundle *mainBundle = [NSBundle mainBundle];
farSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"farSound" ofType:@"caf"]];
nearSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"nearSound" ofType:@"caf"]];
levelSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"levelSound" ofType:@"caf"]];
利用ios设备的重力加速感应,来测量平面的水平位置。有加速度分量,则说明表面有倾斜.
二.技术要点
1.AppDelegate中用+(void)initialize来初始化数据,但是里面不能给NSNotificationCenter addObserver,会报错
//initialize是个很好的初始化数据的地方
+ (void)initialize {
if ([self class] == [LevelAppDelegate class]) {
NSNumber *defaultCalibrationOffset = [NSNumber numberWithFloat:0.0];
//为用户setting数据提供默认值
NSDictionary *resourceDict = [NSDictionary dictionaryWithObject:defaultCalibrationOffset forKey:BubbleLevelCalibrationOffsetKey];
[[NSUserDefaults standardUserDefaults] registerDefaults:resourceDict];
}
}
在应用结束时,将其保存,这样下次打开时,在启动的时候就可以获取上次保存的数值
- (void)applicationWillTerminate:(UIApplication *)application {
//退出程序前保存本次数据
float calibrationOffset = levelViewController.calibrationOffset;
NSNumber *offset = [NSNumber numberWithFloat:calibrationOffset];
[[NSUserDefaults standardUserDefaults] setObject:offset forKey:BubbleLevelCalibrationOffsetKey];
}
2.重力感应
设置delegate,设置的对象需要实现UIAccelerometerDelegate接口
,设置部分参数,主要是更新的间隔,根据不同的应用需求,设置不一样的更新间隔,因为这个功能十分耗电
-(id) init {
if (self = [super init]) {
[[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kUpdateFrequency)];
[[UIAccelerometer sharedAccelerometer] setDelegate:self];
}
return self;
}
UIAccelerometerDelegate的方法
这个就是根据设置的间隔时间触发该方法,值得注意的是里面有个重力感应常用的方法,利用低通来实现一个重力感应缓慢变化的一个过程
// UIAccelerometer delegate method, which delivers the latest acceleration data.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Use a basic low-pass filter to only keep the gravity in the accelerometer values for the X and Y axes
//个人感觉就是让动画影响缓慢点 kFilteringFactor=0.05
accelerationX = acceleration.x * kFilteringFactor + accelerationX * (1.0 - kFilteringFactor);
accelerationY = acceleration.y * kFilteringFactor + accelerationY * (1.0 - kFilteringFactor);
// keep the raw reading, to use during calibrations
currentRawReading = atan2(accelerationY, accelerationX);
float calibratedAngle = [self calibratedAngleFromAngle:currentRawReading];
[levelView updateToInclinationInRadians:calibratedAngle];
}
3.自定义UIView
代码种涉及到2个UIView界面,他们共同使用了同一个Controller,所以它自定义了一个初始化方法,我们可以看到,调用该初始化方法时,它还传入了一个Controller,例子中就是根控制器,这个我觉得在平时写代码种可以经常利用,是个相当不错的思路,此外注意的是,view中的Controller一般来说是assign的。
- (id)initWithFrame:(CGRect)frame viewController:(LevelViewController *)aController {
self = [super initWithFrame:frame];
if (self != nil) {
self.viewController = aController;
}
return self;
}
里面利用了判断2个view是否有superview来获得当前view是否在显示状态中,不错的方法!
- (void)flipAction:(id)sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:kTransitionDuration];
[UIView setAnimationTransition:([levelView superview] ? UIViewAnimationTransitionFlipFromLeft : UIViewAnimationTransitionFlipFromRight) forView:self.view cache:YES];
if ([calibrationView superview]) {
[calibrationView removeFromSuperview];
[self.view addSubview:levelView];
} else {
[levelView removeFromSuperview];
[calibrationView resetToInitialState:self];
[self.view addSubview:calibrationView];
}
[UIView commitAnimations];
}
5.音乐播放
初始化音乐文件,一共三种音效,分别代表水平偏离位置的远,近,中
NSBundle *mainBundle = [NSBundle mainBundle];
farSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"farSound" ofType:@"caf"]];
nearSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"nearSound" ofType:@"caf"]];
levelSound = [[SoundEffect alloc] initWithContentsOfFile:[mainBundle pathForResource:@"levelSound" ofType:@"caf"]];
调用方法,例子中根据一个参数,判断距离,从而决定播放的音效是哪个
- (void)updateLevelSoundForAngle:(float)angle {
float absAngle = fabs(angle);
if (absAngle <= kMaxVariationForLevelSound) {
[levelSound play];
} else if (absAngle <= kMaxVariationForNearSound) {
[nearSound play];
} else if (absAngle <= kMaxVariationForFarSound) {
[farSound play];
}
}
实际调用方法,可以看到增加了一个控制变量,每10次才调用以此音乐播放,否则太过频繁
soundUpdateCounter++;
if (soundUpdateCounter == 10) { // update sound at a tenth the rate of the animation
[self updateLevelSoundForAngle:rotation];
soundUpdateCounter = 0;
}