script 编译成 asset 解决方案

来源:互联网 发布:直角坐标机械手编程 编辑:程序博客网 时间:2024/05/19 05:37
用 Unity 游戏的时候,客户端程序经常会需要动态从远程服务器取 asset(如服务器更新了宠物,而宠物是包含脚本,跟随主人移动). Unity 提供了BuildPipeline.BuildAssetBundle 可以解决大多数问题, 但是, script 和 shader 不能被编成 asset.
好在Unity 的脚本语言是C#,跑在mono 上 ,为解决此类问题提供了可能性.
首先,用vs2005/vs2008新建一个类库类型的项目名字为test,引用 UnityEngine.dll(在\Program Files\Unity\Editor\Data\lib 下)
在 class1里贴上:
using System;
using UnityEngine;
using System.Text;
public class Class1 
{
    public void DoGUI()
    {
        GUILayout.Button("12345");
    }
    public  void DoStart(){}
    public  void DoUpdate(){}
    public  void DoLateUpdate(){}
}
Class1 就是你需要编译后发送到客户端的类(你可以在这个项目里添加多个类
)
ok, 编译,得到test.dll,把test 放到web服务器上(在我本机地址为 http://192.168.0.120/test.dll).

接下来在 客户端程序里加一个类 ScriptAssetFactory
using System;
using UnityEngine;
using System.Reflection;
using System.Collections.Generic;
public class ScriptAssetFactory: MonoBehaviour
{
    public static void AddDll(string GameObjectName, ScriptPara para)
    {
        GameObject obj = GameObject.Find(GameObjectName);
        obj.AddComponent(typeof(ScriptAssetFactory));
        obj.SendMessage("AddScript", para);
    }
    void AddScript(ScriptPara para)
    {
        LoadHelp.LoadBytes(this, para.DllUrl, null, delegate(byte[] buffer)
        {
            Assembly ass = Assembly.Load(buffer);
            foreach (string item in para.Types)
            {
                Type tempType = ass.GetType(item);
                if (tempType != null)
                {
                    ScriptEntry entry = new ScriptEntry();
                    entry.ScriptType = tempType;
                    entry.ScriptObject = ass.CreateInstance(item);
                    if (tempType.GetMethod("DoGUI") != null)
                    {
                        entry.DoGUI = true;
                    }
                    if (tempType.GetMethod("DoLateUpdate") != null)
                    {
                        entry.DoLateUpdate = true;
                    }
                    if (tempType.GetMethod("DoUpdate") != null)
                    {
                        entry.DoUpdate = true;
                    }
                    if (tempType.GetMethod("DoStart") != null)
                    {
                        entry.DoStart = true;
                        entry.ScriptType.InvokeMember("DoStart", BindingFlags.InvokeMethod, null, entry.ScriptObject, null);
                    }
                    ScriptsList.Add(entry);
                }
            }
        });
    }
    private List<ScriptEntry> ScriptsList;
    void Start()
    {
        ScriptsList = new List<ScriptEntry>();
    }
    void Update()
    {
        foreach (ScriptEntry item in ScriptsList)
        {
            if (item.DoUpdate)
            {
                item.ScriptType.InvokeMember("DoUpdate", BindingFlags.InvokeMethod, null, item.ScriptObject, null);
            }
        }
    }
    void LateUpdate()
    {
        foreach (ScriptEntry item in ScriptsList)
        {
            if (item.DoLateUpdate)
            {
                item.ScriptType.InvokeMember("DoLateUpdate", BindingFlags.InvokeMethod, null, item.ScriptObject, null);
            }
        }
    }
    void OnGUI()
    {
        foreach (ScriptEntry item in ScriptsList)
        {
            if (item.DoGUI)
            {
                item.ScriptType.InvokeMember("DoGUI", BindingFlags.InvokeMethod, null, item.ScriptObject, null);
            }
        }
    }
}
public struct ScriptEntry
{
    public object ScriptObject;
    public Type ScriptType;
    public bool DoGUI;
    public bool DoStart;
    public bool DoUpdate;
    public bool DoLateUpdate;
}
public class ScriptPara
{
    public ScriptPara(string _DllUrl, string[] _Types)
    {
        DllUrl = _DllUrl;
        Types = _Types;
    }
    public string DllUrl;
    public string[] Types;
}
提供一个工具类 LoadHelp
using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System;
using System.Xml.Serialization;
using System.Collections;
public delegate void LoadDelegate<T>(T asset);
public class LoadHelp
{
    private static List<WWW> proList = new List<WWW>();
    private static bool enable = false;
    private static int process = 0;
    public static void LoadObject<T>(MonoBehaviour thread, string url, LoadDelegate<T> asset) where T : UnityEngine.Object
    {
        thread.StartCoroutine(_LoadObject<T>(url, asset));
    }
    public static void DoGUI()
    {
        enable = true;
        if (proList.Count > 0)
        {
            float processf = 0;
            WWW[] WWWList = proList.ToArray();
            foreach (WWW item in WWWList)
            {
                processf += item.progress;
            }
            process = (int)(processf * 100.0f) / WWWList.Length;
            GUI.Box(new Rect((Screen.width - 150) / 2, Screen.height - 70, 150, 37), "Loading...\n" + process.ToString() + "%");
        }
    }
    public static void LoadBytes(MonoBehaviour thread, string url, Action<string> GetString, Action<byte[]> GetBytes)
    {
        thread.StartCoroutine(_LoadBytes(url, GetString, GetBytes));
    }
    private static IEnumerator _LoadBytes(string url, Action<string> GetString, Action<byte[]> GetBytes)
    {
        WWW rerquest = new WWW(url);
        if (enable)
        {
            proList.Add(rerquest);
        }
        yield return rerquest;
        if (rerquest.isDone)
        {
            if (GetBytes != null)
            {
                GetBytes(rerquest.bytes);
            }
            if (GetString != null)
            {
                GetString(rerquest.data);
            }
        }
        if (enable)
        {
            proList.Remove(rerquest);
        }
        rerquest.Dispose();
    }
    public static IEnumerator _LoadObject<T>(string url, LoadDelegate<T> asset) where T : UnityEngine.Object
    {
        WWW rerquest = new WWW(url);
        if (enable)
        {
            proList.Add(rerquest);
        }
        yield return rerquest;
        if (rerquest.isDone)
        {
            if (typeof(T) == typeof(Texture2D))
            {
                Texture2D tex = rerquest.texture;
                if (tex != null && asset != null) asset(tex as T);
            }
            if (typeof(T) == typeof(AssetBundle))
            {
                if (asset != null) asset(rerquest.assetBundle as T);
            }
            if (typeof(T) == typeof(GameObject))
            {
                GameObject mod = rerquest.assetBundle.mainAsset as GameObject;
                if (mod != null && asset != null) asset(mod as T);
            }
            if (typeof(T) == typeof(MovieTexture))
            {
                MovieTexture mov = rerquest.movie;
                if (mov != null && asset != null) asset(mov as T);
            }
            if (typeof(T) == typeof(AudioClip))
            {
                AudioClip aud = rerquest.oggVorbis;
                if (aud != null && asset != null) asset(aud as T);
            }
        }
        if (enable)
        {
            proList.Remove(rerquest);
        }
        rerquest.Dispose();
        //GC.Collect();
        //GC.WaitForPendingFinalizers();
        //GC.Collect();
    }
    public static byte[] ObjectToArray<T>(T message)
    {
        XmlSerializer format = new XmlSerializer(typeof(T));
        MemoryStream memoryStream = new MemoryStream();
        format.Serialize(memoryStream, message);
        memoryStream.Close();
        return memoryStream.ToArray();
    }
    public static T ArrayToObject<T>(byte[] array)
    {
        XmlSerializer format = null;
        MemoryStream memoryStream = null;
        object _message = null;
        try
        {
            format = new XmlSerializer(typeof(T));
            memoryStream = new MemoryStream(array);
            _message = format.Deserialize(memoryStream);
        }
        catch (Exception e)
        {
        }
        finally
        {
            memoryStream.Close();
            memoryStream.Dispose();
        }
        return (T)_message;
    }
}
接下来我们测试一下
新建一个cube(用来测试,实际使用的时候可能用宠物的主gameobject)名字为 cube001,新建一个脚本,在 Start()里帖入
ScriptAssetFactory.AddDll("cube001", new ScriptPara("http://192.168.0.120/test.dll", new string[] { "Class1"}));
ok!
原创粉丝点击