作者: htynkn

  • 通过apt-get安装Sublime

    Sublime是一个界面很棒的文本编辑器,最简单的安装方法就是下载然后解压了。

    不过对于ubuntu而言,通过apt-get安装更加方便。

    Sublime-Text-2:

    sudoadd-apt-repositoryppa:webupd8team/sublime-text-2
    sudo apt-getupdate
    sudo apt-get install sublime-text

    Sublime-Text-3:

    sudoadd-apt-repositoryppa:webupd8team/sublime-text-3
    sudo apt-getupdate
    sudo apt-get install sublime-text-installer

    相关链接:

    Sublime Text 3
    http://askubuntu.com/questions/172698/how-do-i-install-sublime-text-2-3

  • Spring Mvc的参数注入分析

    Spring Mvc的一个强大之处在于对于各种参数注入的支持。

    除了基本的request,session等等以外,还支持RequestParam等等便利的东西。基本而言使用Spring mvc你可以直接在方法中指明你希望获得的参数,让Spring注入即可。

    参数注入的原理

    Spring Mvc中有一个HandlerMethodArgumentResolver接口,其中包含两个方法:

    publicbooleansupportsParameter(MethodParameter parameter)
    publicObject (MethodParameter parameter,ModelAndViewContainer mavContainer,NativeWebRequest webRequest, WebDataBinderFactory binderFactory)throws Exception

    当请求被Spring Mvc处理并获取到对应的执行方法时,它会首先检查所需的所有参数,然后依次检查现有的HandlerMethodArgumentResolver等否支持此类型,如果可以再调用resolveArgument方法获取参数对象。

    Spring Mvc自身有RequestParamMethodArgumentResolver,RequestParamMapMethodArgumentResolver等等常用的参数解析器。

    在RequestMappingHandlerAdapter中的getDefaultArgumentResolvers方法中硬编码了它们,而且顺序是固定无法改变的。

    Cookie的注入

    只要实现了HandlerMethodArgumentResolver就可以实现参数注入,以Spring Mvc自带的ServletCookieValueMethodArgumentResolver。

    因为从request从取出cookie值本身是一件相对简单的事情,所以这个类是一个很好的学习的例子。

    @Overrideprotected ObjectresolveName(String cookieName, MethodParameter parameter, NativeWebRequest webRequest)throws Exception {
    HttpServletRequest servletRequest = 
  • Mockito中RETURNS_DEEP_STUBS对于enum的处理

    Mockito是一个测试常用的库,可以快速模拟对象。

    加上对于Junit的支持不错,配有对应的Runner,使用起来也是相当方便。

    一般使用

    最常用的使用自然是SomeClass some=mock(SomeClass.class),如果你使用注解,还可以写成

    @Mock
    private SomeClass some;

    如果这个类有这样的方法some.getObjectOne().getValue(),我们是不能直接使用given或者when断言简单mock的,需要使用

    ObjectOne one=mock(ObjectOne.class);
    given(some.getObjectOne()).willReturn(one);
    given(one.getValue()).willReturn("value");

    Mockito提供了RETURNS_DEEP_STUBS模式,可以自己处理这种情况,如果我们使用SomeClass some=mock(SomeClass.class, RETURNS_DEEP_STUBS),我们就只需要一句简单的

    given(some.getObjectOne().getValue()).willReturn("value");

    就解决了。

    对于Enum的处理

    RETURNS_DEEP_STUBS本质上调用的ReturnsDeepStubs类。

    这个类在org.mockito.internal.stubbing.defaultanswers下面。

    public Objectanswer(InvocationOnMock invocation)throws Throwable {
    GenericMetadataSupport returnTypeGenericMetadata = actualParameterizedType(invocation.getMock()).resolveGenericReturnType(invocation.getMethod());
    Class 
  • 修改Gradle中Wrapper版本

    一直在用Gradle,它提供的wrapper是一个很实用的功能。

    可以快速切换版本,保证构建的一致性,还可以方便没有安装Gradle的用户,也能保持构建工具版本的一致性。

    启用Wrapper以后会创建一个gradle目录,其中包含一个gradle-wrapper.properties文件,内容一般如下:

    distributionBase=GRADLE_USER_HOME
    distributionPath=wrapper/dists
    zipStoreBase=GRADLE_USER_HOME
    zipStorePath=wrapper/dists
    distributionUrl=https://services.gradle.org/distributions/gradle-2.0-bin.zip

    偶尔需要修改Gradle Wrapper版本的时候我会直接修改最后一行的distributionUrl参数。

    今天看文档才发现了一个Wrapper任务,每次的修改只需要修改这个任务,然后运行就会自动创建或者修改上面那个文件了。

    task wrapper(type: Wrapper) {
    gradleVersion = '2.0'
    }

    之后运行./gradlew wrapper即可。…

  • 自定义Homebrew的Formula

    Homebrew是Mac Os X系统下一个非常优秀的软件包管理工具。使用包管理工具的优势就是省心,不再需要在网页上下载安装或者下载后解压再配置环境变量了,只需要使用brew install就可以完成安装了。

    Homebrew支持很多热门的应用和软件,而每一个支持都是一个.rb文件提供的,成为Formula。

    虽然官方支持上千种Formula,但是总有需要自己自定义的时候。

    本文以Moco为例子,创建一个Formula。

    基本内容

    Moco提供了一个命令行的jar,这也是最简单的情况,我们不需要下载编译,而是直接下载,然后链接就行了。

    我们需要的是一个standalone的jar包,版本是0.9.2,地址在这里。

    首先创建一个Formula,运行命令行brew create moco,编辑生成的moco.rb文件,添加内容

    require"formula"
    class Moco < Formula
    homepage"https://github.com/dreamhead/moco"
    url"http://central.maven.org/maven2/com/github/dreamhead/moco-runner/0.9.2/moco-runner-0.9.2-standalone.jar"
    sha1"a21445d7b275c48874ed7756477ade74de299e17"
    def install
    libexec.install"moco-runner-0.9.2-standalone.jar"
    bin.write_jar_script libexec/"moco-runner-0.9.2-standalone.jar","moco"
    end
    end

    这是一个基本的情况,我们下载对应地址的jar包,然后用命令moco链接。

    完成后运行brew install moco就可以看到效果。

    添加测试

    Homebrew提供了测试方法以测试Formula的可靠性,最简单的就是调用…

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

    测试驱动开发(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,

  • Ashley使用实例

    上一篇文章提到了Ashley,但是没给出具体的例子,加之wiki资料不全,可能使用上有些困难。

    superjumper是Libgdx的一个demo,siondream使用Ashley改造了整个项目,特别适合学习入门。

    地址是:https://github.com/siondream/ashley-superjumper

    组件

    components是entity system的主要构成,这里就成为组件吧。

    组件只包含具体的值,比如宽度,高度,状态等等。

    比如我们的主角Bob

    publicclass BobComponent extends Component {
    publicstaticfinalint STATE_JUMP =0;
    publicstaticfinalint STATE_FALL =1;
    publicstaticfinalint STATE_HIT =2;
    publicstaticfinalfloat JUMP_VELOCITY =11;
    publicstaticfinalfloat MOVE_VELOCITY =20;
    publicstaticfinalfloat WIDTH =0.8f;
    publicstaticfinalfloat HEIGHT =0.8f;
    
    publicfloat heightSoFar =0.0f;
    }

    而对于金币Coin…

  • libGDX的实体框架Ashley

    游戏开发之中有时候会使用实体框架,比如Artemis。

    在游戏开发中使用实体框架可以极大的提升项目层次和可测试性。

    比如利用Artemis,你的游戏代码可能是

    publicclass MyGame {
    
    publicvoidMyGame() {
    world =new World();
    
    world.setSystem(new MovementSystem());
    world.setSystem(new RotationSystem());
    world.setSystem(new RenderingSystem());
    
    world.initialize();
    
    while(true) {
    world.setDelta(MyGameTimer.getDelta());
    world.process();
    }
    }
    }

    Ashley

    Ashley并没有提供特别的功能,它是一个很简单的实体框架。

    它属于Libgdx大家族,但它并不是选用的,你可以继续使用Ash或者Artemis。

    使用的时候在你的gradle配置中加上

    dependencies {
    compile"com.badlogicgames.ashley:ashley:1.0.1"
    }

    就行了。

    具体的使用方法稍后Wiki也会放出的。

    最核心的类是EntitySystem。

    参考资料

    实体系统的好处
    API

  • Hexo升级到2.8

    Hexo升级到2.8

    Hexo使用的Yaml Parser做出了一定的修改,所以很有可能在升级Hexo以后会出现HexoError错误。

    [error] { name:'HexoError',
    reason:'incomplete explicit mapping pair; a key node is missed',
    mark:
    { name:null,
    buffer:'categories: Categoriesnsearch: Searchntags: Tagsntagcloud: Tag Cloudnprev: Prevnnext: Nextncomment: Commentsncontents: Contentsnarchive_a: Archivesnarchive_b: Archives: %snpage: Page %dnrecent_posts: Recent Postsnmenu: Menunlinks: Linksnrss: RSSnshowsidebar: Show Sidebarnhidesidebar: Hide