代碼沒有過多的進行封裝,只是先實現了基本的功能.一共才200多行代碼➕註釋--只是沒來得及集成音樂git
對於常常要用到的變量進行了宏定義數組
// // ViewController.m // PlayPinao // // Created by 裴波波 on 16/4/23. // Copyright © 2016年 裴波波. All rights reserved. // #import "ViewController.h" //屏幕寬度 #define kScreenW [UIScreen mainScreen].bounds.size.width //屏幕高度 #define kScreenH [UIScreen mainScreen].bounds.size.height //屏幕尺寸 #define kScreenB [UIScreen mainScreen].bounds #define kLineCount 4 //每行白塊個數 #define kCellCount 200 //白塊總個數 @interface ViewController () @property (weak, nonatomic) IBOutlet UICollectionViewFlowLayout *flowLayout; /** 存儲每一行的cell的可變數組 */ @property (nonatomic, strong) NSMutableArray *arrayM; /** 記錄取整索引 */ @property (nonatomic, assign) int idx; /** 初始狀態總體豎直偏移高度 */ @property (nonatomic, assign) CGFloat offsetTotal; /** 每一個cell高度 */ @property (nonatomic, assign) CGFloat itemH; /** 點擊黑塊計數器 */ @property (nonatomic, assign) int blackCount; /** 主界面view */ @property (nonatomic, strong) UIView *mainView; /** 秒錶計時器 */ @property (nonatomic, strong) NSTimer *timer; /** 顯示時間的label */ @property (nonatomic, strong) UILabel *lblTime; /** 累計用時 */ @property (nonatomic, assign) CGFloat useTime; /** 即將消失 */ @property (nonatomic, assign) int displayNum; @end
@implementation ViewController #pragma mark - 懶加載存儲每行cell的可遍數組 -(NSMutableArray *)arrayM{ if (_arrayM == nil) { _arrayM = [NSMutableArray array]; } return _arrayM; } #pragma mark - 數據源 -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return kCellCount; } -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath]; /** 綁定tag排序用----並無什麼用處 */ cell.tag = indexPath.item; /** 先統一設置cell背景色白色 */ cell.backgroundColor = [UIColor whiteColor]; /** 根據腳標每行隨機設置一個顏色爲黑色的cell */ /** 將每行的cell 4個存入可變數組,獲取隨機數0-3,根據隨機數取腳標讓其變黑 */ /** 將cell數組添加到可變數組 */ [self.arrayM addObject:cell]; /** 記錄索引 = 3的時候從中隨機選擇一個cell讓其背景色變 黑 */ if (self.idx == 3) { /** 產生的隨機腳標 */ int idxBlcak = arc4random_uniform(4); UICollectionViewCell * blackCell = self.arrayM[idxBlcak]; blackCell.backgroundColor = [UIColor blackColor]; } self.idx ++; //idx > 3 重置記錄索引 if (self.idx > 3) { self.idx = 0; //當重置idx的時候 令可變數組arrayM removeAllObject [self.arrayM removeAllObjects]; } return cell; }
#pragma mark - 代理 -(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell * cell = [collectionView cellForItemAtIndexPath:indexPath]; /** 點擊開始計時 */ if (self.timer == nil) { self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0/60 target:self selector:@selector(addTimeOfUserUse) userInfo:nil repeats:YES]; NSRunLoop * runloop = [NSRunLoop currentRunLoop]; [runloop addTimer:self.timer forMode:NSRunLoopCommonModes]; } /** 標記---奠定石系統執行方法didEndDisplayingCell時檢測漏掉的黑色 */ self.displayNum = 1; /** 判斷cell顏色爲黑色->變灰 cell爲白色 -> 變紅 */ /** 若是點擊到了黑塊計數 */ if (cell.backgroundColor == [UIColor blackColor]) { cell.tag = 99999; //此行沒有什麼卵用 cell.backgroundColor = [UIColor grayColor]; self.blackCount ++; } else { //點擊錯誤提示用戶點錯而且返回點擊黑色塊的數量 cell.backgroundColor = [UIColor redColor]; /** 彈出提示框 */ [self showClickError]; /** 中止計時器 */ [self.timer invalidate]; } /** 每次點擊黑色塊讓collectionView偏移 - 一個cell的高度 */ /** 滑動到頭髮生某個事件 */ if (self.collectionView.contentOffset.y == 0) { return; } //點擊滾動 [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:YES]; }
#pragma mark - 將要消失的cell -(void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{ if (cell.backgroundColor == [UIColor blackColor]) { if (self.displayNum == 1) { [self showClickError]; [self.timer invalidate]; self.displayNum = 0; } } }
#pragma mark - 累加時間,每秒執行60次 -(void)addTimeOfUserUse{ self.useTime += 1.0 / 60; } #pragma mark - 提示錯誤框 -(void)showClickError{ UIAlertController * alertVc = [UIAlertController alertControllerWithTitle:@"最終結果" message:[NSString stringWithFormat:@"成績是:%zd個",self.blackCount] preferredStyle:UIAlertControllerStyleAlert]; /** 肯定返回主界面 */ UIAlertAction * action = [UIAlertAction actionWithTitle:@"肯定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { self.lblTime.text = [NSString stringWithFormat:@"累計用時%f",self.useTime]; self.blackCount = 0; self.displayNum = 0; [UIView animateWithDuration:0.2 animations:^{ self.mainView.alpha = 1; }]; }]; [alertVc addAction:action]; [self presentViewController:alertVc animated:YES completion:nil]; }
- (void)viewDidLoad { [super viewDidLoad]; self.collectionView.backgroundColor = [UIColor blueColor]; /** 初始化佈局參數 */ [self initFlowLayout]; /** 初始化主界面 */ [self initMainView]; } #pragma mark - 初始化主界面 -(void)initMainView{ UIView * mainView = [[UIView alloc] initWithFrame:kScreenB]; self.mainView = mainView; mainView.backgroundColor = [UIColor orangeColor]; [self.view addSubview:mainView]; UIButton * button = [[UIButton alloc] init]; [button setTitle:@"進入" forState:UIControlStateNormal]; button.bounds = CGRectMake(0, 0, 50, 30); button.backgroundColor = [UIColor blackColor]; button.center = mainView.center; [mainView addSubview:button]; [button addTarget:self action:@selector(hideMainView) forControlEvents:UIControlEventTouchUpInside]; //顯示遊戲時長label UILabel * lblTime = [[UILabel alloc] init]; lblTime.frame = CGRectMake(0, 0, kScreenW, 200); self.lblTime = lblTime; lblTime.font = [UIFont systemFontOfSize:22]; lblTime.textAlignment = NSTextAlignmentCenter; [mainView addSubview:lblTime]; } #pragma mark - 隱藏主界面進入遊戲 -(void)hideMainView{ /** 將計時器重置爲nil */ self.timer = nil; /** 將累計用時重置nil */ self.useTime = 0; /** 每次進入遊戲將偏移量重置 */ CGFloat offset = (kCellCount / kLineCount - 1) * self.flowLayout.minimumLineSpacing + (kCellCount / kLineCount) * self.itemH - kScreenH; self.offsetTotal = offset; self.collectionView.contentOffset = CGPointMake(0, offset); /** 每次進入遊戲將紅塊重置爲白塊 -> 刷新collectionView */ [self.collectionView reloadData]; [UIView animateWithDuration:0.5 animations:^{ self.mainView.alpha = 0; }]; } #pragma mark - 初始化佈局參數 -(void)initFlowLayout{ self.flowLayout.minimumLineSpacing = 1; self.flowLayout.minimumInteritemSpacing = 0; //cell最小間距 CGFloat itemH = (kScreenH - (kLineCount -1) * self.flowLayout.minimumLineSpacing) / 4; self.itemH = itemH; self.flowLayout.itemSize = CGSizeMake((kScreenW / kLineCount) - 1,itemH); //偏移量 = (行數 - 1) * 行間距 + 行數 * 每一個cell高度 - 屏幕高度 CGFloat offset = (kCellCount / kLineCount - 1) * self.flowLayout.minimumLineSpacing + (kCellCount / kLineCount) * itemH - kScreenH; self.offsetTotal = offset; self.collectionView.contentOffset = CGPointMake(0, offset); self.collectionView.showsVerticalScrollIndicator = NO; self.collectionView.bounces = NO; //取消彈簧效果 self.collectionView.scrollEnabled = NO; //取消滾動 } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end
寫完才明白想了那麼多遍沒想到會遇到的問題.有想法就動手.
注意點:1. 最重要的一個邏輯判斷以及方法就是cell消失的時候系統要調用的方法,一個下午就被坑在這個上面了,中間想了好多方法例如:把界面上能夠看到的黑色的cell篩選出來,通過冒泡排序經過cell.tag來排序,從小到大,每次點擊判斷你是否點擊的是腳標最大的一個cell,,,然而不可行,緣由是,你能夠點擊tag最小的,再趕忙點擊tag最大的也能夠. 還有一個方法是計算腳標最大的cell的偏移量是否越過了屏幕的最底邊,然而測試的時候是每一個cell的偏移量不固定,貌似沒規律,就算用if進行判斷也很複雜..也行不通. 等等吧...最少想了三個方法都不行
最簡單最實用的也就是系統的方法,當cell被幹掉的時候調用的方法,直接判斷黑色的cell是否被幹掉便可.其餘沒什麼難度畢竟就一個collectionView而已.
源代碼demo下載地址:https://git.oschina.net/alexpei/PBPlayPiano.git