IOS_加速计_碰撞检测_小球位置修复_dispatch_once单例

H:/0802/01_accelerometer加速计+小球碰撞检测_ViewController.h
//
//  ViewController.h
//  加速计01-演练1
//
//  Created by apple on 13-8-2.
//  Copyright (c) 2013年 itcast. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UIAccelerometerDelegate>

// 模拟小球视图
@property (weak, nonatomic) IBOutlet UIView *ballView;

@end

H:/0802/01_accelerometer加速计+小球碰撞检测_ViewController.m
//  ViewController.m
//  加速计01-演练1
//  Created by apple on 13-8-2.
//  Copyright (c) 2013年 itcast. All rights reserved.
// 千万注意:在加速计坐标系中Y轴方向和UIKit坐标系中的Y轴方向是相反的。!!!!!!

#import "ViewController.h"
@interface ViewController ()
{
    // 小球速度
    CGPoint     _ballVelocity;
}
@end
@implementation ViewController
- (void)viewDidLoad

 {   [super viewDidLoad];
    // 1. 初始化小球速度为0,让小球初始状态是静止的
    _ballVelocity = CGPointZero;
    // 1. 实例化引用共享的加速计对象(单例UIAccelerometer)
	// 注意:非常耗电,用完要释放
    UIAccelerometer *acce = [UIAccelerometer sharedAccelerometer];
    // 2. 设置更新时间间隔,即频率,单位:赫兹HZ
    [acce setUpdateInterval:1.0 / 30.0];
    // 3. 设置加速计代理为当前控制器<UIAccelerometerDelegate>
    [acce setDelegate:self];
}
#pragma mark - 加速计方法
// 更新小球的位置
- (void)updateBallLocation
{
    // 需求驱动开发
    // 1. 碰撞检测,要限制住小球的运动范围
    // 首先取出小球的当前位置
    CGPoint center = [_ballView center];
    // 需要记录一个小球的半径,以便于后续的碰撞检测计算
    CGFloat r = _ballView.frame.size.width / 2;
    // 需要考虑哪些问题
    // 1.1 考虑水平方向小球的位置	
    if (center.x < r) {
		// 判断是不是碰到屏幕最左边,翻转x方向速度,即反弹向右运动
        // 模拟弹性衰减,速度*0.8
        _ballVelocity.x = 0.8 * abs(_ballVelocity.x);
    } else if (center.x > self.view.bounds.size.width - r) {
		// 判断是不是碰到屏幕最右边,翻转x方向速度,即反弹向左运动
        //模拟弹性衰减 速度*0.8
        _ballVelocity.x = -0.8 * abs(_ballVelocity.x);
    }
    // 1.2 考虑垂直方向的小球位置
    if (center.y < r) {
		// 判断是不是碰到屏幕最顶边,翻转y方向速度,即反弹向下运动
        // 模拟弹性衰减,速度*0.8
        _ballVelocity.y = 0.8 * abs(_ballVelocity.y);
    } else if (center.y > self.view.bounds.size.height - r) {
		// 判断是不是碰到屏幕最底边,翻转y方向速度,即反弹向上运动
        // 模拟弹性衰减,速度*0.8
        _ballVelocity.y = -0.8 * abs(_ballVelocity.y);
    }
    // 2. 通过变化后的速度,设置小球最新的位置
    // 用小球当前的位置+速度变化就可以计算出新的位置了
//    CGPoint center = [_ballView center];
    [_ballView setCenter:CGPointMake(center.x + _ballVelocity.x,
					center.y + _ballVelocity.y)];
}
// 加速计代理方法,每隔指定频率,就会调用
- (void)accelerometer:(UIAccelerometer *)accelerometer
				didAccelerate:(UIAcceleration *)acceleration
{
	/*acceleration加速对象包含:x,y,z和timestamp四个属性,
	其中x,y,z是设备在这三个方向上的重力加速度,单位g,最后一个极少用*/
    // 通过NSLog我们得到了加速计的数据,下面要做的仅是变化小球位置
    NSLog(@"%@", acceleration);
    // 1. 加速计过来的数据是加速度,加速度是修改速度的,因此,需要定义一个小球的速度
    //    通过加速计的数据,更新小球速度的变化数值
    _ballVelocity.x += acceleration.x;
    // 千万注意:在加速计坐标系中Y轴方向和UIKit坐标系中的Y轴方向是相反的。!!!!!!
    _ballVelocity.y -= acceleration.y;
	// 调用自定义方法更新小球位置
    [self updateBallLocation];
}
@end

H:/0802/02_MotionManager+小球位置修复+碰撞检测_ViewController.h
//
//  ViewController.h
//  加速计02.CoreMotion Push演练
//
//  Created by apple on 13-8-2.
//  Copyright (c) 2013年 itcast. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

// 模拟小球视图
@property (weak, nonatomic) IBOutlet UIView *ballView;

@end

H:/0802/02_MotionManager+小球位置修复+碰撞检测_ViewController.m
//  ViewController.m
//  加速计02.CoreMotion Push演练
//  Created by apple on 13-8-2.
//  Copyright (c) 2013年 itcast. All rights reserved.
// 注意重点问题,小球会贴在屏幕边上
// 原因是碰到屏幕的瞬间,可能已经超出屏幕一点点了
// 而此时没有重力,而加速度又特别小的时候,即速度*0.8也很小,
// 不足以抵消小球嵌入屏幕外边的距离时,这时,小球新的坐标,仍然在屏幕外边,
// 最终导致小球嵌在槽里面,出不来了
// 此时,需要手动做一个小球位置的修复!
#import "ViewController.h"
// 需要导入第3方框架
#import <CoreMotion/CoreMotion.h>
@interface ViewController ()
{
    // 运动管理器,必须是成员变量,不能是局部变量
    CMMotionManager *motionManger;
    // 小球速度
    CGPoint _ballVelocity;
}
@end
@implementation ViewController
// 更新小球的位置
- (void)updateBallLocation
{
    // 需求驱动开发
    // 1. 碰撞检测,要限制住小球的运动范围
    // 首先取出小球的当前位置
    CGPoint center = [_ballView center];
    // 需要记录一个小球的半径,以便于后续的碰撞检测计算
    CGFloat r = _ballView.frame.size.width / 2;
	NSLog(@"小球的中心点---%@", NSStringFromCGPoint(center));
    NSLog(@"速度---%@", NSStringFromCGPoint(_ballVelocity));
    // 注意重点问题,小球会贴在屏幕边上
	// 原因是碰到屏幕的瞬间,可能已经超出屏幕一点点了
	// 而此时没有重力,而加速度又特别小的时候,即速度*0.8也很小,
	// 不足以抵消小球嵌入屏幕外边的距离时,这时,小球新的坐标,仍然在屏幕外边,
	// 最终导致小球嵌在槽里面,出不来了
	// 此时,需要手动做一个小球位置的修复!
    if (center.x < r) {
		// 判断是不是碰到屏幕最左边,翻转x方向速度,即反弹向右运动
        // 模拟弹性衰减,速度*0.8
        _ballVelocity.x = 0.8 * abs(_ballVelocity.x);
        // 修复小球位置
        center.x = r;
    } else if (center.x > self.view.bounds.size.width - r) {
		// 判断是不是碰到屏幕最右边,翻转x方向速度,即反弹向左运动
        // 模拟弹性衰减,速度*0.8
        _ballVelocity.x = -0.8 * abs(_ballVelocity.x);
        // 修复小球位置
        center.x = self.view.bounds.size.width - r;
    }
    if (center.y < r) {
		// 判断是不是碰到屏幕最顶边,翻转y方向速度,即反弹向下运动
        // 模拟弹性衰减,速度*0.8
        _ballVelocity.y = 0.8 * abs(_ballVelocity.y);
        center.y = r;
    } else if (center.y > self.view.bounds.size.height - r) {
		// 判断是不是碰到屏幕最底边,翻转y方向速度,即反弹向上运动
        // 模拟弹性衰减,速度*0.8
        _ballVelocity.y = -0.8 * abs(_ballVelocity.y);
        center.y = self.view.bounds.size.height - r;
    }
    // 2. 通过变化后的速度,设置小球最新的位置
    //    用小球当前的位置+速度变化就可以计算出新的位置了
    //    CGPoint center = [_ballView center];
    [_ballView setCenter:CGPointMake(center.x + _ballVelocity.x,
							center.y + _ballVelocity.y)];
    CGFloat x = center.x + _ballVelocity.x;
    CGFloat y = center.y + _ballVelocity.y;
    NSLog(@"更新的小球的中心点---%@", NSStringFromCGPoint(CGPointMake(x, y)));
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    //    1. alloc init实例化Motion管理器
    motionManger = [[CMMotionManager alloc]init];
    //    2. 判断加速度传感器是否可用
    if ([motionManger isAccelerometerAvailable]) {
        //    3. 设定传感器数据更新频率
        //    传感器目前最大采集频率是 100 Hz,而显示屏的刷新是60HZ
        [motionManger setAccelerometerUpdateInterval:1 / 30];
        //    4. startAccelerometerUpdatesToQueue
		//	开启加速传感器更新到主线程队列以,Push方式,通过block指定更新Handle
        [motionManger startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue]
				withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
            // 注意:这里如果直接Log,是不会有反应的,需要使用一下Data,才会有反应
            // 更新小球速度
            // 根据运行情况,加速度数值实在太大,我们需要修正一下
            _ballVelocity.x += accelerometerData.acceleration.x / 10;
			// 加速计的Y轴与UI的坐标中Y轴相反
            _ballVelocity.y -= accelerometerData.acceleration.y / 10;            
            CGPoint a = CGPointMake(accelerometerData.acceleration.x / 10,
								-accelerometerData.acceleration.y / 10);
            NSLog(@"加速度---%@", NSStringFromCGPoint(a));
            //[_ballView setCenter:CGPointMake(_ballView.center.x + _ballVelocity.x,
								//_ballView.center.y + _ballVelocity.y)];
			// 调用自定义方法,更新小球位置,(需做碰撞检测)
            [self updateBallLocation];
        }];
    } else {
        NSLog(@"没有传感器");
    }
}
@end

H:/0802/03_dispatch_once生成CMMotionManager单例+小球位置修正+碰撞检测_AppDelegate.h
//  AppDelegate.h
//  加速计02.CoreMotion Push演练
//  Created by apple on 13-8-2.
//  Copyright (c) 2013年 itcast. All rights reserved.

#import <UIKit/UIKit.h>
//需要导入第3方框架
#import <CoreMotion/CoreMotion.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

// 单例,共享的运动管理器,定义在AppDelegate里面,保证所有controller都能用
@property (strong, nonatomic, readonly) CMMotionManager *sharedMotionManager;

@end

H:/0802/03_dispatch_once生成CMMotionManager单例+小球位置修正+碰撞检测_AppDelegate.m
//  AppDelegate.m
//  加速计02.CoreMotion Push演练
//  Created by apple on 13-8-2.
//  Copyright (c) 2013年 itcast. All rights reserved.
//  dispatch_once生成CMMotionManager单例模板代码
#import "AppDelegate.h"
@interface AppDelegate()
{
    CMMotionManager *_montionManager;
}
@end
@implementation AppDelegate

#pragma mark - 成员变量sharedMotionManager的Getter方法,返回创建的运动管理器单例
// 单例,共享的运动管理器,定义在AppDelegate里面,保证所有controller都能用
- (CMMotionManager *)sharedMotionManager
{
    // 重点!!!!!!!!直接打dispatch_one定义单例
	//静态的泛型,自动生成,做标记用
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _montionManager = [[CMMotionManager alloc]init];
    });
    return _montionManager;
}





- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}
							
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
@end

H:/0802/03_dispatch_once生成CMMotionManager单例+小球位置修正+碰撞检测_ViewController.h
//
//  ViewController.h
//  加速计02.CoreMotion Push演练
//
//  Created by apple on 13-8-2.
//  Copyright (c) 2013年 itcast. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

// 模拟小球视图
@property (weak, nonatomic) IBOutlet UIView *ballView;

@end

H:/0802/03_dispatch_once生成CMMotionManager单例+小球位置修正+碰撞检测_ViewController.m
//  ViewController.m
//  加速计02.CoreMotion Push演练
//  Created by apple on 13-8-2.
//  Copyright (c) 2013年 itcast. All rights reserved.
/*
	已经在AppDelegate.h文件中导入了第3方框架<CoreMotion/CoreMotion.h>
	使用到AppDelegate.m文件中dispatch_once代码生成的单例 _montionManager
*/
#import "ViewController.h"
#import "AppDelegate.h"
@interface ViewController ()
{
    // 运动管理器
    CMMotionManager *motionManger;
    // 小球速度
    CGPoint _ballVelocity;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    //    1. 获取AppDelegate中定义的运动管理器实例
    AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
    motionManger = [appDelegate sharedMotionManager];
    [self startAccelerometer];
}

// 自定义,启动加速计方法,从ViewDidLoad方法中抽取
- (void)startAccelerometer
{
    //    2. 判断传感器是否可用
    if ([motionManger isAccelerometerAvailable]) {
        //    3. 设定传感器数据更新频率
        //    传感器目前最大采集频率是 100 Hz
        [motionManger setAccelerometerUpdateInterval:1 / 30];
        //    4. 启动传感器更新,Push方式更新数据
        [motionManger startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue]
					withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
            // 注意:这里如果直接Log,是不会有反应的,需要使用一下Data,才会有反应
            // 更新小球速度
            // 根据运行情况,加速度数值实在太大,我们需要修正一下
            _ballVelocity.x += accelerometerData.acceleration.x / 10;
            _ballVelocity.y -= accelerometerData.acceleration.y / 10;
            //加速度 打印一下
            CGPoint a = CGPointMake(accelerometerData.acceleration.x / 10,
									-accelerometerData.acceleration.y / 10);
            NSLog(@"加速度---%@", NSStringFromCGPoint(a));
            
            // 更新小球位置
            // 需要做一个碰撞检测
            //            [_ballView setCenter:CGPointMake(_ballView.center.x + _ballVelocity.x,
								//_ballView.center.y + _ballVelocity.y)];
			//调用 自定义方法,更新小球位置
            [self updateBallLocation];
        }];
    } else {
        NSLog(@"没有传感器");
    }
}


// 自定义方法,更新小球的位置
- (void)updateBallLocation
{
    // 需求驱动开发
    // 1. 碰撞检测,要限制住小球的运动范围
    // 首先取出小球的当前位置
    CGPoint center = [_ballView center];
    // 需要记录一个小球的半径,以便于后续的碰撞检测计算
    CGFloat r = _ballView.frame.size.width / 2;
	NSLog(@"小球的中心点---%@", NSStringFromCGPoint(center));
    NSLog(@"速度---%@", NSStringFromCGPoint(_ballVelocity));
	
    // 注意重点问题,小球会贴在屏幕边上
	// 原因是碰到屏幕的瞬间,可能已经超出屏幕一点点了
	// 而此时没有重力,而加速度又特别小的时候,即速度*0.8也很小,
	// 不足以抵消小球嵌入屏幕外边的距离时,这时,小球新的坐标,仍然在屏幕外边,
	// 最终导致小球嵌在槽里面,出不来了
	// 此时,需要手动做一个小球位置的修复!
    if (center.x < r) {
        // 翻转x方向速度
        _ballVelocity.x = 0.8 * abs(_ballVelocity.x);
        // 修复小球位置
        center.x = r;
    } else if (center.x > self.view.bounds.size.width - r) {
        _ballVelocity.x = -0.8 * abs(_ballVelocity.x);
        // 修复小球位置
        center.x = self.view.bounds.size.width - r;
    }
    // 1.2 考虑垂直方向的小球位置
    if (center.y < r) {
        _ballVelocity.y = 0.8 * abs(_ballVelocity.y);
		// 修复小球位置
        center.y = r;
    } else if (center.y > self.view.bounds.size.height - r) {
        _ballVelocity.y = -0.8 * abs(_ballVelocity.y);
		// 修复小球位置
        center.y = self.view.bounds.size.height - r;
    }
//    
//    NSLog(@"小球的中心点---%@", NSStringFromCGPoint(center));
//    NSLog(@"速度---%@", NSStringFromCGPoint(_ballVelocity));
    // 2. 通过变化后的速度,设置小球最新的位置
    // 用小球当前的位置+速度变化就可以计算出新的位置了
    [_ballView setCenter:CGPointMake(center.x + _ballVelocity.x, center.y + _ballVelocity.y)];
    CGFloat x = center.x + _ballVelocity.x;
    CGFloat y = center.y + _ballVelocity.y;
    NSLog(@"更新的小球的中心点---%@", NSStringFromCGPoint(CGPointMake(x, y)));
}


#pragma mark - 点击屏幕,让小球停止
// 1. 触摸事件 Began事件,需要终端加速计的数据采集工作
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 判断加速计是否在采集数据
    // 如果是在采集,我们需要把加速计停止
    if ([motionManger isAccelerometerActive]) {
        [motionManger stopAccelerometerUpdates];
    } else {
		// 调用自定义的启动加速计方法
        [self startAccelerometer];
    }
}
@end

你可能感兴趣的:(单例,ios,Dispatch,CoreMotion,once,加速计)