代码没有过多的进行封装,只是先实现了基本的功能.一共才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