Вторник, 26.11.2024, 16:57
Приветствую Вас Гость

Разработка игр c использованием JPCT

Каталог статей

Главная » Статьи » Разработка игр » Скрипты

Использование Lua
Попробовав подключить LuaJava к проекту и получив кучу непонятных проблем из-за того, что я пользуюсь 64 битной ОС, из-за этого я решил использовать библиотеку JNLua. В данной статье будет представлен класс позволяющий использовать Lua в проектах для придания гибкости приложению.
Для начала необходимо скачать библиотеку и необходимые dll с сайта проекта последняя версия 1.0.4, для запуска приложения потребуется сделать 2 шага, во первых необходимо наличие jnlua52.dll и javavm.dll в папке с библотеками прописанной в свойствах VM Djava.library.path= и во вторых вам необходимо скопировать lua52.dll в папку system32 в противном случае проект не запустится, к сожалению размещение lua52.dll в папке библиотек не дает необходимого эффекта поэтому и необходимо скопировать его в system32, надеюсь в следующих версиях это исправят.
JNLua интересен тем, что он позволяет использовать спецификацию JSR 223: Scripting for the JavaTM Platform, достаточно подробно это описано на странице проекта JSR223Provider на основании информации изложенной в этой статье я написал свой класс позволяющий запускать скрипты Lua из Java(в данном примере он выполнен как singelton), вот его код:
Код

public class LuaScript {  
  ScriptEngineManager manager;  
  ScriptEngine engine;
  Compilable compilable;
   
  private static LuaScript instance;
   
  public static synchronized LuaScript getInstance()
  {
  if (instance == null)
  {
  instance = new LuaScript();
  }
  return instance;
  }
   
  private LuaScript()
  {  
  manager = new ScriptEngineManager();
  engine = manager.getEngineByName("Lua");
  if (engine==null)
  {
  Logger.getLogger(getClass().getName()).log(Level.SEVERE, "Can't init LUA");
  }
  compilable = (Compilable) engine;  
  }
   
  public void load(String script)
  {  
  try {  
  CompiledScript compiledScript = compilable.compile(script);  
  compiledScript.eval(engine.getBindings(ScriptContext.ENGINE_SCOPE));
  } catch (ScriptException e) {
  Logger.getLogger(LuaScript.class.getName()).log(Level.WARNING, " error script load\n"+ e.getMessage(),script);  
  }  
  }
   
  public boolean load(File file)
  {
  try {
  ReaderInputStream ris = new ReaderInputStream(new InputStreamReader(new FileInputStream(file)));
  ris.read();
  String str = ris.result.toString();
  load(str);
  return true;
  } catch (FileNotFoundException ex) {
  Logger.getLogger(LuaScript.class.getName()).log(Level.SEVERE, null, ex);
  } catch (IOException ex) {
  Logger.getLogger(LuaScript.class.getName()).log(Level.SEVERE, null, ex);
  }
  return false;
  }
  public boolean isFuntionLoad(String Name)
  {  
  if (engine.getBindings(ScriptContext.ENGINE_SCOPE).containsKey(Name)||
  engine.getBindings(ScriptContext.GLOBAL_SCOPE).containsKey(Name))
  {
  return true;
  }
  else
  {
  return false;
  }
  }
   
  public Object runScriptFunction(String functionName, Object... params)
  {
  Invocable invocable = (Invocable) engine;  
  try {
  //Logger.getLogger(this.getClass().getName()).log(Level.WARNING,"start script function {0}" ,functionName);
  return invocable.invokeFunction(functionName, params);  
  } catch (ScriptException e) {  
  Logger.getLogger(LuaScript.class.getName()).log(Level.WARNING, "{0} run error\n{1}", new Object[]{functionName, e.getMessage()});
  } catch (NoSuchMethodException e) {  
  Logger.getLogger(LuaScript.class.getName()).log(Level.WARNING, "{0} run error\n{1}", new Object[]{functionName, e.getMessage()});
  }  
  return null;
  }
   
  /**
  * запускает скрипт Lua в котором описан интерфейс runnable в отдельном потоке
  * @param LuaInterface
  */
  public void runLuaRunnable(String LuaInterface)
  {
  Invocable invocable = (Invocable) engine;  
  try {  
  engine.eval(LuaInterface);  
  Object luaRunnable = engine.get("runnable");  
  Runnable runnable = invocable.getInterface(luaRunnable, Runnable.class);  
  Thread thread = new Thread(runnable);  
  thread.start();  
  thread.join();  
  } catch (ScriptException e) {  
  e.printStackTrace();  
  } catch (InterruptedException e) {  
  e.printStackTrace();  
  }  
  }  
  /**
  * запускает скрипт Lua в котором описан интерфейс runnable в отдельном потоке ExecutorService пакета java.util.concurrent
  * @param service это ExecutorService из пакета java.util.concurrent
  * @param LuaInterface это наименование интерфейса для запуска.  
  * @return Future если необходимо отследить момент завершения задачи
  */
  public Future runLuaRunnable(ExecutorService service,String LuaInterface)
  {
  Invocable invocable = (Invocable) engine;  
  try {  
  engine.eval(LuaInterface);  
  Object luaRunnable = engine.get("runnable");  
  Runnable runnable = invocable.getInterface(luaRunnable, Runnable.class);  
  return service.submit(runnable);
  } catch (ScriptException e) {  
  e.printStackTrace();  
  return null;
  }  
  }
   
   
  // -- Private classes  
  /**
  * Provides an UTF-8 input stream based on a reader.
  */  
  private static class ReaderInputStream extends InputStream {
  private static final Charset UTF8 = Charset.forName("UTF-16");
  private Reader reader;
  private CharsetEncoder encoder;
  private boolean flushed;
  private CharBuffer charBuffer = CharBuffer.allocate(1024);
  private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
  private StringBuilder result;
  /**
  * Creates a new instance.
  */
  public ReaderInputStream(Reader reader) {
  this.reader = reader;
  encoder = UTF8.newEncoder();
  charBuffer.limit(0);
  byteBuffer.limit(0);
  flushed=true;
  result = new StringBuilder();
  }
  @Override
  public int read() throws IOException {
  if (!byteBuffer.hasRemaining()) {
  if (!charBuffer.hasRemaining()) {
  charBuffer.clear();
  while(reader.read(charBuffer)!=0)
  {
  charBuffer.flip();
  result.append(charBuffer.toString());
  }  
  }  
  }  
  return charBuffer.length();
  }
  }
}

В классе LuaScript определен внутренний класс ReaderInputStream для удобства чтения файлов со скриптами. Загрузка скриптов производится при помощи функции load в качестве параметров она принимает файл или строку содержащую скрипт, основным в данном методе является вызов compiledScript.eval(engine.getBindings(ScriptContext.ENGINE_SCOPE)); в нем происходит проверка скрипта на синтаксический ошибки, и загрузка содержимого в стек Lua, после этого можно вызывать функции Lua используя метод  runScriptFunction(String functionName, Object... params) в случае возникновении ошибок они будут выведены в лог. Также есть метод isFuntionLoad позволяющий проверить наличие Функции Lua в стеке и соответственно возможности ее запуска.

Использования объектов Java в скриптах Lua происходит через использования механизма отражения(reflected), классы и объекты java отражаются в Lua. В коде Lua это выглядит следующим образом:
Код

System = java.require("java.lang.System") -- импортируем класс в Луа //import class into Lua  
print(System:currentTimeMillis()) -- вызываем статический метод //invoke static method  

out = System.out -- чтение статического поля read static field  
out:println("Hello, world!") -- вызов метода println объекта out для вывода строки(равносильно вызову System.out.println("Hello, world!") из java  

StringBuilder = java.require("java.lang.StringBuilder") -- импортируем класс в Луа
sb = StringBuilder:new() -- вызов конструктора  
sb:append("a") -- вызов метода //invoke method  
sb:append("b")  
out:println(sb:toString())  

TimeZone = java.require("java.util.TimeZone") --импортируем класс в Луа
timeZone = TimeZone:getDefault() -- вызов метода
out:println(timeZone.displayName) -- читаем свойство и выводим его в System.out //read property; invokes getDisplayName()  

Calendar = java.require("java.util.Calendar") --импортируем класс в Луа
today = Calendar:getInstance() -- получаем экземпляр класса Calendar из java(изменив объект тут он изменится и в java)
print(tostring(today)) -- invokes Object.toString()  
tomorrow = today:clone()  
tomorrow:add(Calendar.DAY_OF_MONTH, 1)  
assert(today < tomorrow) -- invokes Comparable.compareTo()  

При использовании в скриптах Lua статических переменных объявленных в java убедитесь что они не null для этого пишите код проверки в скриптах Lua чтобы потом долго не разбираться почему у вас при выполнении скрипта вываливается ошибка, пример ниже.
Код
function create(name)
print=name;
local Factory = java.require("modelview.DataFactory")
local tmp = Factory:CreateData(name)
if tmp == nil then return "object not load" end
return tmp
end

Собственно все, на этом данная статья заканчивается.
Категория: Скрипты | Добавил: Gram01 (10.12.2013) | Автор: Gram01
Просмотров: 1633 | Комментарии: 1 | Теги: Lua+java, использование Lua в Java, jnlua+java | Рейтинг: 0.0/0
Всего комментариев: 1
1 Gram01  
0
Исправил баг с загрузкой больших файлов

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа
Категории раздела
JPCT [11]
Раздел о разработке игр на устройства работающие не под управлением Android'а
Сеть [2]
Раздел по вопросам касающимся сетевого взаимодействия приложений на java в контексте разработки игр
Контент [0]
Статьи о работе к контентом при разработки игр
Скрипты [2]
использование скриптов в игровом движке
Разное [1]
различные материалы о разработке игрового движка
Поиск
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0
    Copyright Неведомый Р.А. © 2024 | Рейтинг@Mail.ru