作者簡(jiǎn)介
科科香,程序員
方向:IoT浓体,方案集成,喜好各種新鮮東東
轉(zhuǎn)載請(qǐng)注明出處
iBeacon簡(jiǎn)介
iBeacon(下面簡(jiǎn)稱Beacon)是Apple在2013年9月發(fā)布的基于iOS7(及以上)的新功能坝辫。其工作方式是,配備有低功耗藍(lán)牙(BLE)通信功能的使用BLE技術(shù)向周圍發(fā)送自己特有的ID弟翘,接收到該ID的應(yīng)用軟件會(huì)根據(jù)該ID采取一些行動(dòng)。
WWDC 14 之后骄酗,對(duì) iBeacon 加大了基數(shù)支持和對(duì)其用于室內(nèi)地圖的應(yīng)用有個(gè)更明確的規(guī)劃稀余。蘋果公司公布了 iBeacon for Developers和 Maps for Developers等專題頁面。
想要了解iBeacon的更多信息趋翻,見維基百科睛琳。
游戲簡(jiǎn)介
將iBeacon設(shè)備作為需要尋找的寶物,隱藏于各個(gè)地方踏烙,玩家需要安裝上開發(fā)的app师骗,帶著手機(jī)找尋寶物,集齊寶物讨惩,獲取獎(jiǎng)勵(lì)辟癌,游戲演示視頻。
Here We Go!
介紹完了背景步脓,進(jìn)入正題愿待,如何制作這款游戲浩螺?
首先靴患,你需要購入Beacon設(shè)備(這個(gè)游戲是尋找龍珠主題,所以買了7個(gè)要出,什么牌子不說了鸳君,有廣告嫌疑)。淘寶上可以搜到很多Beacon賣家患蹂。
Beacon準(zhǔn)備好之后或颊,開始開發(fā),這款游戲只做了iOS版本传于。
創(chuàng)建項(xiàng)目
在Xcode中創(chuàng)建項(xiàng)目囱挑,選擇Simple View項(xiàng)目。輸入名稱dragonball-safari和組織名稱沼溜。
導(dǎo)入CoreLocation.framework平挑。
創(chuàng)建好項(xiàng)目并添加完庫之后,需要?jiǎng)h除ViewController.h和ViewController.m兩個(gè)文件系草。并且添加幾個(gè)新的項(xiàng)目文件:
- TabBarViewController.h
- TabBarViewController.m
- SafariViewController.h
- SafariViewController.m
- PickerViewController.h
- PickerViewController.m
整個(gè)項(xiàng)目結(jié)構(gòu)如下:
在模擬器上運(yùn)行項(xiàng)目通熄,效果如下。因?yàn)楝F(xiàn)在沒有添加任何的視圖元素找都,所以是一個(gè)黑屏唇辨。
界面
本文主要介紹如何應(yīng)用iBeacon技術(shù),界面工作在此不做介紹能耻。下圖是最后需要展示的界面赏枚。
上述的所有源代碼在此下載亡驰。
尋找龍珠
下載好上述的項(xiàng)目工程,并打開項(xiàng)目運(yùn)行饿幅,你會(huì)得到上面展示的界面隐解。下面,我們開始添加iBeacon的部分诫睬,讓整個(gè)游戲開始正常運(yùn)行煞茫。
開始之前,有幾個(gè)地方先說明一下摄凡。
硬件準(zhǔn)備
我用的是BrightBeacon的產(chǎn)品(好吧续徽,還是說了廠家,不過選擇其他廠家產(chǎn)品也沒有影響亲澡,Beacon的接口和屬性都是通用的钦扭,這是因?yàn)锳pple做了規(guī)范),一共買了7個(gè),需要把7個(gè)Beacon的Minor值設(shè)置成從1到7床绪,分別代表七顆龍珠客情。否則無法進(jìn)行游戲。
SDK
因?yàn)橛玫腂rightBeacon的產(chǎn)品癞己,所以直接用的他們提供的SDK膀斋。
下載并將他的SDK和include文件引入項(xiàng)目工程中,如下圖痹雅。
準(zhǔn)備工作做完之后仰担,下面開始進(jìn)行編碼。
打開AppDelegate.m文件绩社,引入BRTBeaconSDK.h文件和UserDefaultTool.h文件摔蓝。自定義一個(gè)用于SDK的App Key。這個(gè)key需要在BrightBeacon的官方網(wǎng)站上申請(qǐng)愉耙。
#import "BRTBeaconSDK.h"
#import "UserDefaultTool.h"
之后注冊(cè)app贮尉,并進(jìn)行初始化工作。UserDefaultTool這個(gè)文件是預(yù)先寫好的朴沿,用于控制龍珠的查找和初始化工作猜谚。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[BRTBeaconSDK registerApp:BRT_SDK_KEY onCompletion:^(NSError *error) {
NSLog(@"%@", error.description);
}];
[UserDefaultTool initUserDefaultData];
return YES;
}
完成這一步之后,運(yùn)行一下悯仙。在模擬器中龄毡,App會(huì)告知用戶需要訪問用戶的地理位置信息,如果沒有打開藍(lán)牙的話锡垄,也會(huì)提示用戶打開藍(lán)牙沦零。是不是很有意思:)
注冊(cè)好應(yīng)用之后,下面開始監(jiān)測(cè)Beacon吧货岭。
在SafariViewController.m里面路操,依次加入這些方法疾渴。
- (void)startToFindBeacons{
[BRTBeaconSDK startRangingWithUuids:@[[[NSUUID alloc] initWithUUIDString:DEFAULT_UUID]] onCompletion:^(NSArray *beacons, BRTBeaconRegion *region, NSError *error){
if (!error) {
[self reloadData:beacons];
}
}];
}
- (void)reloadData:(NSArray *)beacons{
self.beacons = beacons;
[self.dragonBallTableView reloadData];
[self setTopViewData];
[self checkFoundBall];
}
// 監(jiān)控選擇龍珠的距離
-(void)setTopViewData
{
self.topViewBeacon = nil;
if (self.beacons.count > 0) {
for (BRTBeacon * beacon in self.beacons) {
if ([beacon.minor longValue] == self.nowRow + 1) {
self.topViewBeacon = beacon;
}
}
}
[self setTopViewDistance];
}
- (void)setTopViewDistance{
if (self.topViewBeacon == nil) {
self.distanceLaber.text = @"? ? ?";
}else
{
self.distanceLaber.text = ([self.topViewBeacon.distance floatValue] > 10) ? @">10m" : [NSString stringWithFormat:@"%.1f m",[self.topViewBeacon.distance floatValue]];
}
}
// 找到龍珠
-(void)checkFoundBall
{
for (BRTBeacon* beacon in self.beacons) {
if ([beacon.distance floatValue] < 0.3) {
NSMutableArray* array = [UserDefaultTool nowFoundBallsMutableArray];
if ([[array objectAtIndex:[beacon.minor intValue] - 1] isEqual:@(0)]) {
[array setObject:@(1) atIndexedSubscript:[beacon.minor intValue] - 1];
[UserDefaultTool setUserDefaultDataWithArray:array];
[self AfterFindABallCallBack:[beacon.minor intValue]];
}
}
}
}
-(void)AfterFindABallCallBack:(int)minor
{
if ([UserDefaultTool nowFoundBallsCount] == 7) {
//召喚神龍
// [self callTheDragon];
}else{
UIAlertView* alertView = [[UIAlertView alloc]initWithTitle:@"恭喜你" message:[NSString stringWithFormat:@"找到%d星球啦",minor] delegate:nil cancelButtonTitle:@"好的" otherButtonTitles:nil, nil];
[alertView show];
}
}
并在viewDidLoad中調(diào)用startToFindBeacons:
- (void)viewDidLoad {
…
// Start monitoring and ranging
[self startToFindBeacons];
[self setUpAudioPlay];
}
在DragonBallTableViewCell.m里面加入方法:
- (void)setBeacon:(BRTBeacon *)beacon{
[self setDistanceByBeacon:(BRTBeacon *)beacon];
}
- (void)setDistanceByBeacon:(BRTBeacon *)beacon{
NSArray* array = [UserDefaultTool nowFoundBallsArray];
if ([[array objectAtIndex:_rowNum-1] isEqual:@(1)]) {
//這個(gè)beacon已經(jīng)找到過
[self setDistanceLabelWithText:@"囊中之物" andColor:[UIColor greenColor]];
}else{
//沒找到過這個(gè)beacon
if(beacon == nil)
{
[self setDistanceLabelWithText:@"千里之外" andColor:[UIColor grayColor]];
}else{
if ([beacon.distance floatValue] < 2) {
[self setDistanceLabelWithText:@"一步之遙" andColor:kNearTextColor];
[self thereIsANearBeacon];
}else if([beacon.distance floatValue] < 6){
[self setDistanceLabelWithText:@"十步之遙" andColor:kNearTextColor];
}else{
[self setDistanceLabelWithText:@"百步之遙" andColor:kNearTextColor];
}
}
}
}
-(void)thereIsANearBeacon
{
if (!self.isShocked) {
//通知代理
if ([self.delegate respondsToSelector:@selector(CellDidCheckCloseToABall)]) {
[self.delegate CellDidCheckCloseToABall];
}
self.isShocked = 1;
}
}
完成在真機(jī)上運(yùn)行,就可以看到龍珠距離我們的位置并且可以找到它啦:)當(dāng)拿著一個(gè)Beacon靠近手機(jī)的時(shí)候屯仗,就會(huì)有下面的顯示了搞坝。看魁袜,游戲的雛形已經(jīng)出來了桩撮。
說明:這塊最關(guān)鍵的核心就是通過下面方法,來監(jiān)測(cè)Beacon峰弹,根據(jù)找到Beacon的距離信息店量,來判斷是否找到龍珠。這個(gè)方法默認(rèn)是每秒回調(diào)一次鞠呈。
[BRTBeaconSDK startRangingWithUuids: onCompletion:]
找到了龍珠之后融师,我們要在神龍碎片那里可以看到神龍的真面目。在PickerViewController.m中蚁吝,添加方法:
- (void)setUpCurrentDragonFragment{
self.dragonFragImages = @[_dragonFragImage1,
_dragonFragImage2,
_dragonFragImage3,
_dragonFragImage4,
_dragonFragImage5,
_dragonFragImage6,
_dragonFragImage7
];
NSArray* array = [UserDefaultTool nowFoundBallsArray];
for (int i = 0 ; i < array.count; i++) {
NSNumber* isFound = [array objectAtIndex:i];
UIImageView* dragonView = self.dragonFragImages[i];
if ([isFound isEqual:@(1)]) {
dragonView.hidden = NO;
}
}
}
并在viewDidLoad中調(diào)用:
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpCurrentDragonFragment];
}
這樣旱爆,在神龍碎片中就可以看到找到了多少碎片了。
完成游戲
游戲設(shè)定在最后窘茁,找到所有龍珠之后怀伦,神龍出現(xiàn)。現(xiàn)在讓我們完成最后一部分吧庙曙。
創(chuàng)建DragonMovieViewController文件空镜,召喚神龍。
#import "DragonMovieViewController.h"
#import <MediaPlayer/MediaPlayer.h>
@interface DragonMovieViewController ()
@property (nonatomic, strong) MPMoviePlayerController *movie;
@end
@implementation DragonMovieViewController
- (void)viewDidLoad {
self.view.backgroundColor = [UIColor whiteColor];
[self setUpMoviePlay];
}
-(void)setUpMoviePlay
{
//找到文件路徑
NSString* path = [[NSBundle mainBundle]pathForResource:@"dragon_appear" ofType:@"MP4"];
NSURL* url = [NSURL fileURLWithPath:path];
//
MPMoviePlayerController* movC = [[MPMoviePlayerController alloc]initWithContentURL:url];
movC.controlStyle = MPMovieControlStyleNone;
movC.scalingMode = MPMovieScalingModeAspectFill;
movC.view.frame=self.view.bounds;
[self.view addSubview:movC.view];
self.movie = movC;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dragonMovieFinished:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:movC];
[movC play];
}
-(void)dragonMovieFinished:(NSNotification *)notify
{
//視頻播放對(duì)象
MPMoviePlayerController* theMovie = [notify object];
//銷毀播放通知
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
[theMovie.view removeFromSuperview];
[self dismissViewControllerAnimated:YES completion:nil];
UIAlertView* alertView = [[UIAlertView alloc]initWithTitle:@"恭喜恭喜恭喜你" message:@"你已經(jīng)成功召喚神龍!" delegate:nil cancelButtonTitle:@"噢耶" otherButtonTitles:nil, nil];
[alertView show];
}
召喚神龍的地方準(zhǔn)備就緒捌朴,回到SafariViewController.m文件,引入DragonMovieViewController张抄,并在最后加上方法:
-(void)callTheDragon
{
DragonMovieViewController* dC = [[DragonMovieViewController alloc]init];
[self presentViewController:dC animated:YES completion:nil];
}
在AfterFindABallCallBack里面砂蔽,召喚神龍:
-(void)AfterFindABallCallBack:(int)minor
{
if ([UserDefaultTool nowFoundBallsCount] == 7) {
//召喚神龍
[self callTheDragon];
}else{
UIAlertView* alertView = [[UIAlertView alloc]initWithTitle:@"恭喜你" message:[NSString stringWithFormat:@"找到%d星球啦",minor] delegate:nil cancelButtonTitle:@"好的" otherButtonTitles:nil, nil];
[alertView show];
}
}
這樣整個(gè)游戲就完成了:)
趕快開始游戲吧,看看誰是召喚神龍的第一人署惯!
源代碼
整個(gè)項(xiàng)目的源代碼上傳到了我的github里面左驾,歡迎大家下載。
結(jié)語
這里的Beacon游戲只是物聯(lián)網(wǎng)應(yīng)用的一個(gè)初步嘗試极谊,還有很多應(yīng)用有待大家深挖和細(xì)挖诡右。如果你有更好的建議,也請(qǐng)給我留言轻猖。因?yàn)槭莻€(gè)人力量帆吻,不保證響應(yīng)速度但保證響應(yīng)質(zhì)量:)
下一篇文章準(zhǔn)備寫關(guān)于物聯(lián)網(wǎng)的一個(gè)實(shí)際應(yīng)用小demo。