LuaJava学习笔记
使用Lua控制Java对象
[资源准备]
本次依然使用LuaJava1.1作为工具,你可以到这里进行下载:http://luaforge.net/projects/luajava/。不要忘记将本地库放到项目目录中去。我的工作目录是这样的:
为了方便,我使用Maven进行的项目依赖关联,你也可以将luajava的jar包导入项目中,这两者都是等效的。如果使用的linux进行开发,你的本地库名称应该是一个so文件,这些库文件在链接页面中都可以找到。
[源文件]
TestObject.java
package com.thrblock.lua.luatest; public class TestObject { /**普通方法的测试 * */ public void sayStr(String str){ System.out.println(str); } /**静态方法的测试 * */ public static void stTest(){ System.out.println("static method"); } /**带有返回值方法的测试 * */ public String getInfo(){ return "Test Info"; } /**一个延时函数 * */ public void delay(int millSecond){ try { Thread.sleep(millSecond); } catch (InterruptedException e) {} } }
Main.java
package com.thrblock.lua.luatest; import org.keplerproject.luajava.LuaState; import org.keplerproject.luajava.LuaStateFactory; public class Main { public static void main(String[] args) { LuaState l = LuaStateFactory.newLuaState(); l.LdoFile("./scripts/main.lua");//设置脚本 TestObject m = new TestObject();//实例化测试对象 l.getGlobal("doScript");//设置方法入口 l.pushJavaObject(m);//设置参数 l.call(1, 0);//调用方法(阻塞) System.out.println("call complete!"); } }
main.lua
function doScript (obj) obj:sayStr("delay 2 sleep...") obj:delay(2000) obj:sayStr("done! and another sleep 2...") obj:delay(2000) obj:sayStr("done!") obj:stTest() end
[测试结果]
delay 2 sleep...
done! and another sleep 2...
done!
static method
call complete!
[意义何在]
在传统的编程中,我们开发各个模块,最后使用恰当的运行脉络(例如主线程)调用模块中的各个方法,调用过程的控制依赖于硬编码,通用性不是很高而且维护成本较大。
为了改变硬编码的不足,诸多解决方案与框架开始出现,一个典型的模式是使用接口进行模块间的耦合隔离,并配合配置文件+反射的机制来控制接口对应的实现加载,这样我们仅需改变配置文件即可对程序的整体运行进行控制。例如JSP的Servlet、Struts中的Action、Android中的Activity、Spring的依赖注入以及各种JPA实现中配置的实体bean等等,对编码敏感的人应该注意到上述类没有一个是我们new出来的,它们由容器通过xml配置文件进行恰当的加载与实例化。
即使有如上诸多手段降低程序改变的成本,但需求依然没被满足。有些程序对模块的实现并不敏感,但对模块的调用序列敏感,此时上面方案能起到的作用变得极其有限,这常见于各类游戏。
举例说明,比如一个飞行射击游戏,包含一个产生敌人的模块:
Model.generateEnemy(TYPEtype,Action anction,int x,int y);
其中type泛指敌人的类型,action代指敌人的运动模式,xy是产生在屏幕的坐标点。那么,整个游戏的游戏性极大地依赖于该模块的调用序列,即何时、何地、产生何种类型的敌人以及使用何种移动策略。
调用序列的不同一般会反映到各种关卡、MOD、甚至游戏DLC上,因此有效地组织调用序列变得意义极大。但一般的配置文件显然不擅长叙述调用序列的结构,因为不同序列间差异极大并且可能包含有逻辑控制结构(例如根据玩家选择的难度、角色不同而创建不同的敌人),所以脚本成为了解决此类问题的主力——不需要编译、成本低廉、能够叙述大部分控制结构。而Lua,除了这些特性外,其多平台支持和与其它语言的超高亲和能力使它备受游戏开发者的青睐。设想一下,我们为游戏开发DLC时,仅仅更新几个小巧的lua脚本,这真是件惬意的事情。
[总结]
本次介绍了一个使用Lua控制Java类的方法,对于传入的Java类对象,使用Lua脚本控制其调用序列。
在文章的最后部分,我们讨论了软件开发中为了降低维护成本所出现的典型方案,以及脚本在其中所扮演的角色。
最后,我们对脚本所擅长解决的问题加以概括,那就是对模块调用序列敏感的程序可以将调用过程交由脚本控制。