描述:用CoreMontion加速计控制小球的运动,通过屏幕触摸,暂停和恢复。
步骤
1. 添加MontionManager和CADisplayLink
- (void)viewDidLoad
{
[super viewDidLoad];
// 添加小球
UIImage *image = [UIImage imageNamed:@"black"];
_ball = [[UIImageView alloc] initWithImage:image];
_ball.center = self.view.center;
[self.view addSubview:_ball];
_ballVelocity = CGPointZero;
_queue = [[NSOperationQueue alloc] init];
// 运动管理器方法
// 1) 实例化运动管理器
MyMontionManager *montionManager =
[MyMontionManager sharedMyMontionManager];
// 2) 判断加速计是否可用
if (montionManager.isAccelerometerAvailable) {
// 3) 设置采样数据的时间间隔
montionManager.accelerometerUpdateInterval = 1 / 60.0;
// 4)开始采样数据
[self startAccelerometerUpdates];
} else {
NSLog(@"摔坏了");
}
// 实例化游戏时钟 防止小球虚化显示 montionManager负责采集,CADisplayLink 负责显示
_gameTimer = [CADisplayLink displayLinkWithTarget:self
selector:@selector(updateLocation)];
// 将时钟添加到主运行循环中
[_gameTimer addToRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
}
2. 设置MontionManager单例,方便使用
static MyMontionManager *_instance;
@implementation MyMontionManager
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
+ (instancetype)sharedMyMontionManager
{
if (_instance == nil) {
_instance = [[MyMontionManager alloc] init];
}
return _instance;
}
@end
3. 采样方法
- (void)startAccelerometerUpdates
{
// 操作队列是负责处理采样的数据
[[MyMontionManager sharedMyMontionManager]
startAccelerometerUpdatesToQueue:_queue
withHandler:^(CMAccelerometerData *accelerometerData, NSError *error)
{
// 处理采样数据,修改小球速度
_ballVelocity.x += accelerometerData.acceleration.x;
_ballVelocity.y -= accelerometerData.acceleration.y;
NSLog(@"%@", [NSThread currentThread]);
}];
}
4. 更改小球位置、
- (void)updateLocation
{
NSLog(@"==== %@", [NSThread currentThread]);
// 设置小球的位置
CGPoint center = _ball.center;
CGSize size = self.view.bounds.size;
// 解决小球出界问题,碰撞检测
// 水平方向:左边,右边
if (CGRectGetMinX(_ball.frame) <= 0 || CGRectGetMaxX(_ball.frame) >= size.width) {
// 修改小球的速度方向
_ballVelocity.x *= -1;
// 修复位置 < 0
if (CGRectGetMinX(_ball.frame) <= 0) {
center.x = _ball.bounds.size.width / 2.0;
} else {
center.x = size.width - _ball.bounds.size.width / 2.0;
}
}
// 垂直方向
if (CGRectGetMinY(_ball.frame) <= 0 || CGRectGetMaxY(_ball.frame) >= size.height) {
// 修改小球的速度方向
_ballVelocity.y *= -1;
// 修复位置 < 0
if (CGRectGetMinY(_ball.frame) <= 0) {
center.y = _ball.bounds.size.height / 2.0;
} else {
center.y = size.height - _ball.bounds.size.height / 2.0;
}
}
center.x += _ballVelocity.x;
center.y += _ballVelocity.y;
_ball.center = center; //在mainloop中,所以不需要队列
}
5 触摸停止/启动
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 正在采样数据,说明游戏进行中,暂停
if ([MyMontionManager sharedMyMontionManager].isAccelerometerActive)
{
// 定制采样数据
[[MyMontionManager sharedMyMontionManager] stopAccelerometerUpdates];
// 停止时钟
// invalidate停止时钟
// 1> 将时钟从主运行循环中撤销
// 2> 将时钟销毁
// [_gameTimer invalidate];
// 直接从主运行循环中将游戏时钟删除,而不会销毁时钟,等到需要时再次添加即可。
[_gameTimer removeFromRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
} else {
// 开始采样加速计数据
[self startAccelerometerUpdates];
[_gameTimer addToRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
}
}