Tuesday, 7 October 2014

Simple Java LuaJ Tutorial

I've been recently playing around with Lua in Java. Here is how you can too.

Recently I had been looking at Lua as a way to enable 3rd parties to add plugins to my software easily and it seems perfect for this. In fact a quick search of my machine shows thousands of lua files which range from simple configuration files through to complex game logic.

The Plan

We are going to make a little program that draws a chart of some data created by a Lua script.

What we will do:

  • Call a Lua script using LuaJ from Java
  • Call a function on a java object inside Lua
  • Draw something using it!
You will need:
  • An IntelliJ Gradle project.
  • An internet connection for downloading dependencies.

Gradle Setup

We need both LuaJ and JFreeChart for this. JFreeChart is a nice and easy way to get a pretty looking graph and is easy to use.

To get them add the below to your dependencies section of the build.gradle

 compile 'org.luaj:luaj-jse:2.0'   
 compile 'jfreechart:jfreechart:1.0.0'  

Lovely.

Lua File

Lets write a simple function to create some data to draw the graph of. Create a file called LuaCode.lua and inside it put the code below.

 function GetLineData(myJavaObject)  
   for i = 0, 2*math.pi, 0.01 do  
     myJavaObject:addValue(math.sin(i));  
   end  
 end  

I'm sure you can see whats happening here. We are passing in a java object and calling the addValue function on it with the value that we want to show in the chart. This should put sin wave values into java object.

Java

The class we manipulated in Lua needs to be created. Lets do that

 public class LineData {  
      public final List<Float> valueList = new ArrayList<Float>();  
      public void addValue(float value){  
           valueList.add(value);  
      }  
 }  


We need a java function that will convert this to something that Lua can understand and then call the Lua function.

 public LineData callGetLuaLine() {  
      LineData lineValue = new LineData();  
      try {  
           LuaValue luaGlobals = JsePlatform.standardGlobals();  
           luaGlobals.get("dofile").call(LuaValue.valueOf("./LuaCode.lua"));
  
           LuaValue luaVals = CoerceJavaToLua.coerce(lineValue);  

           LuaValue luaGetLine = luaGlobals.get("GetLineData");  
           if (!luaGetLine.isnil()) {  
                luaGetLine.call(luaVals);  
           } else {  
                System.out.println("Lua function not found");  
           }  
      } catch (LuaError e){  
           e.printStackTrace();  
      }  
      return lineValue;  
 }  

What are we doing here?
  1. First we initialise the standard globals
  2. Load in our lua file in.
  3. Using CoerceJavaToLua.coerce() a LuaJ representation of our Java class is created.
  4. We get a reference to our Lua function called GetLineData.
  5. If the function is non null we call it and pass in our Lua representation of the Java Class.

Drawing the Line

That it for lua. If you don't need, want, or care about seeing a quite frankly beautifully rendered sine line then stop here.

The JFreeChart library is capable of drawing all sorts of nice things. We will settle on an simple x-y chart for our visualisation.

Add the following code into a class that extends something like a JDialog or JFrame and then calling it using the LineData object you have created previously. Make sure you have the usual boilerplate stuff to make the window visible.

 public void createChart(LineData lineValue){  
      XYSeries series = new XYSeries("Lua Sin");  
      for (int i = 0; i < lineValue.valueList.size(); i++) {  
           series.add(i, lineValue.valueList.get(i));  
      }  
      XYSeriesCollection dataset = new XYSeriesCollection();  
      dataset.addSeries(series);  
      JFreeChart chart = ChartFactory.createXYLineChart(null, null, null, dataset, PlotOrientation.VERTICAL, true, true, true);  
      ChartPanel chartpanel = new ChartPanel(chart);  
      chartpanel.setDomainZoomable(true);  
      add(chartpanel);  
      pack();  
 }  

This populates the XYSeries object and creates a chart using the ChartFactory. Finally we add it to the dialog and tell it to repack itself.


Links

For a link to the IntelliJ project and source click here.