iOS简易蓝牙对战五子棋游戏设计思路之一——核心蓝牙通讯类的设计(二)

简介: iOS简易蓝牙对战五子棋游戏设计思路之一——核心蓝牙通讯类的设计

三、游戏中蓝牙通讯类的设计


  创建一个命名为BlueToothTool的工具类,作为游戏的蓝牙通讯类,编写其头文件如下:


BlueToothTool.h


#import <Foundation/Foundation.h>

#import <UIKit/UIKit.h>

#import <CoreBluetooth/CoreBluetooth.h>

//这个代理用于处理接收到对方设备发送来的数据后的回调

@protocol BlueToothToolDelegate <NSObject>

//获取对方数据

-(void)getData:(NSString *)data;

@end


@interface BlueToothTool : NSObject<CBPeripheralManagerDelegate,CBCentralManagerDelegate,CBPeripheralDelegate,UIAlertViewDelegate>

//代理

@property(nonatomic,weak)id<BlueToothToolDelegate>delegate;

//标记是否是游戏中的房主

@property(nonatomic,assign)BOOL isCentral;

/**

*获取单例对象的方法

*/

+(instancetype)sharedManager;

/*

*作为游戏的房主建立游戏房间

*/

-(void)setUpGame:(NSString *)name block:(void(^)(BOOL first))finish;

/*

*作为游戏的加入者查找附近的游戏

*/

-(void)searchGame;

/**

*断块连接

*/

-(void)disConnect;

/*

*进行写数据操作

*/

-(void)writeData:(NSString *)data;

@end


实现BlueToothTool.m文件如下:


#import "BlueToothTool.h"

@implementation BlueToothTool

{

   //外设管理中心

   CBPeripheralManager * _peripheralManager;

   //外设提供的服务

   CBMutableService * _ser;

   //服务提供的读特征值

   CBMutableCharacteristic * _readChara;

   //服务提供的写特征值

   CBMutableCharacteristic * _writeChara;

   //等待对方加入的提示视图

   UIView * _waitOtherView;

   //正在扫描附近游戏的提示视图

   UIView * _searchGameView;

   //设备中心管理对象

   CBCentralManager * _centerManger;

   //要连接的外设

   CBPeripheral * _peripheral;

   //要交互的外设属性

   CBCharacteristic * _centerReadChara;

   CBCharacteristic * _centerWriteChara;

   //开始游戏后的回调 告知先手与后手信息

   void(^block)(BOOL first);

}

//实现单例方法

+(instancetype)sharedManager{

   static BlueToothTool *tool = nil;

   static dispatch_once_t predicate;

   dispatch_once(&predicate, ^{

       tool = [[self alloc] init];

   });

   return tool;

}

//实现创建游戏的方法

-(void)setUpGame:(NSString *)name block:(void (^)(BOOL))finish{

   block = [finish copy];

   if (_peripheralManager==nil) {

       //初始化服务

        _ser= [[CBMutableService alloc]initWithType:[CBUUID UUIDWithString:@"68753A44-4D6F-1226-9C60-0050E4C00067"] primary:YES];

       //初始化特征

       _readChara = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:@"68753A44-4D6F-1226-9C60-0050E4C00067"] properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];

       _writeChara = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:@"68753A44-4D6F-1226-9C60-0050E4C00068"] properties:CBCharacteristicPropertyWriteWithoutResponse value:nil permissions:CBAttributePermissionsWriteable];

       //向服务中添加特征

       _ser.characteristics = @[_readChara,_writeChara];

       _peripheralManager = [[CBPeripheralManager alloc]initWithDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];

   }

   //设置为房主

   _isCentral=YES;

   //开始广播广告

   [_peripheralManager startAdvertising:@{CBAdvertisementDataLocalNameKey:@"WUZIGame"}];

}

//外设检测蓝牙状态

-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{

   //判断是否可用

   if (peripheral.state==CBPeripheralManagerStatePoweredOn) {

       //添加服务

       [_peripheralManager addService:_ser];

       //开始广播广告

       [_peripheralManager startAdvertising:@{CBAdvertisementDataLocalNameKey:@"WUZIGame"}];

   }else{

       //弹提示框

       dispatch_async(dispatch_get_main_queue(), ^{

       [self showAlert];

       });

   }

}

//开始放广告的回调

-(void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error{

   if (_waitOtherView==nil) {

       _waitOtherView = [[UIView alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-100, 240, 200, 100)];

       dispatch_async(dispatch_get_main_queue(), ^{

       UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 100)];

       label.backgroundColor = [UIColor clearColor];

       label.textAlignment = NSTextAlignmentCenter;

       label.text = @"等待附近玩家加入";

       [_waitOtherView addSubview:label];

       _waitOtherView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4];

           [[[UIApplication sharedApplication].delegate window]addSubview:_waitOtherView];

       });


   }else{

       dispatch_async(dispatch_get_main_queue(), ^{

           [_waitOtherView removeFromSuperview];

           [[[UIApplication sharedApplication].delegate window]addSubview:_waitOtherView];

       });

   }

}



//添加服务后回调的方法

-(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{

   if (error) {

       NSLog(@"添加服务失败");

   }

   NSLog(@"添加服务成功");

}


//中心设备订阅特征值时回调

-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic{

   [_peripheralManager stopAdvertising];

   if (_isCentral) {

       UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"" message:@"请选择先手后手" delegate:self cancelButtonTitle:@"我先手" otherButtonTitles:@"我后手", nil];

       dispatch_async(dispatch_get_main_queue(), ^{

           [_waitOtherView removeFromSuperview];

           [alert show];

       });

   }

}

//收到写消息后的回调

-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests{

   dispatch_async(dispatch_get_main_queue(), ^{

       [self.delegate getData:[[NSString alloc]initWithData:requests.firstObject.value encoding:NSUTF8StringEncoding]];

   });

}

//弹提示框的方法

-(void)showAlert{

   UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"温馨提示" message:@"请确保您的蓝牙可用" delegate:nil cancelButtonTitle:@"好的" otherButtonTitles:nil, nil];

   [alert show];

}

//===============================================================作为游戏加入这实现的方法========

//搜索周围游戏

-(void)searchGame{

   if (_centerManger==nil) {

       _centerManger = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];

   }else{

       [_centerManger scanForPeripheralsWithServices:nil options:nil];

       if (_searchGameView==nil) {

           _searchGameView = [[UIView alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-100, 240, 200, 100)];

           UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 100)];

           label.backgroundColor = [UIColor clearColor];

           label.textAlignment = NSTextAlignmentCenter;

           label.text = @"正在扫加入描附近游戏";

           _searchGameView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4];

           [_searchGameView addSubview:label];

           [[[UIApplication sharedApplication].delegate window]addSubview:_searchGameView];

       }else{

           [_searchGameView removeFromSuperview];

           [[[UIApplication sharedApplication].delegate window]addSubview:_searchGameView];

       }

   }

   //设置为游戏加入方

   _isCentral = NO;

}

//设备硬件检测状态回调的方法 可用后开始扫描设备

-(void)centralManagerDidUpdateState:(CBCentralManager *)central{

   if (_centerManger.state==CBCentralManagerStatePoweredOn) {

       [_centerManger scanForPeripheralsWithServices:nil options:nil];

       if (_searchGameView==nil) {

            dispatch_async(dispatch_get_main_queue(), ^{

           _searchGameView = [[UIView alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2-100, 240, 200, 100)];

           UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 100)];

           label.backgroundColor = [UIColor clearColor];

           label.textAlignment = NSTextAlignmentCenter;

           label.text = @"正在扫加入描附近游戏";

           _searchGameView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4];

           [_searchGameView addSubview:label];

                [[[UIApplication sharedApplication].delegate window]addSubview:_searchGameView];

            });

       }else{

         

           dispatch_async(dispatch_get_main_queue(), ^{

               [_searchGameView removeFromSuperview];

               [[[UIApplication sharedApplication].delegate window]addSubview:_searchGameView];

           });

       }

   }else{

        dispatch_async(dispatch_get_main_queue(), ^{

       [self showAlert];

        });

   }

}

//发现外设后调用的方法

-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{

   //获取设备的名称 或者广告中的相应字段来配对

   NSString * name = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];

   if ([name isEqualToString:@"WUZIGame"]) {

       //保存此设备

       _peripheral = peripheral;

       //进行连接

       [_centerManger connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES}];

   }

}

//连接外设成功的回调

-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{

   NSLog(@"连接成功");

   //设置代理与搜索外设中的服务

   [peripheral setDelegate:self];

   [peripheral discoverServices:nil];

    dispatch_async(dispatch_get_main_queue(), ^{

        [_searchGameView removeFromSuperview];

    });

}

//连接断开

-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{

   NSLog(@"连接断开");

   [_centerManger connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES}];

}

//发现服务后回调的方法

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{

   for (CBService *service in peripheral.services)

   {

       //发现服务 比较服务的UUID

       if ([service.UUID isEqual:[CBUUID UUIDWithString:@"68753A44-4D6F-1226-9C60-0050E4C00067"]])

       {

           NSLog(@"Service found with UUID: %@", service.UUID);

           //查找服务中的特征值

           [peripheral discoverCharacteristics:nil forService:service];

           break;

       }

     

   }

}

//开发服务中的特征值后回调的方法

-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{

   for (CBCharacteristic *characteristic in service.characteristics)

   {

       //发现特征 比较特征值得UUID 来获取所需要的

       if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"68753A44-4D6F-1226-9C60-0050E4C00067"]]) {

           //保存特征值

           _centerReadChara = characteristic;

           //监听特征值

           [_peripheral setNotifyValue:YES forCharacteristic:_centerReadChara];

       }

       if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"68753A44-4D6F-1226-9C60-0050E4C00068"]]) {

           //保存特征值

           _centerWriteChara = characteristic;

       }

   }

}

//所监听的特征值更新时回调的方法

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error

{

   //更新接收到的数据

   NSLog(@"%@",[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding]);

   //要在主线程中刷新

   dispatch_async(dispatch_get_main_queue(), ^{

       [self.delegate getData:[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding]];

   });

}


-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{

   //告诉开发者先后手信息

   if (buttonIndex==0) {

       if (_isCentral) {

           block(1);

       }else{

           block(0);

       }

   }else{

       if (_isCentral) {

           block(0);

       }else{

           block(1);

       }

   }

}

//断开连接

-(void)disConnect{

   if (!_isCentral) {

       [_centerManger cancelPeripheralConnection:_peripheral];

     [_peripheral setNotifyValue:NO forCharacteristic:_centerReadChara];

   }

}

//写数据

-(void)writeData:(NSString *)data{

   if (_isCentral) {

       [_peripheralManager updateValue:[data dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:_readChara onSubscribedCentrals:nil];

   }else{

       [_peripheral writeValue:[data dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:_centerWriteChara type:CBCharacteristicWriteWithoutResponse];

   }

}


@end


附录:游戏的源码已经放在git上,时间比较仓促,只用了一下午来写,其中还有许多细节与bug没有进行调整,有需要的可以作为参考:


git地址:https://github.com/ZYHshao/BlueGame

目录
相关文章
|
测试技术 程序员 C++
iOS:项目中无用类检测和无用图片检测汇总
在涉及到项目大改版,或者涉及到某个功能模块大变更,就会涉及到图片废弃和文件废弃的情况。 但是这时候就会遗留下一个很大的问题,没有将废弃的、无用的文件类或资源删除干净。而这次需要对工程代码的无用资源和无用文件进行删除处理,感触颇多,故在此笔记。 首先,感觉很多人的代码习惯还是恶待提高。比如我发现一些人的代码操作习惯,从好到次,可以大略分以下情况
1161 0
iOS:项目中无用类检测和无用图片检测汇总
|
缓存 安全 Linux
自建iOS构建流水线建设核心原理剖析
文章主要从iOS打包机远程构建的角度分析,整体链路脚本涉及的shell、ruby、security指令、xml以及iOS工程化相关知识,文章通过一个远程构建流程简单并重点的讲解了如何规避本地打包环境下的小的修改出包存在的大量人工操作,如何动态化配置证书、版本号等信息以及内测分发方式的避坑点。
自建iOS构建流水线建设核心原理剖析
|
存储 缓存 安全
iOS-底层原理 35:组件化(二)组件间通讯方式
iOS-底层原理 35:组件化(二)组件间通讯方式
839 0
iOS-底层原理 35:组件化(二)组件间通讯方式
|
设计模式 编译器 C++
iOS-底层原理 19:类扩展 与 关联对象 底层原理探索
iOS-底层原理 19:类扩展 与 关联对象 底层原理探索
118 0
iOS-底层原理 19:类扩展 与 关联对象 底层原理探索
|
存储 iOS开发
iOS-底层原理 18:类的加载(下)
iOS-底层原理 18:类的加载(下)
114 0
iOS-底层原理 18:类的加载(下)
|
存储 缓存 算法
iOS-底层原理 17:类的加载(上)
iOS-底层原理 17:类的加载(上)
176 0
iOS-底层原理 17:类的加载(上)
|
存储 C++
iOS-底层原理 09:类 & isa 经典面试题分析
iOS-底层原理 09:类 & isa 经典面试题分析
144 0
iOS-底层原理 09:类 & isa 经典面试题分析
|
存储 编译器 C++
iOS-底层原理 08:类 & 类结构分析
iOS-底层原理 08:类 & 类结构分析
138 0
iOS-底层原理 08:类 & 类结构分析
|
存储 设计模式 编译器
iOS-底层原理 07:isa与类关联的原理
iOS-底层原理 07:isa与类关联的原理
100 0
iOS-底层原理 07:isa与类关联的原理
|
iOS开发 C++
iOS 类的加载分析 (中)
我们都知道iOS的整体机制是懒加载, 也是就是使用到, 再去加载, 不使用就释放掉来节省内存.
80 0