Picnic Invasion! Day 5
Worked on integrating the Mozilla Rhino javascript engine today. Here’s a brief example (in Java) of using it with slick:
/*
This file demonstrates using the Rhino Javascript engine within the
Slick 2d game engine.
Rhino can be found at: http://www.mozilla.org/rhino/
Slick can be found at: http://slick.cokeandcode.com/
*/
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ScriptableObject;
public class Rhino extends BasicGame {
/*
The ScriptProxy class defined here is one half of the interface
between Java code and the Javascript environment. It is used to,
among other things, provide access to Java objects within Rhino.
The ScriptableObject class implements the majority of the
Scriptable interface. The Scriptable interface is used to define
functions and objects that will be available to the javascript
environment.
*/
class ScriptProxy extends ScriptableObject {
String test1;
/*
This is the only method required to fully implement the
abstract class ScriptableObject. I'm not sure what it is
supposed to do. The "global" value is used in at least one
example in the Rhino documentation.
*/
public String getClassName() {
return "global";
}
/*
Access to the "test" object in the javascript environment is
implemented through calls to the setTest and getTest
methods.
*/
public void setTest(String str) {
test1 = str;
}
public String getTest() {
return test1;
}
/*
A test function that can be called within the JavaScript
environment.
*/
public void testfunc(String s) {
// System.out.println("test function called");
System.out.println(s);
}
}
/*
A Context is an instance of the javascript environment. The
context is used to load and interpret .js files and interpret
Javascript code as strings, among other things. In this example
it is used exclusively to interpret Javascript strings.
*/
protected Context scriptContext;
protected ScriptProxy gameProxy;
public void init(GameContainer container) throws SlickException {
/*
The static method Context.enter is, apparently, the easiest
way to obtain a javascript environment.
*/
scriptContext = Context.enter();
gameProxy = new ScriptProxy();
/*
We'll set a string for the "test" property that will be
exposed in Javascript now so we know it is calling across
the bridge.
*/
gameProxy.setTest("This was set within java, but called from javascript.");
/*
This must be called before scripts can be evaluated in this
Context. It creates some of the basic Javascript objects.
*/
scriptContext.initStandardObjects(gameProxy);
/*
Functions provided by a ScriptableObject (such as our
example 'testfunc') are initialized in the following manner.
*/
String[] scriptAvailableFunctions = { "testfunc" };
gameProxy.defineFunctionProperties(scriptAvailableFunctions, ScriptProxy.class, ScriptableObject.DONTENUM);
/*
A "property" is a Javascript object that is exposed through
getters and setters in the ScriptableObject. Rhino
automatically prepends the "set" and "get" terms and
uppercases the first letter, so exact naming is important.
*/
gameProxy.defineProperty("test", ScriptProxy.class, ScriptableObject.DONTENUM);
}
public void render(GameContainer container, Graphics g) {
/*
Here we are using the context (javascript engine) to
evaluate a string. The first parameter is our
ScriptableObject, which is used to provide definitions for
the engine. The second argument is the code to be evaluated.
In this case simply writing "test" evaluates the Javascript
object named "test", which is looked up in our gameProxy,
which passed the result of it's getTest() method to the
Javascript engine.
Since this is the only instruction in the string to be
evaluated it is used as the return value for
evaluateString. To provide flexibility in return type
handling evaluateString returns a java.lang.Object, which is
why the result must be cast back into a String.
The third parameter is a string that describes the source
for the Javascript code being evaluated. This may be a
filename if that is where the string comes from.
The fourth parameter is the starting line number for this
script, which might be useful if a script is being pieced
together from a variety of components.
The last parameter is used to provide a security domain for
the script to run under. I *think* this is used to ensure
that the Javascript code cannot execute certain methods or
instantiate some objects, but haven't done enough research
to be sure. Passing a null value here does not restrict the
evaluation of Javascript code.
*/
String result = (String) scriptContext.evaluateString(gameProxy, "test;", "js", 1, null);
g.drawString("Javascript result: " + result, 40, 120);
}
public void update(GameContainer container, int delta) {
}
public void keyPressed(int key, char c) {
if(key == Input.KEY_ESCAPE) {
/*
The script context will most likely be shut down
properly, but it's a good idea to be neat and tidy,
right?
*/
scriptContext.exit();
System.exit(0);
}
if(key == Input.KEY_SPACE) {
/*
This example is largely similar to the above, except
that now we are calling the javascript function
"testfunc()". This is found and executed on gameProxy,
printing a string to the console."
*/
scriptContext.evaluateString(gameProxy, "testfunc(\"testing console output\");", "js", 5, null);
}
}
public Rhino(String s) {
super(s);
}
public static void main(String[] Args) {
try {
AppGameContainer container = new AppGameContainer(new Rhino("Picnic Invasion!"));
container.setDisplayMode(600,480,false);
// container.setShowFPS(false);
container.setMinimumLogicUpdateInterval(30);
container.start();
} catch (SlickException e) {
e.printStackTrace();
}
}
}
No comments
No comments yet. Be the first.
Leave a reply