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