About Co!orMix (3) - Co!orMix 小记:关于开发的那点儿事

By on

关于 Co!orMix

前几天, Cee 童鞋把 Co!orMix 开源了。当时刚上架的时候,团队里的另外两个童鞋都发了文,@Cee 讲产品,@Albus 讲设计(这两篇文章都在 V2EX 上发布过)。

既然代码开源了,那是时候说一下项目本身了。

Co!orMix 里面并没有什么特别有技术含量的东西,可以说,任何一个人都可以毫不费力地把它做出来。对于新手来说,也值得一试。不过毫不谦虚地说,如果要达到零错误率,还是有一定难度的,而上线至今,它的 Crash 率一直保持在 0 ,这是我所引以为豪的。(欢迎大家试玩!偷偷说一句,我可是跟组里承诺过,只要出现一个 crash ,就请吃饭的哦!)

动手之前的思考

无论是多简单的项目,开动之前必须要思考一下大致的架构。 Co!orMix 本身是一个相对很简单的游戏。

从页面考虑:主页、设置页、游戏界面、游戏结果页、引导页; 从游戏本身考虑:题目、选项、得分、策略、游戏模式

第一天晚上我们三个人商量出了游戏的大致功能和规则,我和 Cee 便直接开始讨论起了实现。由于游戏本身的复杂度不高,我们决定采用最传统的 MVC 来完成这个应用。

  • Model 层
    CMCard :卡片(对应游戏界面上半部分) CMColor :颜色(游戏中所对应的颜色的概念) CMQuestion :问题(包含 CMCard ,以及对应的 Option 和 Answer ) CMScene :游戏场景(对应一次游戏,根据游戏模式区分不同表现) Factory :工厂(工厂模式,生产问题)

  • View 层
    CMCardView :卡片 View CMQuestionView :问题 View CMScoreView :得分

  • Controller 层
    CMClassicTutorialViewController/CMFantasyTutorialViewController :新手引导 CMGameResultViewController :游戏结果 CMGameViewController :游戏界面 CMMenuViewController :游戏菜单界面 CMSettingViewController :游戏设置界面

项目结构

由于项目比较简单,所以并没有按照功能模块进行分类,项目的结构大致如下:

目录 职能
Category 工具、扩展类
ViewController Controller 层
View View 层
Model Model 层

项目并没有使用任何第三方库(除了友盟统计),所以自然也就没有使用 Cocoapods 了。

关于开发细节

  • 规范

项目主体编码主要是我负责的,@Cee 在初期做了 Code Review 工作(惊讶吧!这么小的项目还做 Code Review )。开发在 dev 分支做,记得第一次提交的时候,@Cee 写了 N 个 comments ,很多都是关于 Coding Style 的问题(我自认已经很注意了,但是在某个人的强迫症面前根本不值一提),改完了所有的问题。之后就更加小心地完成编码工作。最后通过 Pull Request 合并进主分支。之后又开发了 Android 版本,感兴趣的童鞋可以去 dev_android 的分支看一下安卓版本,实现的大致逻辑和 iOS 差不多。

  • 适配

项目采用 xib + AutoLayout + Size Classes 完成界面搭建,这也是我们第一次尝试使用 Size Classes 。
总体来说,算是不错的一次实践, 0 代码完成全平台适配。我们以游戏界面中的 QuestionView 为例(CMQuestionView)做一下介绍,这个界面算是相当相当的典型了!

分析一下这个界面,基本可以分三部分:卡片、问题、选项。这里我总共分了三个 View 来区分,分别为 Options 、 Card 、 Question ,其中 Options 是撑满整个 View 的。(参看 Fantasy 模式下的表现)

可以注意一下这里还有一个背景占位符,它是一个垫在最底层撑满整个屏幕的透明的 View ,用来给其他 subview 做尺寸上的参考,比如 Card 部分的高度所做的约束通过背景占位符高度的一半来限定。

另外分享一个小的 Tip ,在 xib 中可以直接通过右侧的选项实时查看不同设备下界面的布局:

再有就是 Tutorial 的这个界面,细心的用户也会发现也是全适配的。我们的游戏引导界面并没有单纯地使用图片,而是在原有的游戏界面上加上了对应的引导元素,不管是箭头还是文字都是使用 AutoLayout 拉的约束。

  • 分享

为求最简,我们的分享使用的系统原生的 UIActivityViewController 来实现。不过这里在适配的时候遇到了个坑,直接上代码:

- (IBAction )onShareButtonClicked:(id )sender {
    [MobClick event:@"Share"];
    CMScoreView *scoreView = [[CMScoreView alloc] initWithScore:self.score];
    UIImage *imageToShare = [UIImage captureImageFromView:scoreView];
    NSString *stringToShare = [NSString stringWithFormat:@"I scored %ld in the %@ mode, play #Co!orMix with me: %@", (long )self.score, self.gameMode == classicMode ? @"classic" : @"fantasy" , kAppStoreUrl ];
    NSArray *activityItems = [[NSArray alloc] initWithObjects:imageToShare,stringToShare, nil];
    UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
    activityVC.excludedActivityTypes = @[UIActivityTypeSaveToCameraRoll];
    if (IS_IPAD ) {
        UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:activityVC];
        self.shareController = popup;
        popup.delegate = self;
        [popup presentPopoverFromRect:CGRectMake (self.view.frame.size.width / 2, self.shareBtn.frame.size.height + self.shareBtn.frame.origin.y , 0, 0 )inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
    } else {
        [self presentViewController:activityVC animated:YES completion:nil];
    }
}

对于 UIActivityViewController,在 iPhone 上,我们可以直接使用 present 的方式;但是在 iPad 上,这会引起崩溃,可以使用 UIPopoverController 来包装 UIActivityViewController

  • 设置界面的效果

个人还是很喜欢这个效果的,使用的是 iOS8 自带的毛玻璃效果。上代码:

- (IBAction )onSettingButtonClicked:(id )sender {
    [MobClick event:@"Setting"];
    self.settingViewController = [[CMSettingViewController alloc] initWithNibName:NSStringFromClass ([CMSettingViewController class]) bundle:nil];
    self.settingViewController.view.frame = self.view.bounds;
    self.settingViewController.view.alpha = 0;
    [self.view addSubview:self.blurView];
    [self.view addSubview:self.settingViewController.view];
    [self addChildViewController:self.settingViewController];
    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        _blurView.alpha = 1;
        self.settingViewController.view.alpha = 1;
    } completion:nil];
}

- (UIView *)blurView {
    if (!_blurView ) {
        _blurView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
        _blurView.frame = [[UIScreen mainScreen] bounds];
        _blurView.alpha = 0;
    }
    return _blurView;
}
  • GameCenter 和友盟

这两块都是 @Cee 负责弄的。友盟的接入相对简单,不过 GameCenter @Cee 弄了一晚上,还吐槽网上没有成熟的 GameCenter 接入指南,我觉得有必要让他专门写一份了。

  • 面向对象

项目虽小,可以用任何方式实现。不过这样一个小项目可以把面向对象思想很好地加以实践。所有的类都实现了对应的职能,隐藏了内部细节。

总结

以前写过不少项目,不过都比较庞大,而且基本都是负面教材。 Co!orMix 是一个小而精的 App ,从萌生想法,到 Demo ,到设计出炉正式完工,整个周期一共就一星期:设计花了一整天做出了可供交互的原型;在代码上只花了两天,但是却不仓促。代码均在 GitHub 上托管,测试上使用 TestFlight 完成分发,通过种子用户的体验修改游戏参数,提高用户体验。同时兼顾各种极端操作,保证代码安全性,做到零错误率。

简单来说,对于新手来说,大家可以先下一下这个 App ,感兴趣的可以自己实现一遍,一点都不困难!然后再对比一下我们的实现。如果 Co!orMix 有任何不合理的地方,也欢迎指正!

最后欢迎大家体验!