Blog logoJustZht

Blog logo

2017.6.10

 • 

自己的 20 岁已经过了四分之一了。
妹子早上起来总是会和我说她做的梦,那个时候我一般在上班的地铁上。有时候我会感叹自己已经不怎么做梦了,我对妹子的解释是做梦是一个消耗额外精力的事情,所以小孩子精力充沛会多梦,而长大后精力不够就不怎么做梦了。但我总觉得自己是刻意把做梦的功能给关掉了,就像是电闸一样,那个功能再也不会用了。
在百度实习这段时间后,觉得自己的心态越来越糟糕了,因此博客也一直没更新,毕竟去总结自己为什么过的不开心本来就已经够令人不开心了。回到学校过后细细想了下,主要还是觉得现在的生活有种隐隐的约束感,而我这个人对于不自由是非常敏感的。
每天通勤 2 小时,白天上班要写的项目处于维护状态没有什么新鲜感,晚上不加班的情况下下班后到家一般要八九点,然后妹子和我妈会打电话过来,接完差不多就要去洗漱了,晚上就没什么时间写自己的项目。有时候会觉得自己难道要一辈子一直这样下去,在公司写没有意义的代码,也没有时间做自己的事情,所有的时间貌似都在为别人而过。
当然这种担心肯定是不可能发生的,因为我还只是大三,还是实习,所有这些担忧都只是自己在某种情绪下的极度担忧而已,况且离职就可以立刻解决这种问题,因为这样的话白天的时间就会有大部分是自己的了。但这种隐隐的对不自由的担忧会仍然存在,而一旦我觉得自己不自由了,就会各种折腾,最后把大家都弄的不开心。我生性如此,而且貌似可见的十年之内不会有改动,而且我自己无计可施。

Funny Things About the Launch of BoardForGitHub

 • 

  • 发了 40 个 Promo Code,V2EX 和 Product Hunt 各 20。
  • Product Hunt 上当日(五月 25 日)排名第四,目前 520 个 Upvotes。
  • 特性请求(Feature Request)最多的两个:1.发布 Windows/Linux 版本 2.发布 GitLab 版本(上次的 Contributions 也有小哥问我能不能写 GitLab 的)
  • 有很多人以为这是一个 Electron 包装的软件,其实并不是。BoardForGitHub 是一个 ObjC + WebView 的软件。
  • 昨天 61 和我说 BoardForGitHub 在主显示器里被拖到边缘的时候不能自动移动到另一个 Space 上去,这个貌似是因为 Override 了 NSWindow 的 MouseDragged 方法
  • Softpedia 给这个软件写了一个 Review,功能介绍比我自己的都详细(我自己很懒的),因此我决定以后使用他们写的 Review 来介绍自己的软件 hhhh
  • Paddle 的 Fee 特别高,而且是每次购买都收费,因此 $1.99 会去除 $0.6 的 Fee 和 $0 - $0.4 的 Tax,截止目前大概有十几个人购买,差不多挣了二十刀。
  • 最近也说不出是忙还是闲,很多邮件一直没来得及回,这次 launch 后也多了一些邮件,问合作的,提功能需求的,还好没有要退款的

CSS & Cetacea Dev Blog

 • 

最近在进行两个项目的重写,进度都还不错。

China Startup Simulator (CSS)

CSS 作为一个小型游戏其实没什么好说的,但特殊的是 CSS 是一个类似于 Regins 的文字游戏,因此有特别多的文本。之前用的是 xls 文件进行事件(JZEvent)和事件回应(JZEventResponse)的储存,能用但比较繁琐,比如 xls 文件修改一次就要重新 deploy 一次。所以最近把储存改为了 Google Doc,可以在 iOS / Android 上实时地从 Google Drive 上拉取解析。
不过整个数据库仍然是基于列表的,对于文字对话类游戏来说,或许是一个好的序列化方式,但不是一个好的编辑方式。
所以最近在基于 https://github.com/Seneral/Node_Editor/ 写一个可视化的节点故事流程图,拖拽故事节点后编辑内容,然后序列化到 ScriptableObject 中。

Cetacea

把 Cetacea-Mac 拆成了包含四个 project 的大 workspace:

- Cetacea-Mac
- Cetacea-iOS
- CetaceaSharedFramework
- Pods

其中 CetaceaSharedFramework 包含了 Data 层的大部分内容,让 iCloud 这部分写起来更容易了些。目前两个系统的 Cetacea 如下:

2017.5.7

 • 

这两周在路上花了不少时间,事情呢做了一些,但都不怎么顺。

面试&笔试

回长沙考期中,顺便去腾讯面试。当天长沙下雨,立珊专线还堵了一下,迟了半小时到。面试官大致问了以下内容:

  • KVO / KVC,问了下概念。
  • 线程相关,问我平时用什么。我说 NSOperation 和 GCD,然后问我用过 NSThread 没,我说没怎么用过。
  • 问 Atomic / Noatomic 的含义
  • 让我写一个线程安全的 Singleton,我用 Dispatch_once 写的,不过貌似写的不全
  • 让我乱序向一个 NSMutableArray 插入 0 - 99 这一百个数字。我问能不能用 NSSortDescriptor 然后在 Block 里面随机返回真假,面试官有些疑惑的样子,一直问我这个排序到底是怎么拍的,复杂度多少,我说这个就是苹果的内部实现,我也不敢打包票。
  • 问项目经验,特别问了 RavenTech 的 EVA VR。听完项目后问我为什么要给 Unity 写 Native WebBroswer to Texutre2D 的 Plugin,我说 Unity 只 pack 了一个 Mono Runtime,至于打包 WebKit 这种事情不是 Unity 关心的,只能自己写。估计面试官以为 Unity 应该有 Universal 的那种浏览器 UI,所以问我这个问题。
  • 问我挂过科没,回答上学期刚挂过。问我为什么有这么多项目经验,我说翘课,除了考试以外都在写项目。面试官说那是挺胆大的,我也不好揣摩意思回答,只能耸耸肩。
  • 最后问我有什么想问的没,我很实诚地回答没有。后来听同学说应该回答有问题的以显示自己很有诚意。

面完当天晚上查,显示没有过。

至于阿里的笔试,Objective-C 的运行环境是用 GNUStep 搭建的,编译也很严格,有 Warning 就不能过。我在本地 Xcode 写好的代码在在线评测上不能用,因为总会有各种类型转换的警告,比如 id 到 NSNumber,最后索性放弃了。

至于感受,校招不关心你有多少 star,自己最好还是多看看算法和数据结构,还有就是面试这种东西,还是要准备下的,不是说仗着自己忙就不去看,很多东西就是在公司用不到忘掉,但临面试看下就又记得的。

Board For GitHub

这是一个去年十月份写的开源小项目,后来有意向把这个软件上架到 Mac App Store,就又加了些功能,例如 NSTouchBar,NSUserNotifcation。结果苹果的审核团队连续五次拒绝了上架请求,原因还是和写 ArtWall 的时候一样:用户体验和用 Safari 类似。不同的是 ArtWall 是货真价实的 Native Application,而 Board For GitHub 是真的 WebView 软件,就更难过审了。
最后决定在 MAS 外分发。原本想用 DevMate 做试用功能集成 + Stripe 付款,后来发现 Paddle 直接把这两个功能都合并在了一个 SDK 里,有 Cocoa 和 JS 的版本,就很方便。但 Paddle 不包括自动升级功能,于是又用了 HockeyApp 做了自动升级。目前的发布版本可见 https://justinfincher.github.io/BoardForGitHub-Landing/

日常

和喵喵一起看了几部电影。周末窝在家里打 Gang Beasts 和 Broforce。学校管的越来越严了,我不在长沙后据说又加了脸部打卡什么的,但我已经没有精力去对付这些事情了。
回学校后发现其实还是暗流涌动,学院里同学平时都是一副不关心工作的样子,暗地里都在忙着找这个那个实习。
差不多两三年来我第一次对自己走的这个方向是不是对的有了怀疑。面试没过让我有点疑惑,在学校呆的一周发现学校有事情要对付,公司因为我回长沙也少发了些工资,和妹子有时候会有误解,让我在四月底有一种什么都不好了的感觉。
银河护卫队 2 的 Soundtrack 挺好听。

2017.4.25

 • 

最近烦心事挺多的。
回长沙考期中,然后和妹子订好了去杭州和北京的票。突然一门课的考试向后推延两天,定的票几乎全废,想要再改签也不容易,毕竟临近五一了。
WWDC 奖学金没过。我认识的两三个国内大学在读的 iOS 开发都没过,反倒是有一些苹果设置教育点的大学里的学员过的比较轻松。在这就不讨论到底公不公平的事情了,只是对于我来说,今年没过意味着短期内是不可能参加 WWDC 了:去年因为在渡鸦写 VR 没提交,今年提交了没过,明年要忙毕设,后年就在正式工作没学生这个身份了。
我从北京回长沙后,我负责的项目只能交给另一个同事来做,而从三月份重构到现在,整个 Unity 工程已经不是那位同事熟悉的样子了。我只能在长沙远程打电话或者发消息告诉同事项目的架构以及工具链如何用。然后 HR 和我说回学校考试算缺勤,扣了一大半工资。虽然知道会有这个规定,但我觉得还是有些寒心的,毕竟考虑到断断续续一年多来在公司加班,下班后留公司干活这些事情。
还是有些令人高兴的事情的,等考完回北京后再写吧。

My WWDC 2017 Playground For Application

 • 

From noreply-appledev@email.apple.com
Your WWDC Scholarship Status
Thank you for applying for a WWDC 2017 Scholarship. We appreciate your hard work and enjoyed seeing your creativity. With an extraordinary number of engaging Swift playground submissions, the selection process was not easy. We regret that we are unable to offer you a scholarship this year.

Now Open Sourced at https://github.com/JustinFincher/WWDC-17-Scholarship-Project

Unity Custom Inspector Value Saving

 • 

最近发现 SetDirty 不太好用,总是没办法让自定义 Inspector 里面的值序列化。然后在 https://docs.unity3d.com/ScriptReference/EditorUtility.SetDirty.html 这里发现有一段话:

NOTE: ''Prior to Unity 5.3, this was the primary method of marking objects as dirty. From 5.3 onwards, with the introduction of Multi-Scene Editing, this function should no-longer be used for modifying objects in scenes. Instead, you should use Undo.RecordObject prior to making changes to the object. This will mark the object's scene as dirty and provide an undo entry in the editor.''

看了下 Undo.RecordObject 的文档,唯一的不好是 EditorGUI.BeginChangeCheck() 和 EditorGUI.EndChangeCheck() 需要一前一后,对于继承的自定义 Custom Editor 有些难办,因此用 Action 把代码变成一个 Code Block:

Helper Code

using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using System;  
#if UNITY_EDITOR

using UnityEditor;  
using UnityEditor.SceneManagement;

namespace FinGameWorksEditor.Helper  
{
    public static class FGWEditorUtility
    {   
        /// <summary>
        /// Helper Function to use the Undo In Custom Inspector
        /// </summary>
        /// <param name="guiCode">code block to write editorguilayout stuff</param>
        /// <param name="targetCode">code block to write updating target variable stuff</param>
        /// <param name="target">the target monobehavior</param>
        public static void RecordUndoBlock(Action guiCode,Action targetCode,UnityEngine.Object target)
        {
            EditorGUI.BeginChangeCheck();
            guiCode();
            if (EditorGUI.EndChangeCheck())
            {
                Undo.RecordObject(target, "Changed");
                targetCode();
            }
        }
    }
}
#endif

Usage Example

using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
using System.Linq;  
using UnityEngine.SceneManagement;  
using FinGameWorks.Helper;

#if UNITY_EDITOR
using UnityEditor;  
using FinGameWorksEditor;  
using FinGameWorksEditor.Helper;  
using FinGameWorks.Controller.SceneManagement;

namespace FinGameWorksEditor.Controller.SceneManagement  
{
    [CustomEditor(typeof(FGWSceneLoader), true)]
    public class FGWSceneLoaderEditor : FGWMonobehaviorEditorBase
    {
        public List<string> scenesInBuild
        {
            get
            {
                if (_scenesInBuild == null)
                {
                    _scenesInBuild = FGWSceneHelper.getAllSceneNameInBuild();
                }
                return FGWSceneHelper.getAllSceneNameInBuild();;
            }
        }
        private List<string> _scenesInBuild;

        public FGWSceneLoader loader
        {
            get { return (FGWSceneLoader)target; }
        }

        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            bool loadSceneOnStart = false;
            int sceneIndexToLoad = 0;
            FGWEditorUtility.RecordUndoBlock(()=>
            {
                GUILayout.Label("Parameters",EditorStyles.boldLabel);
                loadSceneOnStart = EditorGUILayout.Toggle("Load Scene On Start", loader.loadSceneOnStart);
                sceneIndexToLoad = EditorGUILayout.Popup("Scene To Set",loader.sceneIndexToLoad,scenesInBuild.ToArray());

                GUILayout.Label("Action",EditorStyles.boldLabel);
                if (GUILayout.Button("Refresh Scene List"))
                {
                    _scenesInBuild = null;
                    foreach (var item in scenesInBuild)
                    {
                        Debug.Log(item);
                    }
                }
            },
            ()=>{
                loader.loadSceneOnStart = loadSceneOnStart;
                loader.sceneIndexToLoad = sceneIndexToLoad;
            },loader);
        }
    }

}


#endif

namespace FinGameWorks.Controller.SceneManagement  
{
    public class FGWSceneLoader : MonoBehaviour
    {
        public bool loadSceneOnStart;
        public int sceneIndexToLoad;

        void Start ()
        {
            if (loadSceneOnStart)
            {
                SceneManager.LoadScene(sceneIndexToLoad);
            }
        }

        void Update () {

        }
    }
}

Epoch Dev Blog 8

 • 

事务繁忙,从去年十月份就没怎么再动过。不过最近把 Epoch 升级到了 Unity 5.6,现在 build 了一个 WebGL 的版本,如果有兴趣的同学可以去玩下。
点这里进入 WebPlayer (Hosted on itch.io)

操作:目前的操作是主要面向手机的,网页版或许会比较难以控制。网页加载完成后,鼠标按住上下滑动可以加减速。操控由左下角的摇杆控制。若提示内存不足,请刷新浏览器。推荐电脑端 Chrome。目前 macOS 10.12 + Chrome 57.0.2987.133 (64-bit) 上测试通过。

Fun Fact:目前 Epoch 在手机上的编译大小只有 60 MB,其中一大半都是飞船的贴图和模型 —— 星球部分只有代码,贴图和模型完全是实时生成。

2017.4.10

 • 
女朋友&吃吃喝喝

妹子来北京找我玩。带着妹子见了一些互联网圈子里的朋友和同事。两个人前半段时间在外面吃吃喝喝看电影逛街,后半段就主要窝在家里。中间尝试在家里继续写 Cetacea For Mac,妹子颇有兴趣地看了会,然后就困了。所以就在一起用电脑看 YouTube 和 Bilibili。

Cetacea For Mac

重构了一部分,也加了一部分功能。highlight.js 的基本嵌入工作完成,因此 Preview Panel 的功能趋于可用。Markdown Parser 的正则仍在修改,也在尝试实现一套 Incremental Parser。除此以外,主题功能也在逐步更新中,目前的效果如图。

WWDC Scholarship 2017

我的 Swift Playground 叫 Golf GO。Golf GO 是一个使用了 SceneKit,ModelIO,GamePlayKit 的地图过程生成的高尔夫球游戏。写 WWDC 奖学金申请的体会是 Swift Playground 并不是一个“严肃”的编程平台,包括如果不通过设置 plist 就不能关掉 logging,所有类都要写在一个文件里,各种放在 Single Page Application 模板里运行没问题的代码会在 Playground 里无故出错。除此以外,我也再也不想写 Swift 了。

WebDrop

更新了一个版本:1.0.1,Related Issue:WebDrop/issues/2

电影&音乐

看了攻壳机动队美女和野兽,听了 The Wheel by SOHN