Calmer的文章

  • 首页
  • 文章归档
  • 关于页面

  • 搜索
体验游戏 笔记 推荐 工具链 工具使用 小游戏 插件 UI 软件 教程

XLua+UGUI框架

发表于 2020-04-05 | 分类于 游戏开发 | 0 | 阅读次数 1491

前言

在现在商业项目中,Lua被使用的很多,不光是他可以很快的书写逻辑,而且能够方便的进行热更新等,也被证实了在很多成功项目案例中。
同样前几年NGUI被应用与Unity很多,随着Unity对自己原生UI的完善,UGUI也越来越容易被大家接受,也便于被大家使用。这篇就介绍UGUI+XLua的UI框架。

还有FairyGUI也是很不错的,以后有时间再做介绍。


搭建框架

  • 导入XLua:https://github.com/Tencent/xLua

  • 添加两个空的场景:驱动场景 Drivers和UI面板UGameStart场景

  • 将Drivers和UGameStart场景添加到Build Settings中
    UI框架Scene添加00.jpg

  • 编写代码Drivers.cs(主要用于设备的适配等,还要包括一些更新判断等)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using UnityEngine.SceneManagement;
public class Drivers : MonoBehaviour
{

    //主程序逻辑入口类
    public string MainProc = "UMain";

    private Assembly assembly;

    private void Start()
    {
        //防止加载场景后该脚本失效,加载完成后再销毁
        DontDestroyOnLoad(gameObject);

        //设配相关操作

        //加载场景,开始游戏主逻辑
        StartCoroutine(OnStart());
    }

    private IEnumerator OnStart()
    {
        assembly = Assembly.Load("Assembly-CSharp");
        yield return StartCoroutine(LoadingScene());
        GameObject camera = Camera.main.gameObject;
        DontDestroyOnLoad(camera);
        //主相机上添加主逻辑脚本
        camera.AddComponent(assembly.GetType(MainProc));
        Destroy(gameObject);
    }

    //加载游戏逻辑场景UGameStart
    private IEnumerator LoadingScene()
    {
        AsyncOperation ao = SceneManager.LoadSceneAsync("UGameStart");
        yield return ao;
    }
}

  • 编写UMain.cs,UMainModule.cs,AppBase.cs,CAppModule.cs
    (主要用于启动游戏的主逻辑,控制游戏模块,以及Update等方法的驱动)

UMain:AppBase 挂在MainCamera上,进行驱动

AppBase对CAppModule进行管理,继承于MonoBehaviour

UMainModule中添加相关模块 其中的模块都继承与CAppModule

CAppModule提供几个需要实现的方法
Init Destroy Update LateUpdate FixedUpdate

  • 编辑场景UGameStart
    • 修改MainCamera的Culling Mask 去掉UI可见
    • 创建EmptyGameObject 归位0,0,0 ,命名为UIRoot
    • 在UIRoot下创建Camera(UICamera),设置Culling Mask为只可见UI,并添加设置 Tag:UICamera,Layer:UI
    • UIRoot下添加Canvas,并设置Canvas组件的Render Mode为Screen Space-Camera,将UICamera赋值
    • 设置Canvas Scaler组件 UI Scale Mode为:Scale With Screen Size:设置分辨率为750x1344(这里需要后期读取设备属性进行动态修改)
    • 设置Graphic RayCaster组件 Blocking Mask为:UI 和Ignore Raycast
    • 新建几个UI显示的层级:CloseLayer,LowLayer,MiddleLayer,HighLayer,TipLayer等,显示层级逐一提高。
    • CloseLayer 设置RectTranform Left Top Right Bottom 分为-5000,5000,5000,-5000 为不见层
    • LowLayer设置PosZ为-500 MiddleLayer:-1000 HighLayer:-1500 TipLayer:-2000,并设置他们的Canvas组件:勾选Override Sorting,SortingLayer分别设置为LowLayer,MiddleLayer,HighLayer,TipLayer(需要添加上上面4个层)
    • 以上完成UGameStart编辑,可自行扩展,保存场景
  • 接入XLua
    • 在UMainModule.cs中添加LuaModule:CAppModule
using System;
using System.IO;
using UnityEngine;
using XLua;


//UMain的模块类

/// <summary>
/// Lua模块
/// </summary>
public class LuaModule : CAppModule
{
    private static LuaEnv luaEnv;
    public static LuaTable CurEnvGlobal()
    {
        if (luaEnv != null)
        {
            return luaEnv.Global;
        }
        return null;
    }

    [CSharpCallLua]
    private delegate void UpdateD(float time, float unscaleTime, float deltaTime, float unscaleDeltaTime, float realtimeSinceStartUp);
    [CSharpCallLua]
    private delegate void LateUpdateD();
    [CSharpCallLua]
    private delegate void FixedUpdateD(float fixedDeltaTime);

    private UpdateD updateD = null;
    private LateUpdateD lateUpdateD = null;
    private FixedUpdateD fixedUpdateD = null;

    public LuaModule()
    { 
    }

    private Byte[] MyLoader(ref string filepath)
    {
        filepath = Application.dataPath + "/Lua/" + filepath.Replace('.', '/') + ".lua";
        if(File.Exists(filepath))
        {
            return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(filepath));
        }
        return null;
    }

    public override void Init()
    {
        name = "LuaModule";
        luaEnv = new LuaEnv();
        luaEnv.AddLoader(MyLoader);
        try
        {
            //该LuaStart 为调用的第一个LuaStart.lua文件
            luaEnv.DoString("require 'LuaStart'");
        }
        catch(Exception e)
        {
            Debug.Log(e);
            return;
        }

        updateD = luaEnv.Global.GetInPath<UpdateD>("Update");
        fixedUpdateD = luaEnv.Global.GetInPath<FixedUpdateD>("FixedUpdate");
        lateUpdateD = luaEnv.Global.GetInPath<LateUpdateD>("LateUpdate");

    }

    public override void Update()
    {
        updateD?.Invoke(Time.time,Time.unscaledTime,Time.deltaTime,Time.unscaledDeltaTime,Time.realtimeSinceStartup);
        if(luaEnv!=null)
        {
            luaEnv.Tick();
        }
    }

    public override void LateUpdate()
    {
        lateUpdateD?.Invoke();
    }

    public override void FixedUpdate()
    {
        fixedUpdateD?.Invoke(Time.fixedDeltaTime);
    }

    public override void Destroy()
    {
        updateD = null;
        fixedUpdateD = null;
        lateUpdateD = null;
        luaEnv.Dispose();
        luaEnv = null;
    }

    public void StartGame()
    {
        luaEnv.Global.Get<LuaFunction>("StartGame").Call();
    }

    public void ExitGame()
    {
        luaEnv.Global.Get<LuaFunction>("ExitGame").Call();
    }
}

在UMain.cs中初始化,调用StartGame即可开始Lua游戏逻辑
至此C#层的启动逻辑书写完毕。

扩展:C#层给与了充足的模块扩展空间,之后还需要封装网络层

  • 编写Lua相关文件
    • LuaStart.lua
    --设置垃圾回收的参数
    
    --其他参数
    
    print("加载成功")
    
    require("Main")
    
    • Main.lua
    function Update(time,unscaledTime,deltaTime,unscaledDeltaTime,realtimeSinceStartup)
    
    end
    
    function LateUpdate()
    
    end
    
    function FixedUpdate(fixedDeltaTime)
    
    end
    
    function Init()
    
    end
    
    function StartGame()
        print("StartGame")
    end
    
    function ExitGame()
        print("ExitGame")
    end
    

完成以上:如果出现InvalidCastExcaption:This type must add to CsharpCallLua...错误:1.File->Build Settings->Player Setting->OtherSettings->Api Compatibility Level*改为 .NET 4.x;2.XLua->Clear Generated Code即可。
运行,即可加载LuaStart,以及使用Lua中的一些函数。

UI框架XLua接入.jpg


LuaUI框架封装

  • 在Lua文件夹下创建Core->UI文件夹,存放UI框架核心类
  • 在Lua下创建LuaInclude.lua与CSInclude.lua分别用于Lua的载入与CS类的引用
  • 在Lua->Core文件夹下创建Class.lua (lua面向对象Class相关方法)和CoreInclude (用于引用Core文件夹中的Lua文件)
  • Lua->Core->UI目录下创建InterfaceView.lua(UI类接口),BaseView.lua(基础UI类) ,UIClassHelper.lua(UI类助手类),UIManager(UI的创建,销毁等)
  • 在Lua下创建Module文件夹,用于存放UI模块。
  • 在Lua->Module 下创建ModuleInclude.lua(用于模块的导入),再创建LoginView文件夹(用登录页面作为范例)
  • 再Lua->Module->LoginView下创建:LoginControl.lua,LoginDefine.lua,LoginEvent.lua,LoginModel.lua,LoginView.lua,RegisterView.lua,LoginViewInclude.lua

框架核心:每个模块应该有以下文件
1.xxxControl.lua:该lua用于与后端进行交互,书写该模块网络协议的监听
2.xxxModel.lua:该lua用于该页面的动态数据存储,例如红点数据,同时提供其他页面从该页面数据中获取数据的方法
3.xxxDefine.lua:该lua用于该页面的静态数据定义,例如子弹的上限值(策划后期可能会更改)
4.xxxEvent.lua:该lua用于该页面的相关事件声明,例如LoginEvent.LoginFinish(登录完成事件)
5.xxxView.lua:该lua用于每个模块下相关的页面定义,主要书写页面的具体业务逻辑
6.xxxInclude.lua:该lua用于引入该文件夹下的lua文件,便于管理

具体项目结构如下
UI框架XLua核心UI框架.jpg


简单封装资源加载工具(ResourceManager)和UGUI工具(UGUITools)

  • ResourceManager.cs
using UnityEngine;
public static class ResourceManager
{
    public static Transform LoadUIPrefab(string name)
    {
        return Resources.Load<Transform>(name);
    }
    
    public static Sprite LoadSprite(string path)
    {
        return Resources.Load<Sprite>(path);
    }
}
  • UGUITools.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public static class UGUITools
{
    public static GameObject FindChild(GameObject obj,string path)
    {
        if(obj!=null)
        {
            Transform tf = obj.transform.Find(path);
            if (tf != null)
                return tf.gameObject;
        }
        return null;
    }

    public static Component FindInChild(string componentTypeName,GameObject gameObject,string path="")
    {
        Transform tf;
        Component comp;
        if(string.IsNullOrEmpty(path))
        {
            tf = gameObject.transform;
        }
        else
        {
            tf = gameObject.transform.Find(path);
        }
        if (tf!=null)
        {
            comp = tf.GetComponent(componentTypeName);
            if (comp != null)
                return comp;
        }
        return null;
    }

    public static bool IsNil(object obj)
    {
        if(obj!=null)
        {
            if(obj.Equals(null))
            {
                return true;
            }
            return false;
        }
        return true;
    }

    public static GameObject SimpleClone(GameObject obj)
    {
        if(obj!=null)
        {
            Transform tf = obj.transform.parent;
            if(tf!=null)
            {
                return GameObject.Instantiate(obj, tf);
            }
            else
            {
                return GameObject.Instantiate(obj);
            }
        }
        return null;
    }

    public static Image CreateImage(string name,Transform parent=null)
    {
        GameObject imgGo = new GameObject(name);
        if(parent!=null)
        {
            imgGo.transform.SetParent(parent,false);
            
        }
        Image img = imgGo.AddComponent<Image>();
        return img;
    }

}

完成以上辅助工具后,便可开始第一个案例:登录与注册页面
XLua需要调用C#或者引擎等相关代码,需要再Editor目录下创建一个GenConfig.cs进行配置


纯Unity+XLua UI框架

下载链接

  • 本文作者: Calmer
  • 本文链接: https://mytechplayer.com/archives/xluaugui框架
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
Pr的使用
Unity3D编辑器扩展(UnityEditor)
  • 文章目录
  • 站点概览
Calmer

Calmer

88 日志
7 分类
10 标签
RSS
Creative Commons
0%
© 2020 — 2025 Calmer
由 Halo 强力驱动
蜀ICP备20010026号-1川公网安备51019002006543
Copyright © 2020-2025 Calmer的文章