首先查看一下jvm当前支持了哪些脚本引擎,当前使用的是jdk6版本
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
List<ScriptEngineFactory> engineFactories = scriptEngineManager.getEngineFactories();
if (engineFactories.size() == 0) {
System.out.println("本JVM尚不支持任何脚本引擎");
return;
}
System.out.println("本JVM支持的脚本引擎有:");
for (ScriptEngineFactory engineFactory : engineFactories) {
System.out.println("引擎名称:" + engineFactory.getEngineName());
System.out.println("\t可被ScriptEngineManager识别的名称:"+ engineFactory.getNames());
}
结果:
本JVM支持的脚本引擎有:
引擎名称:Mozilla Rhino
可被ScriptEngineManager识别的名称:[js, rhino, JavaScript, javascript, ECMAScript, ecmascript]
可以知道jvm默认是支持JavaScript脚本的,当然jvm提供了相应的接口,是可以接入第三方脚本引擎的,比如Python,
Expression Language等支持。当前引用了jython.jar,jython-engine.jar,jexl.jar,重新查看支持的引擎。本JVM支持的脚本引擎有:
引擎名称:Mozilla Rhino
可被ScriptEngineManager识别的名称:[js, rhino, JavaScript, javascript, ECMAScript, ecmascript]
引擎名称:jython
可被ScriptEngineManager识别的名称:[jython, python]
引擎名称:JEXL Engine
可被ScriptEngineManager识别的名称:[JEXL, Jexl, jexl, JEXL2, Jexl2, jexl2]
好了,既然jvm可以扩展支持这么多脚本,下面举几个实际运用的例子:
1.比如有这样的需求,有一个给玩家的奖励是要根据玩家等级(level)进行计算的,比如需要把100*level,这里我们可以使用两种方式来解决:
第一种:在代码里面写死,判断当是指定奖励的时候*level
第二种:使用表达式,然后使用引擎执行表达式,看下面的例子,使用JavaScript引擎:
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("javascript");
String exp = "100 * level";
scriptEngine.put("level", 4);
Object result = scriptEngine.eval(exp);
System.out.println(exp + " = " + result);
这样我们就可以将我们的奖励表达式,交给一个表达式处理器统一处理。这里我们是利用了JavaScript可以执行表达式的功能,当然可以利用更专业的表达式执行引擎jexl,性能会更好。
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("jexl");
2.还有更复杂的需求,就是战斗系统,不仅仅是解析表达式了,需要更多的逻辑,比如最常用的计算伤害,需要一个很复杂的逻辑,而这个逻辑最清楚的是策划,所以我们通过提供接口,然后由脚本来实现,我们的程序只负责调用就行了。
比如这个接口由Python来实现:def increaseHp(attackUnit,defenceUnit,skill,buff,type):#attackUnit 技能释放者,defenceUnit 技能中招者,skill 技能,buff ,type 1=求数值 2=求描述
....省略
通过一系列的参数最后计算出伤害。
或者看一个更简单的Python脚本test.py:
def addition(num1,num2):
return num1+num2;
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("python");
String jsFileName = "scripts/test.py"; // 读取py文件
FileReader reader = new FileReader(jsFileName); // 执行指定脚本
engine.eval(reader);
if (engine instanceof Invocable) {
Invocable invoke = (Invocable) engine;
Integer c = (Integer) invoke.invokeFunction("addition", 2, 3);
System.out.println("c = " + c);
}
好了,暂且就介绍这两种需求了,肯定还有运用在其他的地方的需求。
忘了说了脚本比如JavaScript,Python,lua,都是解释执行的,不需要编译,所有现在游戏中经常用脚本来实现热更新。