Aladdin_XLua
[Unity XLua] 热更新 XLua 入门 (一) — 基础篇
Предисловие
Некоторое время назад Tencent открыл исходный код внутреннего фреймворка для горячего обновления XLua в сообществе разработчиков Unity. Это вызвало бурное обсуждение и получило поддержку многих разработчиков. Я, конечно же, с любопытством начал изучать его. Позже я также опубликую расширенную версию проекта на git, чтобы мы могли учиться и общаться вместе! Здесь я хотел бы выразить свою благодарность автору XLua за создание такого полезного фреймворка!
Связанные ссылки:
Мои взгляды на XLua:
Расширение поддержки NGUI в XLua В настоящее время существует мало открытых фреймворков горячего обновления Lua, которые поддерживают NGUI. Возможно, сейчас тенденция заключается в использовании собственного UGUI. Однако некоторые разработчики, использующие NGUI, могут предпочесть продолжать использовать его. Хотя NGUI использовался в течение длительного времени, пример использования lua в XLua уже поддерживает UGUI. Здесь я дополню его, чтобы он поддерживал разработку NGUI. В будущем я добавлю больше примеров UGUI. Давайте сначала посмотрим на эффект интерфейса, который был расширен для поддержки NGUI, а затем объясним, как сделать так, чтобы XLua поддерживал сторонние плагины.
Эффект изображения:
Здесь напишите описание изображения.
Быстрый старт Прежде чем изучать что-то новое, лучше всего сначала изучить множество обучающих документов, написанных автором XLua. Они включают примеры, wiki и issu. Если у вас есть какие-либо вопросы, вы можете присоединиться к группе в конце статьи, чтобы обсудить и изучить их вместе.
1. Создание пользовательских классов C#, доступных для Lua Здесь вы можете изучить пример в Test, предоставленный автором. Он довольно подробный, но я всё равно хочу записать свой собственный процесс.
(1) Способ с использованием атрибутов XLua поддерживает использование атрибутов для маркировки, чтобы пользовательские классы были доступны для Lua. C#:
[LuaCallCSharp]
public class CSModelWithAttribute
{
public static void SayHello1()
{
Debug.Log("Hello Aladdin_XLua, I am static model function");
}
public void SayHello2()
{
Debug.Log("Hello Aladdin_XLua, I am model function");
}
public void SayHello3(string s)
{
Debug.Log("Hello Aladdin_XLua, I am model function whih param:" + s);
}
public string SayHello4(string s)
{
Debug.Log("Hello Aladdin_XLua, 我是具有返回值的CS方法:" + s);
return "你好,我获得了lua,我是C#";
}
public void SayHelloWithRefParam(ref string s)
{
Debug.Log("传入的参数是:" + s);
s = "Hello 我是C#";
}
public string SayHelloWithRefParamAndReturnString(ref string s)
{
Debug.Log("传入的参数是:" + s);
s = "Hello 我是C#";
return "我是返回的字符串";
}
public void SayHelloWithOutParam(out string s)
{
s = "Hello,我是C#";
Debug.Log("Hello Aladdin_XLua, I am model function whih out param:" + s);
}
}
После добавления атрибута программа автоматически найдёт класс с атрибутом при запуске и добавит его в стек Lua, чтобы мы могли получить доступ к пользовательским классам и методам C# через Lua.
Lua доступ:
using UnityEngine;
using System.Collections;
using XLua;
public class SelfExampleSrc : MonoBehaviour
{
LuaEnv luaenv = new LuaEnv();
void Start()
{
luaenv.DoString(@"
print('Lua访问特性标记的对象方法')
local luaM2 = CS.CSModelWithAttribute
local luaO2 = luaM2()
luaM2:SayHello1()
luaO2:SayHello2()
luaO2:SayHello3('我是阿拉丁') --每次添加一个CS方法时候都要重新Generate一下啊
--测试字符串返回
local value = luaO2:SayHello4('你好,我是lua')
print(value)
--测试ref
local inputValue = '你好,我是lua'
local outputValue = luaO2:SayHelloWithRefParam(inputValue)
print(outputValue) --lua是通过字符串返回
local outValue1,outValue2 = luaO2:SayHelloWithRefParamAndReturnString(inputValue)
print(outValue1)
print(outValue2)
--测试out
inputValue = '我是测试lua'
outputValue = luaO2:SayHelloWithOutParam(inputValue)
print(outputValue)
local luaM3 = CS.CSModelTest
local luaO3 = luaM3()
luaO3.TestDelegate('lua中测试委托')
luaO3.onClick = function(obj)
print('hello 我是lua')
print(obj)
end
luaO3.onClick('我是lua')
");
}
}
(2) Метод обёртки Если мы сами пишем код C#, мы можем добавить атрибут, чтобы сделать класс доступным для Lua, что довольно удобно. Но если мы используем сторонний плагин, как быстро сделать его доступным для XLua? Мы можем использовать метод обёртки Generate, который также используется другими фреймворками Lua.
C#:
namespace Aladdin_XLua
{
public class CSModel
{
public void SayHello()
{
Debug.Log("Hello Aladdin_XLua");
}
}
}
Lua:
print('Lua доступ к именованному объекту / статический метод') local luaModel = CS.Aladdin_XLua.CSModel local luaObj = luaModel() luaObj:SayHello()
**б) Доступ к классу без пространства имён**
C#:
public class CSModelWidhoutNameSpace { public void SayHello() { Debug.Log("Hello Aladdin_XLua without Namespace"); } }
Lua:
print('Lua доступ к методу объекта без пространства имен') local luaM = CS.CSModelWidhoutNameSpace local luaO = luaM() luaO:SayHello()
«Если нет пространства имён, то после CS идёт имя класса. На самом деле CS — это ещё один уровень пространства имён, просто автор помог нам с разделением».
**3. Тип делегата**
C#
public class CSModelTest { public SelfVoidDelegate onClick; public delegate void SelfVoidDelegate(GameObject go); void OnClick() { Debug.Log("Тест"); }
public Action<string> TestDelegate = (param) =>
{
Debug.log("TestDelegate in c#:" + param);
};
}
Делегат фактически является типом, равным классу, поэтому мы должны обрабатывать его так же, как класс. Это можно сделать с помощью добавления атрибутов или через механизм Wrap. Здесь делегат находится внутри класса, но на самом деле он может быть помещён непосредственно в пространство имён. Так работает .NET-библиотека, хотя, если посмотреть исходный код NGUI, мы увидим, что все кнопки используют этот подход для обработки событий.
Lua
local luaM3 = CS.CSModelTest local luaO3 = luaM3() luaO3.TestDelegate('lua тест делегата')
luaO3.onClick = function(obj) print('hello Я — lua') print(obj) end luaO3.onClick('Я — lua')
**4. Функции с параметрами ref и out**
Поскольку Lua — это язык со слабой типизацией, в котором нет такого разнообразия типов, как в C#, иногда возникают проблемы с обработкой параметров. В XLua есть раздел Issues, где автор отвечает на вопросы пользователей. Ниже приведён пример того, как функции с параметрами ref и out обрабатываются в Lua.
C#
public void SayHelloWithRefParam(ref string s) { Debug.Log("Переданный параметр: " + s); s = "Привет, я — C#"; }
public string SayHelloWithRefParamAndReturnString(ref string s) { Debug.Log("Переданный параметр: " + s); s = "Привет, я — C#"; return "Я — возвращаемая строка"; }
public void SayHelloWithOutParam(out string s) { s = "Привет, это — C#"; Debug.Log("Привет, Aladdin_XLua, я — функция модели с параметром out: " + s); }
Сначала я думал, что Lua вернёт изменённое значение параметра ref, переданного в функцию. Но этого не произошло. Автор подсказал мне, что Lua возвращает изменённое значение через возвращаемое значение функции. Если функция уже имеет возвращаемое значение, то последним параметром будет либо параметр ref, либо out.
Lua
-- Тестирование ref local inputValue = 'Привет, я — lua' local outputValue = luaO2:SayHelloWithRefParam(inputValue) print(outputValue) -- lua возвращает результат через строку
local outValue1, outValue2 = luaO2:SayHelloWithRefParamAndReturnString(inputValue) print(outValue1) print(outValue2)
-- Тестирование out inputValue = 'Я — тестовый lua' outputValue = luaO2:SayHelloWithOutParam(inputValue) print(outputValue)
*Примечание: в запросе отсутствует информация о том, какой именно фрагмент текста необходимо перевести. Поэтому ответ содержит перевод всего текста.* **b) Построить два пользовательских интерфейса (UI), логика интерфейса на C#, Lua вызывает методы C# в логике вызова интерфейса.**
**C#:**
using UnityEngine; using System.Collections; using XLua; public class AsyncBuy : MonoBehaviour { LuaEnv luaenv = null;
void Start()
{
luaenv = new LuaEnv();
luaenv.DoString("require 'async_buy'");
}
// Update is called once per frame
void Update()
{
if (luaenv != null)
{
luaenv.Tick();
}
}
}
**Логика панели:**
using UnityEngine; using UnityEngine.UI; using XLua; using System.Collections.Generic; using System; using UnityEngine.Events;
public class MessagePanel : MonoBehaviour
{
///
/// <summary>
/// Показать подтверждающее окно
/// </summary>
/// <param name="message"></param>
/// <param name="title"></param>
/// <param name="onFinished"></param>
public static void ShowConfirmPanel(string message, string title, Action<bool> onFinished = null)
{
var rootPanel = GameObject.Find("Panel").transform;
var confirmPanel = rootPanel.Find("ConfirmPanel");
if (confirmPanel == null)
{
confirmPanel = (Instantiate(Resources.Load("ConfirmPanel")) as GameObject).transform;
confirmPanel.gameObject.name = "ConfirmPanel";
confirmPanel.SetParent(rootPanel);
confirmPanel.localPosition = Vector3.zero;
confirmPanel.localScale = Vector3.one;
}
confirmPanel.Find("Title").GetComponent<UILabel>().text = title;
confirmPanel.Find("Content").GetComponent<UILabel>().text = message;
confirmPanel.gameObject.SetActive(true);
if (onFinished != null)
{
var confirmBtn = confirmPanel.Find("BtnBuy").GetComponent<UIButton>();
var cancelBtn = confirmPanel.Find("CancelBuy").GetComponent<UIButton>();
UIEventListener.Get(confirmBtn.gameObject).onClick = go =>
{
onFinished(true);
confirmPanel.gameObject.SetActive(false);
};
UIEventListener.Get(cancelBtn.gameObject).onClick = go =>
{
confirmPanel.gameObject.SetActive(false);
};
}
}
}
**Lua:**
lua-файл можно поместить в соответствующие ресурсы.
async_buy.lua
``` **Перевод кода на русский язык:**
async_recharge -------------------------async_recharge----------------------------- local function async_recharge(num, cb) --模拟的异步充值 print('request server...') cb(true, num) end
local recharge = util.async_to_sync(async_recharge) -------------------------async_recharge end---------------------------- local buy = function() message_panel.alert("余额提醒", "您余额不足,请充值!") if message_panel.confirm("确认充值10元吗?", "确认框" ) then local r1, r2 = recharge(10) print('recharge result', r1, r2) message_panel.alert("提示", "充值成功!") else print('cancel') message_panel.alert("提示", "取消充值!") end end
CS.UIEventListener.Get(CS.UnityEngine.GameObject.Find("BtnBuy").gameObject).onClick = util.coroutine_call(buy)
**Перевод message_panel.lua:**
local util = require 'xlua.util'
local sync_alert = util.async_to_sync(CS.MessagePanel.ShowAlertPanel) local sync_confirm = util.async_to_sync(CS.MessagePanel.ShowConfirmPanel)
--构造alert和confirm函数 return { alert = function(title, message) if not message then title, message = message, title end sync_alert(message,title) end;
confirm = function(title, message)
local ret = sync_confirm(title,message)
return ret == true
end;
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )