Co!orMix 小记──关于开发的那点儿事

2015-09-10 23:19:28 +08:00
 Cee

本文作者 LuckyMore

关于 Co!orMix

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

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

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

动手之前的思考

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

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

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

项目结构

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

目录 职能
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;
}

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

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

总结

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

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

最后欢迎大家体验!

3632 次点击
所在节点    分享创造
16 条回复
loveuqian
2015-09-10 23:26:13 +08:00
赞,必须学习
Dreista
2015-09-10 23:26:16 +08:00
赞。
razrlele
2015-09-10 23:53:49 +08:00
顶 Cee 总!
jetbillwin
2015-09-11 08:12:33 +08:00
赞 Cee 总!
RyuZheng
2015-09-11 10:25:45 +08:00
zld
2015-09-11 10:26:57 +08:00
挺 Cee 总!
kxxoling
2015-09-11 10:56:18 +08:00
给 Cee 总点个赞!
msxcms
2015-09-11 16:34:39 +08:00
ぺろぺろ
21grams
2015-09-12 08:12:49 +08:00
iOS 上的?
SeanChense
2015-09-12 09:06:01 +08:00
超级喜欢设置的设计
Cee
2015-09-12 14:02:26 +08:00
@21grams 恩是的,現在適配了 iPhone 和 iPad 。 考慮往 tvOS 上適配了。
@SeanChense 謝謝!
SeanChense
2015-09-12 14:38:46 +08:00
@Cee 然后就照着你的思路也给我的项目加了个模糊背景了 哈哈哈
hweining
2015-09-13 15:12:53 +08:00
Cee 菊苣不准备把 android 版的开源了吗 感觉国内 quiz 这类游戏还有市场未挖掘‘
Cee
2015-09-13 15:40:23 +08:00
@hweining 其實有 http://github.com/Cee/ColorMix/blob/dev-android/
當時偷懶就 android 也放在一個 repo 下了
Caringor
2015-09-15 12:00:07 +08:00
Cee 苣苣 prpr
wsph123
2015-09-17 09:35:53 +08:00
prprprpr !

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/219813

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX