月度归档: 2014 年 9 月

  • 在游戏开发中应该使用测试驱动开发吗?

    测试驱动开发(TDD)逐渐成为越来越流行的实践,它提升了代码的易用性和独立性,也增强了开发信心。

    TDD作为一种实践自然不存在不适用的领域,但是在一些领域它是具有挑战性的,比如游戏开发。

    知你所愿

    测试驱动开发在游戏开发中应用的最大挑战并不是来自UI。
    其核心问题是你通常并不清楚你的UI是什么样的。UI是你必须面对的东西,而和它的交互更多时候是一个深层次的东西。

    游戏的本质是状态机,而获得某种状态或者到达某种状态有时候需要付出相当大的代价。

    测试这些东西是困难而且浪费的。

    Uncle Bob曾说过:‘不要TDD UI’。

    对于UI做纯粹的TDD是困难的,但是对于部分做TDD确实可能的。

    比如游戏中的算法,状态机本身的变化等等。

    对于UI它的确不合适,但是对于其他部分,TDD是一个不错的选择。

    单一责任原则

    遵循SRP原则是一个很好的补充。

    将你的代码分离出来,从某种意义来看这样是为了测试而改变,但是从长远来看,也是一种很好的维护方法。

    有很多事情是可以做到的,比如将可以测试的算法部分从UI中剥离,分离一些不同原因而存在的代码。

    有一点是需要牢记的,有些代码第一次看的时候很难测试,但并不意味着第二次的时候仍然很复杂。

    在流程上的妥协并不是什么大问题,首先使用你喜欢的方法写出代码,然后编写测试。

    你需要预防的只有一次性写完整个游戏再进行测试的冲动。

    在事后写测试的问题在于代码耦合,进而难以测试那些重要而有用的类。如果你发现你写的代码难以测试,请尽量遵循依赖倒置原则和开闭原则。

    这样才能保证代码解耦足够支撑你事后测试。

    实体系统

    将代码分离,说着很容易,操作起来确实困难的。

    如果分离?依照何种标准归类?

    Entity System本身就是一种分离规则,将整个游戏分离成组件、实体和系统。

    Libgdx有Ashley支持,它是一个轻量级的实体系统。

    一旦整个项目跟随这个规则来拆分,大部分代码都是可以测试的。

    游戏的核心部分将归入系统之中,而系统本身和绘制,即UI是可以分离的,这样游戏中的各种状态和情况都可以很快速的测试出来。

    BDD合适吗?

    BDD本身是一种设计方式,换一种方法思考本身并不能改变什么。

    从本质上讲,二者也不是一种东西。

    参考资料

    IEEE:TDD
    BDD
    Game engine 101…

  • 升级Libgdx到最新版本

    升级Libgdx到最新版本

    Libgdx现在已经是1.X时代了,但是手上很多项目都还是在0.9.X上面,感觉越来越不顺手了。

    没法使用最新版本就意味着对于iOS的支持还停留在以前的解决方案中,即Xamarin+Monotouch。Xamarin收费不说,主要是慢而且要收费。

    看着别人快乐的使用最新版本,实在受不了了,开始升级之旅。

     

    基础Gradle配置

    最简单的办法应该是直接自己根据项目配置专属的build.gradle配置,然后将原有依赖移除,重新构建项目就行了。

    但是具体操作中感觉略麻烦,所以最后选择了新建初始化的项目,然后直接将旧的代码拷贝过去。

    建立初始化项目比较简单,直接使用setup工具就行了。

    我以DartsShaSha为例,这是一个简单的示例程序。

    setup

    创建好初始化项目以后直接拷贝原有的项目文件过来,然后运行./gradlew idea创建项目并引入Intellij IDEA。

    基础配置调整

    首先新版本已经移除了对于OpenGL ES 1.0的支持,原有配置的中的config.useGL10不再支持,默认启用OpenGL ES 2.0,config中可以不再书写。

    对于配置中的useGLSurfaceView20API18这一项,默认为false,就不要轻易改动了。

    Stage的缩放

    新增的Viewport类增强了Libgdx的屏幕自适应能力,原有的构造函数Stage(480,320,true)就不再适用,可以考虑使用new Stage(new StretchViewport(480, 320));替换。

    除了StretchViewport以外,可以选择的还有FitViewport、FillViewport、ScreenViewport、ExtendViewport和CustomViewport。

    一般情况用StretchViewport就够用了,不需要自己实现一个。

    一些细节

    有些细节有点复杂,比如Actor中的public void draw(SpriteBatch batch, …