|
Loxodon.Framework.XLua 是一个XLua的开源的MVVM框架,它作为我的Unity3D的MVVM框架Loxodon.Framework的插件来使用。使用这个框架,可以做到完全使用Lua来编写游戏逻辑,并且遵循MVVM的开发习惯,支持数据绑定,有感兴趣的朋友可以去github下载。
下面是代码示例
require("framework.System")
local Context = CS.Loxodon.Framework.Contexts.Context
local LuaBindingServiceBundle = CS.Loxodon.Framework.Binding.LuaBindingServiceBundle
local ObservableObject = require("framework.ObservableObject")
local ObservableDictionary = require("framework.ObservableDictionary")
---
--创建一个Account子视图模型
--@module Account
local Account = class("Account",ObservableObject)
function Account:ctor(t)
--执行父类ObservableObject的构造函数,这个重要,否则无法监听数据改变
Account.super.ctor(self,t)
if not (t and type(t)=="table") then
self.id = 0
self.username = ""
self.Password = ""
self.email = ""
self.birthday = os.time({year =1970, month = 00, day =00, hour =00, min =00, sec = 00})
self.address = ""
end
end
---
--创建一个数据绑定示例的视图模型
--@module DatabindingViewModel
local DatabindingViewModel = class("DatabindingViewModel",ObservableObject)
function DatabindingViewModel:ctor(t)
--执行父类ObservableObject的构造函数,这个重要,否则无法监听数据改变
DatabindingViewModel.super.ctor(self,t)
if not (t and type(t)=="table") then
self.account = Account()
self.remember = false
self.username = ""
self.email = ""
self.errors = ObservableDictionary()
end
end
function DatabindingViewModel:submit()
if #self.username < 1 then
--注意C#字典类型的使用方式,通过set_Item或者get_Item 访问
self.errors:set_Item(&#34;errorMessage&#34;,&#34;Please enter a valid username.&#34;)
return
end
if #self.email < 1 then
--注意C#字典类型的使用方式,通过set_Item或者get_Item 访问
self.errors:set_Item(&#34;errorMessage&#34;,&#34;Please enter a valid email.&#34;)
return
end
self.errors:Clear()
self.account.username = self.username
self.account.email = self.email
self.account.remember = self.remember
end
---
--创建一个数据绑定视图,扩展DatabindingExample.cs 对象,这里的target是从C#脚本传过来的
--@module DatabindingExample
local M = class(&#34;DatabindingExample&#34;,target)
function M:awake()
local context = Context.GetApplicationContext()
local container = context:GetContainer()
--初始化Lua的数据绑定服务,一般建议在游戏的C#启动脚本创建
local bundle = LuaBindingServiceBundle(container)
bundle:Start();
end
function M:start()
--初始化Account子视图模型
local account = Account({
id = 1,
username = &#34;test&#34;,
password = &#34;test&#34;,
email = &#34;yangpc.china@gmail.com&#34;,
birthday = os.time({year =2000, month = 03, day =03, hour =00, min =00, sec = 00}),
address = &#34;beijing&#34;,
remember = true
})
--初始化视图模型
self.viewModel = DatabindingViewModel({
account = account,
username = &#34;&#34;,
email = &#34;&#34;,
remember = true,
errors = ObservableDictionary()
})
self:BindingContext().DataContext = self.viewModel
--进行数据绑定
local bindingSet = self:CreateBindingSet();
bindingSet:Bind(self.username):For(&#34;text&#34;):To(&#34;account.username&#34;):OneWay()
bindingSet:Bind(self.password):For(&#34;text&#34;):To(&#34;account.password&#34;):OneWay()
bindingSet:Bind(self.email):For(&#34;text&#34;):To(&#34;account.email&#34;):OneWay()
bindingSet:Bind(self.remember):For(&#34;text&#34;):To(&#34;account.remember&#34;):OneWay()
bindingSet:Bind(self.birthday):For(&#34;text&#34;):ToExpression(function(vm)
return os.date(&#34;%Y-%m-%d&#34;,vm.account.birthday)
end ,&#34;account.birthday&#34;):OneWay()
bindingSet:Bind(self.address):For(&#34;text&#34;):To(&#34;account.address&#34;):OneWay()
bindingSet:Bind(self.errorMessage):For(&#34;text&#34;):To(&#34;errors[&#39;errorMessage&#39;]&#34;):OneWay()
bindingSet:Bind(self.usernameInput):For(&#34;text&#34;,&#34;onEndEdit&#34;):To(&#34;username&#34;):TwoWay()
bindingSet:Bind(self.emailInput):For(&#34;text&#34;,&#34;onEndEdit&#34;):To(&#34;email&#34;):TwoWay()
bindingSet:Bind(self.rememberInput):For(&#34;isOn&#34;,&#34;onValueChanged&#34;):To(&#34;remember&#34;):TwoWay()
bindingSet:Bind(self.submit):For(&#34;onClick&#34;):To(&#34;submit&#34;):OneWay()
bindingSet:Build()
end
return M
require(&#34;framework.System&#34;)
local util = require(&#34;xlua.util&#34;)
local Executors = CS.Loxodon.Framework.Execution.Executors
local ProgressResult = CS.Loxodon.Framework.Asynchronous[&#34;ProgressResult`1[System.Single]&#34;]
---
-- 在Lua中使用协程的例子
-- 将一个Lua函数通过util.cs_generator包装成一个C#的迭代器IEnumerator,然后用Executors调用
--@module CoroutineExample
local M=class(&#34;CoroutineExample&#34;,target)
function M:start()
--[[--
在C#脚本LuaBehaviour中定义的属性或者是通过Variables配置而虚拟出来的属性,都可以在Lua脚本中通过self.xxx 来访问
如下示例,通过self.startButton self.stopButton 访问启动和停止按钮,通过self.slider 访问滑动条
]]
self.startButton.onClick:AddListener(function()
print(&#34;onClick Start&#34;)
self.loadResult = self:Load()
self.loadResult:Callbackable():OnProgressCallback(function(progress)
--printf(&#34;progress:%0.2f&#34;,progress) -- 打印进度,%0.2f 是小数点2位的浮点数
self.slider.value = progress
end)
end)
self.stopButton.onClick:AddListener(function()
if self.loadResult then
self.loadResult:Cancel()
self.loadResult = nil
end
print(&#34;onClick Stop&#34;)
end)
print(&#34;lua start...&#34;)
end
---
-- 加载
function M:Load()
local result = ProgressResult(true)
Executors.RunOnCoroutineNoReturn(util.cs_generator(function() self:doLoad(result) end))
return result
end
---
-- 模拟一个加载任务
function M:doLoad(promise)
print(&#34;task start&#34;)
for i = 1, 50 do
--如果有取消请求,即调用了ProgressResult的Cancel()函数,则终止任务
if promise.IsCancellationRequested then
break
end
promise:UpdateProgress(i/50) --更新任务进度
--这里coroutine.yield中可以不传入参数,则表示是每帧执行一次,
--也可以传入所有继承了YieldInstruction的参数,如:UnityEngine.WaitForSeconds(0.1)
--还可以传入一个IEnumerator对象,如:AsyncResult.WaitForDone()
coroutine.yield(CS.UnityEngine.WaitForSeconds(0.1))--等待0.1秒
end
promise:UpdateProgress(1)
promise:SetResult() --设置任务执行完成
print(&#34;task end&#34;)
end
return M
LoginViewModel.lua
require(&#34;framework.System&#34;)
local Context = CS.Loxodon.Framework.Contexts.Context
local SimpleCommand = CS.Loxodon.Framework.Commands.SimpleCommand
local AsyncTask = CS.Loxodon.Framework.Asynchronous[&#34;AsyncTask`1[System.Object]&#34;]
local ObservableObject = require(&#34;framework.ObservableObject&#34;)
local ObservableDictionary = require(&#34;framework.ObservableDictionary&#34;)
local InteractionRequest = require(&#34;framework.InteractionRequest&#34;)
---
--模块
--@module LoginViewModel
local M=class(&#34;LoginViewModel&#34;,ObservableObject)
--[[--
构造函数
@param #table self
@param #table t 初始化参数
]]
function M:ctor(t)
M.super.ctor(self,t)
self.username = self.globalPreferences:GetString(&#34;LAST_USERNAME&#34;, &#34;&#34;);
self.password = &#34;&#34;
self.account = nil
self.errors = ObservableDictionary()
self.loginCommand = SimpleCommand(function() self:login() end,true)
self.cancelCommand = SimpleCommand(function() self.interactionFinished:Raise(nil) end,true)
self.interactionFinished = InteractionRequest(self)
self.toastRequest = InteractionRequest(self)
end
function M:validateUsername()
if not self.username or self.username == &#39;&#39; or not string.gmatch(self.username, &#34;^[a-zA-Z0-9_-]{4,12}$&#34;) then
self.errors:set_Item(&#34;username&#34;,self.localization:GetText(&#34;login.validation.username.error&#34;, &#34;Please enter a valid username.&#34;))
return false
else
self.errors:Remove(&#34;username&#34;);
return true
end
end
function M:validatePassword()
if not self.password or self.password == &#39;&#39; or not string.gmatch(self.password, &#34;^[a-zA-Z0-9_-]{4,12}$&#34;) then
self.errors:set_Item(&#34;password&#34;,self.localization:GetText(&#34;login.validation.password.error&#34;, &#34;Please enter a valid password.&#34;))
return false
else
self.errors:Remove(&#34;password&#34;);
return true
end
end
function M:login()
self.account = nil;
self.loginCommand.Enabled = false --by databinding, auto set button.interactable = false.
local task = nil
if not (self:validateUsername() and self:validatePassword()) then
task = AsyncTask(function() return nil end)
else
task = AsyncTask(function()
local result = self.accountService:Login(self.username, self.password)
local account = result:Synchronized():WaitForResult()
if account then
Context.GetApplicationContext():GetMainLoopExcutor():RunOnMainThread(function()
self.globalPreferences:SetString(&#34;LAST_USERNAME&#34;, self.username)
self.globalPreferences:Save()
end)
end
return account
end)
end
task:OnPostExecute(function(account)
if account then
--login success
self.account = account
self.interactionFinished:Raise(nil) --Interaction completed, request to close the login window
else
--Login failure
local tipContent = self.localization:GetText(&#34;login.failure.tip&#34;, &#34;Login failure.&#34;)
self.toastRequest:Raise(tipContent) --show toast
end
end):OnError(function(e)
local tipContent = self.localization:GetText(&#34;login.exception.tip&#34;, &#34;Login exception.&#34;)
self.toastRequest:Raise(tipContent) --show toast
end):OnFinish(function()
self.loginCommand.Enabled = true --by databinding, auto set button.interactable = true.
end):Start()
end
return M
LoginWindow.lua
require(&#34;framework.System&#34;)
local Loading = CS.Loxodon.Framework.Views.Loading
local Toast = CS.Loxodon.Framework.Views.Toast
---
--模块
--@module LoginWindow
local M=class(&#34;LoginWindow&#34;,target)
function M:onCreate(bundle)
local bindingSet = self:CreateBindingSet();
bindingSet:Bind():For(&#34;onInteractionFinished&#34;):To(&#34;interactionFinished&#34;)
bindingSet:Bind():For(&#34;onToastShow&#34;):To(&#34;toastRequest&#34;)
bindingSet:Bind(self.username):For (&#34;text&#34;, &#34;onEndEdit&#34;):To (&#34;username&#34;):TwoWay ()
bindingSet:Bind(self.usernameErrorPrompt):For (&#34;text&#34;):To (&#34;errors[&#39;username&#39;]&#34;):OneWay ()
bindingSet:Bind(self.password):For (&#34;text&#34;,&#34;onEndEdit&#34;):To (&#34;password&#34;):TwoWay ()
bindingSet:Bind(self.passwordErrorPrompt):For (&#34;text&#34;):To (&#34;errors[&#39;password&#39;]&#34;):OneWay ()
bindingSet:Bind(self.confirmButton):For (&#34;onClick&#34;):To (&#34;loginCommand&#34;)
bindingSet:Bind(self.cancelButton):For (&#34;onClick&#34;):To (&#34;cancelCommand&#34;)
bindingSet:Build()
end
function M:onInteractionFinished(sender, args)
self:Dismiss()
end
function M:onToastShow(sender, args)
local notification = args.Context
if not notification then
return
end
Toast.Show(self, notification, 2);
end
return M下载和安装
请在github下载项目 Loxodon.Framework,在Docs/XLua目录下面有个插件包Loxodon.Framework.XLua,安装之后,就可以完全使用Lua来开发游戏,安装步骤请看Docs/XLua/Readme 文件,如果疑问,请加技术支持群,在项目介绍页面能看到。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|