《坦克大戰(zhàn)》ulua+unity

一、定義一些簡單的基本需求:

邏輯需求.png

二、一些資源等...準(zhǔn)備工作:

[ulua](http://www.ulua.org/index.html

[模型](http://www.aigei.com/s?q=%E5%9D%A6%E5%85%8B&type=3d

三、Unity(2017)UI搭建(UGUI)

場景01.png

場景02.png

選擇角色界面我用的是RawImage+RenderTexture將模型渲染到Panel
image.png

image.png

四裂问、代碼編寫(這里用的是ulua提供的框架)
1皮壁、為了方便我們先把AssetBundle模式關(guān)掉(關(guān)于AssetBundle我會后面另開文章單獨(dú)介紹)
image.png

image.png

2滴须、場景管理器(場景跳轉(zhuǎn))
lua-view-新建StartPanel
image.png

image.png

3、初始化
當(dāng)運(yùn)行的時候加載出所有Manager
image.png

游戲初始化管理器Game Manager
image.png

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using LuaInterface;
using System.Reflection;
using System.IO;


namespace LuaFramework {
    public class GameManager : Manager {
        protected static bool initialize = false;
        private List<string> downloadFiles = new List<string>();

        /// <summary>
        /// 初始化游戲管理器
        /// </summary>
        void Awake() {
            Init();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        void Init() {
            DontDestroyOnLoad(gameObject);  //防止銷毀自己

            CheckExtractResource(); //釋放資源
            Screen.sleepTimeout = SleepTimeout.NeverSleep;
            Application.targetFrameRate = AppConst.GameFrameRate;
        }

        /// <summary>
        /// 釋放資源
        /// </summary>
        public void CheckExtractResource() {
            bool isExists = Directory.Exists(Util.DataPath) &&
              Directory.Exists(Util.DataPath + "lua/") && File.Exists(Util.DataPath + "files.txt");
            if (isExists || AppConst.DebugMode) {
                StartCoroutine(OnUpdateResource());
                return;   //文件已經(jīng)解壓過了岂膳,自己可添加檢查文件列表邏輯
            }
            StartCoroutine(OnExtractResource());    //啟動釋放協(xié)成 
        }

        IEnumerator OnExtractResource() {
            string dataPath = Util.DataPath;  //數(shù)據(jù)目錄
            string resPath = Util.AppContentPath(); //游戲包資源目錄

            if (Directory.Exists(dataPath)) Directory.Delete(dataPath, true);
            Directory.CreateDirectory(dataPath);

            string infile = resPath + "files.txt";
            string outfile = dataPath + "files.txt";
            if (File.Exists(outfile)) File.Delete(outfile);

            string message = "正在解包文件:>files.txt";
            Debug.Log(infile);
            Debug.Log(outfile);
            if (Application.platform == RuntimePlatform.Android) {
                WWW www = new WWW(infile);
                yield return www;

                if (www.isDone) {
                    File.WriteAllBytes(outfile, www.bytes);
                }
                yield return 0;
            } else File.Copy(infile, outfile, true);
            yield return new WaitForEndOfFrame();

            //釋放所有文件到數(shù)據(jù)目錄
            string[] files = File.ReadAllLines(outfile);
            foreach (var file in files) {
                string[] fs = file.Split('|');
                infile = resPath + fs[0];  //
                outfile = dataPath + fs[0];

                message = "正在解包文件:>" + fs[0];
                Debug.Log("正在解包文件:>" + infile);
                facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);

                string dir = Path.GetDirectoryName(outfile);
                if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);

                if (Application.platform == RuntimePlatform.Android) {
                    WWW www = new WWW(infile);
                    yield return www;

                    if (www.isDone) {
                        File.WriteAllBytes(outfile, www.bytes);
                    }
                    yield return 0;
                } else {
                    if (File.Exists(outfile)) {
                        File.Delete(outfile);
                    }
                    File.Copy(infile, outfile, true);
                }
                yield return new WaitForEndOfFrame();
            }
            message = "解包完成!!!";
            facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
            yield return new WaitForSeconds(0.1f);

            message = string.Empty;
            //釋放完成毙死,開始啟動更新資源
            StartCoroutine(OnUpdateResource());
        }

        /// <summary>
        /// 啟動更新下載扼倘,這里只是個思路演示,此處可啟動線程下載更新
        /// </summary>
        IEnumerator OnUpdateResource() {
            if (!AppConst.UpdateMode) {
                OnResourceInited();
                yield break;
            }
            string dataPath = Util.DataPath;  //數(shù)據(jù)目錄
            string url = AppConst.WebUrl;
            string message = string.Empty;
            string random = DateTime.Now.ToString("yyyymmddhhmmss");
            string listUrl = url + "files.txt?v=" + random;
            Debug.LogWarning("LoadUpdate---->>>" + listUrl);

            WWW www = new WWW(listUrl); yield return www;
            if (www.error != null) {
                OnUpdateFailed(string.Empty);
                yield break;
            }
            if (!Directory.Exists(dataPath)) {
                Directory.CreateDirectory(dataPath);
            }
            File.WriteAllBytes(dataPath + "files.txt", www.bytes);
            string filesText = www.text;
            string[] files = filesText.Split('\n');

            for (int i = 0; i < files.Length; i++) {
                if (string.IsNullOrEmpty(files[i])) continue;
                string[] keyValue = files[i].Split('|');
                string f = keyValue[0];
                string localfile = (dataPath + f).Trim();
                string path = Path.GetDirectoryName(localfile);
                if (!Directory.Exists(path)) {
                    Directory.CreateDirectory(path);
                }
                string fileUrl = url + f + "?v=" + random;
                bool canUpdate = !File.Exists(localfile);
                if (!canUpdate) {
                    string remoteMd5 = keyValue[1].Trim();
                    string localMd5 = Util.md5file(localfile);
                    canUpdate = !remoteMd5.Equals(localMd5);
                    if (canUpdate) File.Delete(localfile);
                }
                if (canUpdate) {   //本地缺少文件
                    Debug.Log(fileUrl);
                    message = "downloading>>" + fileUrl;
                    facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
                    /*
                    www = new WWW(fileUrl); yield return www;
                    if (www.error != null) {
                        OnUpdateFailed(path);   //
                        yield break;
                    }
                    File.WriteAllBytes(localfile, www.bytes);
                     */
                    //這里都是資源文件除呵,用線程下載
                    BeginDownload(fileUrl, localfile);
                    while (!(IsDownOK(localfile))) { yield return new WaitForEndOfFrame(); }
                }
            }
            yield return new WaitForEndOfFrame();

            message = "更新完成!!";
            facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);

            OnResourceInited();
        }

        void OnUpdateFailed(string file) {
            string message = "更新失敗!>" + file;
            facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
        }

        /// <summary>
        /// 是否下載完成
        /// </summary>
        bool IsDownOK(string file) {
            return downloadFiles.Contains(file);
        }

        /// <summary>
        /// 線程下載
        /// </summary>
        void BeginDownload(string url, string file) {     //線程下載
            object[] param = new object[2] { url, file };

            ThreadEvent ev = new ThreadEvent();
            ev.Key = NotiConst.UPDATE_DOWNLOAD;
            ev.evParams.AddRange(param);
            ThreadManager.AddEvent(ev, OnThreadCompleted);   //線程下載
        }

        /// <summary>
        /// 線程完成
        /// </summary>
        /// <param name="data"></param>
        void OnThreadCompleted(NotiData data) {
            switch (data.evName) {
                case NotiConst.UPDATE_EXTRACT:  //解壓一個完成
                //
                break;
                case NotiConst.UPDATE_DOWNLOAD: //下載一個完成
                downloadFiles.Add(data.evParam.ToString());
                break;
            }
        }

        /// <summary>
        /// 資源初始化結(jié)束
        /// </summary>
        public void OnResourceInited() {
#if ASYNC_MODE
            ResManager.Initialize(AppConst.AssetDir, delegate() {
                Debug.Log("Initialize OK!!!");
                this.OnInitialize();
            });
#else
            ResManager.Initialize();
            this.OnInitialize();
#endif
        }

        void OnInitialize() {
            LuaManager.InitStart();
            LuaManager.DoFile("Logic/Game");         //加載游戲
            LuaManager.DoFile("Logic/Network");      //加載網(wǎng)絡(luò)
            NetManager.OnInit();                     //初始化網(wǎng)絡(luò)
            Util.CallMethod("Game", "OnInitOK");     //初始化完成

            initialize = true;

            //類對象池測試
            var classObjPool = ObjPoolManager.CreatePool<TestObjectClass>(OnPoolGetElement, OnPoolPushElement);
            //方法1
            //objPool.Release(new TestObjectClass("abcd", 100, 200f));
            //var testObj1 = objPool.Get();

            //方法2
            ObjPoolManager.Release<TestObjectClass>(new TestObjectClass("abcd", 100, 200f));
            var testObj1 = ObjPoolManager.Get<TestObjectClass>();

            Debugger.Log("TestObjectClass--->>>" + testObj1.ToString());

            //游戲?qū)ο蟪販y試
            var prefab = Resources.Load("TestGameObjectPrefab", typeof(GameObject)) as GameObject;
            var gameObjPool = ObjPoolManager.CreatePool("TestGameObject", 5, 10, prefab);

            var gameObj = Instantiate(prefab) as GameObject;
            gameObj.name = "TestGameObject_01";
            gameObj.transform.localScale = Vector3.one;
            gameObj.transform.localPosition = Vector3.zero;

            ObjPoolManager.Release("TestGameObject", gameObj);
            var backObj = ObjPoolManager.Get("TestGameObject");
            backObj.transform.SetParent(null);

            Debug.Log("TestGameObject--->>>" + backObj);
        }

        /// <summary>
        /// 當(dāng)從池子里面獲取時
        /// </summary>
        /// <param name="obj"></param>
        void OnPoolGetElement(TestObjectClass obj) {
            Debug.Log("OnPoolGetElement--->>>" + obj);
        }

        /// <summary>
        /// 當(dāng)放回池子里面時
        /// </summary>
        /// <param name="obj"></param>
        void OnPoolPushElement(TestObjectClass obj) {
            Debug.Log("OnPoolPushElement--->>>" + obj);
        }

        /// <summary>
        /// 析構(gòu)函數(shù)
        /// </summary>
        void OnDestroy() {
            if (NetManager != null) {
                NetManager.Unload();
            }
            if (LuaManager != null) {
                LuaManager.Close();
            }
            Debug.Log("~GameManager was destroyed");
        }
    }
}

這里是lua層的初始化 ↓


image.png

加載獲取所有view文件夾文件:


image.png
image.png

image.png

新建并注冊一個ctrl:


image.png

加載構(gòu)造:
image.png
image.png

image.png

指定加載面板:


image.png
StartCtrl = {}

local this = StartCtrl

function StartCtrl.New()
    return this
end

function StartCtrl.Awake()
    panelMgr:CreatePanel('Start', InitEnd);
end

function InitEnd()
    log("開始面板創(chuàng)建成功")
end

對應(yīng)的調(diào)用方法在c#PanelManager中的CreatePanel方法

image.png

四、Assetbundle打包登錄場景加載
image.png

AddBuildMap("Start" + AppConst.ExtName, "*.prefab", "Assets/Resources/Panels/Starpanel");
image.png

運(yùn)行測試下:


ezgif.com-video-to-gif.gif

五颜曾、業(yè)務(wù)層邏輯的處理(實現(xiàn)場景跳轉(zhuǎn))
先說一個簡單的跳轉(zhuǎn)處理(這里我們需要寫自己的需求所以自己寫一個管理器)

image.png

這里用到了LuaBehaviour中的一些回調(diào)

using UnityEngine;
using LuaInterface;
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine.UI;

namespace LuaFramework {
    public class LuaBehaviour : View {
        private string data = null;
        private Dictionary<string, LuaFunction> buttons = new Dictionary<string, LuaFunction>();

        protected void Awake() {
            Util.CallMethod(name, "Awake", gameObject);
        }

        protected void Start() {
            Util.CallMethod(name, "Start");
        }

        protected void OnClick() {
            Util.CallMethod(name, "OnClick");
        }

        protected void OnClickEvent(GameObject go) {
            Util.CallMethod(name, "OnClick", go);
        }

        /// <summary>
        /// 添加單擊事件
        /// </summary>
        public void AddClick(GameObject go, LuaFunction luafunc) {
            if (go == null || luafunc == null) return;
            buttons.Add(go.name, luafunc);
            go.GetComponent<Button>().onClick.AddListener(
                delegate() {
                    luafunc.Call(go);
                }
            );
        }

        /// <summary>
        /// 刪除單擊事件
        /// </summary>
        /// <param name="go"></param>
        public void RemoveClick(GameObject go) {
            if (go == null) return;
            LuaFunction luafunc = null;
            if (buttons.TryGetValue(go.name, out luafunc)) {
                luafunc.Dispose();
                luafunc = null;
                buttons.Remove(go.name);
            }
        }

        /// <summary>
        /// 清除單擊事件
        /// </summary>
        public void ClearClick() {
            foreach (var de in buttons) {
                if (de.Value != null) {
                    de.Value.Dispose();
                }
            }
            buttons.Clear();
        }

        //-----------------------------------------------------------------
        protected void OnDestroy() {
            ClearClick();
#if ASYNC_MODE
            string abName = name.ToLower().Replace("panel", "");
            ResManager.UnloadAssetBundle(abName + AppConst.ExtName);
#endif
            Util.ClearMemory();
            Debug.Log("~" + name + " was destroy!");
        }
    }
}

StartCtrl (加載面板)

StartCtrl = {}

local this = StartCtrl

function StartCtrl.New()
    logWarn("StartCtrl.New--->>");
    return this
end

function StartCtrl.Awake()
    logWarn("StartCtrl.Awake--->>");
    panelMgr:CreatePanel('Start', InitEnd);
end

function InitEnd(go)
    log("開始面板創(chuàng)建成功")
    behaviour = go:GetComponent("LuaBehaviour")
    --(按鈕實例纠拔,回調(diào)函數(shù))
    behaviour:AddClick(StartPanel.startBtn,OnStartBtnClick)
    behaviour:AddClick(StartPanel.exitBtn,OnExitButtonClick)
end

function OnStartBtnClick()
    log("開始按鈕被點擊了")
end
function OnExitButtonClick()
    log("退出按鈕被點擊了")
end

StartPanel (獲取組件)

--處理業(yè)務(wù)邏輯
StartPanel = { }

local this = StartPanel

function StartPanel.Awake(go)

    gameObject = go
    transform = go.transform
    this.init()
end

function StartPanel.init()
    
    --獲取組件
    this.startBtn = transform:Find("StartButton").gameObject
    this.exitBtn = transform:Find("ExitButton").gameObject
    
end

六、場景管理器(管理頁面跳轉(zhuǎn))

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SceneMgr : MonoBehaviour {

    //同步跳轉(zhuǎn)
    public void LoadScene(int index)
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(index);
    }
    public void LoadScene(string index)
    {
        UnityEngine.SceneManagement.SceneManager.LoadScene(index);
    }
    //異步跳轉(zhuǎn)
    public void LoadSceneAsync(int index)
    {
        StartCoroutine(LoadSceneA(index));
    }
    private IEnumerator LoadSceneA(int index)
    {
       AsyncOperation asyncOperation =  UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(index);

        yield return asyncOperation;
    }
}

image.png
image.png

image.png

image.png

lua中define:

sceneMgr = LuaHelper.GetSceneManager();

StartPanel點擊事件:

function OnStartBtnClick()
    log("開始按鈕被點擊了")
    sceneMgr:LoadScene(1)
end

運(yùn)行效果如下:


ezgif.com-video-to-gif(1).gif

//cjson(lua表轉(zhuǎn)json)

#!/usr/bin/env lua

-- usage: json2lua.lua [json_file]
--
-- Eg:
-- echo '[ "testing" ]' | ./json2lua.lua
-- ./json2lua.lua test.json

local json = require "cjson"
local util = require "cjson.util"

local json_text = util.file_load(arg[1])
local t = json.decode(json_text)
print(util.serialise_value(t))

七泛豪、場景二和場景一相同:

image.png

image.png

image.png

1.首先我們要用一個空物體初始化這個場景
image.png

image.png

我們這里沒有用這種方法因為需要加載面板很多話不方便管理

2.需要注意的是OnLevelLoaded
我們需要去注冊一個事件它才會去通知跳轉(zhuǎn)(5.4以及高版本以上是需要注冊一個事件绿语,才會在跳轉(zhuǎn)場景的時候發(fā)送通知低版本相反)


image.png
using UnityEngine;
using System.Collections;
using LuaInterface;
using UnityEngine.SceneManagement;

namespace LuaFramework {
    public class LuaManager : Manager {
        private LuaState lua;
        private LuaLoader loader;
        private LuaLooper loop = null;
        LuaFunction levelLoaded;

        // Use this for initialization
        void Awake() {
            loader = new LuaLoader();
            lua = new LuaState();
            this.OpenLibs();
            lua.LuaSetTop(0);

            LuaBinder.Bind(lua);
            DelegateFactory.Init();
            LuaCoroutine.Register(lua, this);

            //注冊事件
            SceneManager.sceneLoaded += OnSceneLoaded;
        }

        public void InitStart() {
            InitLuaPath();
            InitLuaBundle();
            this.lua.Start();    //啟動LUAVM
            this.StartMain();
            this.StartLooper();
        }

        void StartLooper() {
            loop = gameObject.AddComponent<LuaLooper>();
            loop.luaState = lua;
        }

        //cjson 比較特殊,只new了一個table候址,沒有注冊庫吕粹,這里注冊一下
        protected void OpenCJson() {
            lua.LuaGetField(LuaIndexes.LUA_REGISTRYINDEX, "_LOADED");
            lua.OpenLibs(LuaDLL.luaopen_cjson);
            lua.LuaSetField(-2, "cjson");

            lua.OpenLibs(LuaDLL.luaopen_cjson_safe);
            lua.LuaSetField(-2, "cjson.safe");
        }

        void StartMain() {
            lua.DoFile("Main.lua");

            levelLoaded = lua.GetFunction("OnLevelWasLoaded");
            //main.Call();
            //main.Dispose();
            //main = null;    
        }
        //監(jiān)聽場景跳轉(zhuǎn)事件的方法
        void OnSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            OnLevelLoaded(scene.buildIndex);
        }
        //場景跳轉(zhuǎn)回調(diào)
        void OnLevelLoaded(int level)
        {
            if (levelLoaded != null)
            {
                levelLoaded.BeginPCall();
                levelLoaded.Push(level);
                levelLoaded.PCall();
                levelLoaded.EndPCall();
            }

            if (lua != null)
            {
                lua.RefreshDelegateMap();
            }
        }

        /// <summary>
        /// 初始化加載第三方庫
        /// </summary>
        void OpenLibs() {
            lua.OpenLibs(LuaDLL.luaopen_pb);      
            lua.OpenLibs(LuaDLL.luaopen_sproto_core);
            lua.OpenLibs(LuaDLL.luaopen_protobuf_c);
            lua.OpenLibs(LuaDLL.luaopen_lpeg);
            lua.OpenLibs(LuaDLL.luaopen_bit);
            lua.OpenLibs(LuaDLL.luaopen_socket_core);

            this.OpenCJson();
        }

        /// <summary>
        /// 初始化Lua代碼加載路徑
        /// </summary>
        void InitLuaPath() {
            if (AppConst.DebugMode) {
                string rootPath = AppConst.FrameworkRoot;
                lua.AddSearchPath(rootPath + "/Lua");
                lua.AddSearchPath(rootPath + "/ToLua/Lua");
            } else {
                lua.AddSearchPath(Util.DataPath + "lua");
            }
        }

        /// <summary>
        /// 初始化LuaBundle
        /// </summary>
        void InitLuaBundle() {
            if (loader.beZip) {
                loader.AddBundle("lua/lua.unity3d");
                loader.AddBundle("lua/lua_math.unity3d");
                loader.AddBundle("lua/lua_system.unity3d");
                loader.AddBundle("lua/lua_system_reflection.unity3d");
                loader.AddBundle("lua/lua_unityengine.unity3d");
                loader.AddBundle("lua/lua_common.unity3d");
                loader.AddBundle("lua/lua_logic.unity3d");
                loader.AddBundle("lua/lua_view.unity3d");
                loader.AddBundle("lua/lua_controller.unity3d");
                loader.AddBundle("lua/lua_misc.unity3d");

                loader.AddBundle("lua/lua_protobuf.unity3d");
                loader.AddBundle("lua/lua_3rd_cjson.unity3d");
                loader.AddBundle("lua/lua_3rd_luabitop.unity3d");
                loader.AddBundle("lua/lua_3rd_pbc.unity3d");
                loader.AddBundle("lua/lua_3rd_pblua.unity3d");
                loader.AddBundle("lua/lua_3rd_sproto.unity3d");
            }
        }

        public void DoFile(string filename) {
            lua.DoFile(filename);
        }

        // Update is called once per frame
        public object[] CallFunction(string funcName, params object[] args) {
            LuaFunction func = lua.GetFunction(funcName);
            if (func != null) {
                return func.LazyCall(args);
            }
            return null;
        }

        public void LuaGC() {
            lua.LuaGC(LuaGCOptions.LUA_GCCOLLECT);
        }

        public void Close() {
            //取消注冊
            SceneManager.sceneLoaded -= OnSceneLoaded; 

            loop.Destroy();
            loop = null;

            lua.Dispose();
            lua = null;
            loader = null;
        }
    }
}

3.在lua Main函數(shù)中接受回調(diào)

--主入口函數(shù)。從這里開始lua邏輯
function Main()                 
    print("logic start")            
end

--場景切換通知
function OnLevelWasLoaded(level)
    print("回調(diào)函數(shù)執(zhí)行了 --------"..level)

    if level == 1 then--選塔克場景
       --調(diào)用此面板點擊事件
       panelMgr:CreatePanel("SelectTank",SelectTankCtrl.CreateTankHandler)

    end
    
    collectgarbage("collect")
    Time.timeSinceLevelLoad = 0
end



function OnApplicationQuit()
end
function SelectTankCtrl.CreateTankHandler(go)
    log("開始面板創(chuàng)建成功")
    behaviour = go:GetComponent("LuaBehaviour")
    --(按鈕實例岗仑,回調(diào)函數(shù))
    behaviour:AddClick(SelectTankPanel.LeftBtn,OnLeftBtnClick)
    behaviour:AddClick(SelectTankPanel.RigthBtn,OnRigthButtonClick)
    behaviour:AddClick(SelectTankPanel.EnterBtn,OnEnterButtonClick)
end
function OnLeftBtnClick()
    log("向左按鈕被點擊了")
end
function OnRigthButtonClick()
    log("向右按鈕被點擊了")
end
function OnEnterButtonClick()
    log("進(jìn)入游戲按鈕被點擊了")
end
image.png

4.根據(jù)情況角色模型是分開打包或者打包到一起


image.png

5.SelectTankPanel 獲取相機(jī)

--獲取Camera
    this.Camera = transform:Find("Camera").gameObject

6.SelectTankCtrl(角色選擇與加載邏輯代碼)


SelectTankCtrl = {}

local this = SelectTankCtrl

local tanks = { } 

local disPlayTankIndex = 1


function SelectTankCtrl.New()
    logWarn("SelectTankCtrl.New--->>");
    return this
end


function SelectTankCtrl.Awake()
    
    logWarn("SelectTankCtrl.Awake--->>");
    --panelMgr:CreatePanel('SelectTank', this.InitEnd);
    panelMgr:CreatePanel("SelectTank",SelectTankCtrl.CreateTankHandler)
    
end


function SelectTankCtrl.CreateTankHandler(go)
    
    log("開始面板創(chuàng)建成功")
    behaviour = go:GetComponent("LuaBehaviour")
    --(按鈕實例匹耕,回調(diào)函數(shù))
    behaviour:AddClick(SelectTankPanel.LeftBtn,OnLeftBtnClick)
    behaviour:AddClick(SelectTankPanel.RigthBtn,OnRigthButtonClick)
    behaviour:AddClick(SelectTankPanel.EnterBtn,OnEnterButtonClick)
    
    --獲取加載角色
    tankNames = {"Buggy","Cube"}
    resMgr:LoadPrefab("Tanks",tankNames,this.InitTankHandler)
    
end

function SelectTankCtrl.InitTankHandler(gos)
    
    print(gos[0].name)
    print(gos[1].name)
    
    local go = newObject(gos[0]);
    --將預(yù)制體加載到相機(jī)并且固定坐標(biāo)
    go.transform:SetParent(SelectTankPanel.Camera.transform,false)
    
    local go1 = newObject(gos[1]);
    go1.transform:SetParent(SelectTankPanel.Camera.transform,false)
    
    tanks[1] = go
    tanks[2] = go1
    
    for i=1, #tanks  do
        tanks[i]:SetActive(false)
    end
    
    ShowTank()
    
end

function ShowTank()
    
    tanks[disPlayTankIndex]:SetActive(true)
    
    for i = 1, #tanks do
        if i ~= disPlayTankIndex then
            tanks[i]:SetActive(false)
        end
    end
end


function OnLeftBtnClick()
    log("向左按鈕被點擊了")
    
    disPlayTankIndex = disPlayTankIndex - 1
    if disPlayTankIndex == 0 then
        disPlayTankIndex = #tanks
    end
    
    ShowTank()
    
end



function OnRigthButtonClick()
    log("向右按鈕被點擊了")
    
    disPlayTankIndex = disPlayTankIndex + 1 
    if disPlayTankIndex == #tanks + 1 then
        disPlayTankIndex = 1
    end
    
    ShowTank()
end


function OnEnterButtonClick()
    log("進(jìn)入游戲按鈕被點擊了")
end
ezgif.com-video-to-gif.gif

八、游戲場景

[場景搭建](https://blog.csdn.net/nicolelili1/article/details/72843163

image.png

lua TankCtrl

TankCtrl = {}

local this = TankCtrl

local gameObject

local transform

function TankCtrl.GetInstance()
     return this
end

function TankCtrl.Awake(go)
    
    gameObject = go
    
    transform = go.transform
    
end
image.png

c#(掛在角色上的)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LuaFramework;

public class TankCtrl : MonoBehaviour {

    public void Awake()
    {
        Util.CallMethod("Tankctrl","Awake",gameObject);
    }
    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        
    }
}

1.角色移動


image.png

image.png

2.角色控制器

TankCtrl = {}

local this = TankCtrl

local gameObject

local transform
--角色控制器
local characterController

function TankCtrl.GetInstance()
     return this
end

function TankCtrl.Awake(go)
    
    gameObject = go
    
    transform = go.transform
    
    --characterController = go:GetComponent("CharacterController")
    characterController = gameObject:GetComponent("CharacterController")
    
end

function TankCtrl.Update()
    horizontal = UnityEngine.Input.GetAxis("Horizontal")
    vertical = UnityEngine.Input.GetAxis("Vertical")
    
    --[[if horizontal ~= 0 or vertical ~= 0 then
        dir = Vector3.New()
        dir.x = horizontal
        dir.y = -vertical
        transform:Translate(dir)
    end]]
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.W) then
        characterController:SimpleMove(-transform.up * UnityEngine.Time.deltaTime * 650)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.S) then
        characterController:SimpleMove(transform.up * UnityEngine.Time.deltaTime * 420)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.A) then
        transform:Rotate(Vector3.back * 2)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.D) then
        transform:Rotate(Vector3.forward * 2)
    end
end

c#接收

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LuaFramework;

public class TankCtrl : MonoBehaviour {

    public void Awake()
    {
        Util.CallMethod("TankCtrl", "Awake",gameObject);
    }
    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        Util.CallMethod("TankCtrl", "Update", gameObject);
    }
}

2.子彈發(fā)射


image.png

image.png

tankctrl

TankCtrl = {}

local this = TankCtrl

local gameObject

local transform

local bullet--子彈

local firPos--父物體

--角色控制器
local characterController

function TankCtrl.GetInstance()
     return this
end

function TankCtrl.Awake(go)
    
    gameObject = go
    
    transform = go.transform
    
    --characterController = go:GetComponent("CharacterController")
    characterController = gameObject:GetComponent("CharacterController")
    
    --子彈加載(返回到回調(diào)函數(shù)中)
    resMgr:LoadPrefab("Bullet",{"RedBullet"},TankCtrl.loadHandler)
    
    --firPos = child("FirePos")

    firPos = transform:Find("FirePos")
    
    print(firPos)
    
end
--返回的子彈
function TankCtrl.loadHandler(gos)
    print(gos[0])
    bullet = gos[0]
end

function TankCtrl.Update()
    horizontal = UnityEngine.Input.GetAxis("Horizontal")
    vertical = UnityEngine.Input.GetAxis("Vertical")
    
    --[[if horizontal ~= 0 or vertical ~= 0 then
        dir = Vector3.New()
        dir.x = horizontal
        dir.y = -vertical
        transform:Translate(dir)
    end]]
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.W) then
        characterController:SimpleMove(-transform.up * UnityEngine.Time.deltaTime * 650)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.S) then
        characterController:SimpleMove(transform.up * UnityEngine.Time.deltaTime * 420)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.A) then
        transform:Rotate(Vector3.back * 2)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.D) then
        transform:Rotate(Vector3.forward * 2)
    end
    
    --加載子彈(按下鼠標(biāo)左鍵)
    if UnityEngine.Input.GetMouseButtonDown(0) then
        print(bullet)
        --獲取子彈
        temp = newObject(bullet)
        --設(shè)置父物體
        temp.transform:SetParent(firPos,false)
        --temp.transform.localScale = Vector3(1,1,1)
        temp.transform.localScale = Vector3.one
        temp.transform.localPosition = Vector3(0,0,0)
        
    end
end

3.給子彈掛一個腳本

image.png

image.png

4.子彈的生成移動

BulletCtrl = {}

local this = BulletCtrl

BulletCtrl.gameObject = nil

BulletCtrl.transform = nil

--[[local gameObject = nil

local transform = nil--]]

function BulletCtrl:New(o,go)
    --print(o)
    o = o or{}
    
    o = setmetatable(o,self)
    
    self.__index = self
    
    o.gameObject = go
    
    o.transform = o.gameObject.transform
    
    return o
end 

--[[function BulletCtrl.Awake(go)
    gameObject = go
    
    transform = gameObject.transform
end--]]

function BulletCtrl:Update()
    
    self.transform:Translate(-self.transform.forward * UnityEngine.Time.deltaTime * 50)
    
end

5.坦克發(fā)射子彈調(diào)用

require "Battle/BulletCtrl"

TankCtrl = {}

local this = TankCtrl

local gameObject

local transform

local bullet--子彈

local firPos--父物體

--儲存子彈的表
local bullets = { }

--角色控制器
local characterController

function TankCtrl.GetInstance()
     return this
end

function TankCtrl.Awake(go)
    
    gameObject = go
    
    transform = go.transform
    
    --characterController = go:GetComponent("CharacterController")
    characterController = gameObject:GetComponent("CharacterController")
    
    --子彈加載(返回到回調(diào)函數(shù)中)
    resMgr:LoadPrefab("Bullet",{"RedBullet"},TankCtrl.loadHandler)
    
    --firPos = child("FirePos")

    firPos = transform:Find("FirePos")
    
    print(firPos)
    
end
function TankCtrl.loadHandler(gos)
    print(gos[0])
    bullet = gos[0]
end

function TankCtrl.Update()
    horizontal = UnityEngine.Input.GetAxis("Horizontal")
    vertical = UnityEngine.Input.GetAxis("Vertical")
    
    --[[if horizontal ~= 0 or vertical ~= 0 then
        dir = Vector3.New()
        dir.x = horizontal
        dir.y = -vertical
        transform:Translate(dir)
    end]]
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.W) then
        characterController:SimpleMove(-transform.up * UnityEngine.Time.deltaTime * 250)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.S) then
        characterController:SimpleMove(transform.up * UnityEngine.Time.deltaTime * 220)
    end
    
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.A) then
        transform:Rotate(Vector3.back * 2)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.D) then
        transform:Rotate(Vector3.forward * 2)
    end
    
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.P) then
    --加載子彈(按下鼠標(biāo)左鍵)
    --if UnityEngine.Input.GetMouseButtonDown(0) then
        print(bullet)
        --獲取子彈
        temp = newObject(bullet)
        
        --把每一個發(fā)射的子彈存入戰(zhàn)斗子彈管理類
        BattleCtrl.GetInstance().Bullets[temp] = bc
        
        --將每個子彈存儲
        bc =  BulletCtrl:New(nil,temp)

        table.insert(bullets,bc)
        
        --設(shè)置父物體
        temp.transform:SetParent(firPos,false)
        temp.transform.localScale = Vector3(1,1,1)
        --temp.transform.localScale = Vector3.one
        temp.transform.localPosition = Vector3(0,0,0)
        
        temp.transform.parent = nil
        --取消設(shè)置父物體
        temp.transform.DetachChildren(firPos)
        
        
    end
    
    if table.getn(bullets) > 0 then
        for i,v in ipairs(bullets) do
            v:Update()
        end
    end
    
end

6.戰(zhàn)斗時子彈射中敵人的管理類BattleCtrl


image.png
--模擬一個子彈類
BattleCtrl = {}

local this = BattleCtrl

BattleCtrl.Bullets = {}

function BattleCtrl.GetInstance()
    return this
end

function BattleCtrl.OnTriggerEnter(go,other)
     
    local enemyTank = go
    
    bulletCtrl = this.Bullets[other.gameObject]
    --把子彈和野怪(被擊中的敵人)傳遞給bulletCtrl
    bulletCtrl.Attack(other.gameObject, enemyTank)
end

添加子彈碰撞管理及銷毀

require "Battle/BulletCtrl"

TankCtrl = {}

local this = TankCtrl

local gameObject

local transform

local bullet--子彈

local firPos--父物體

--儲存子彈的表
local bullets = { }

--角色控制器
local characterController

function TankCtrl.GetInstance()
     return this
end

function TankCtrl.Awake(go)
    
    gameObject = go
    
    transform = go.transform
    
    --characterController = go:GetComponent("CharacterController")
    characterController = gameObject:GetComponent("CharacterController")
    
    --子彈加載(返回到回調(diào)函數(shù)中)
    resMgr:LoadPrefab("Bullet",{"RedBullet"},TankCtrl.loadHandler)
    
    --firPos = child("FirePos")

    firPos = transform:Find("FirePos")
    
    print(firPos)
    
end
function TankCtrl.loadHandler(gos)
    print(gos[0])
    bullet = gos[0]
end

function TankCtrl.Update()
    horizontal = UnityEngine.Input.GetAxis("Horizontal")
    vertical = UnityEngine.Input.GetAxis("Vertical")
    
    --[[if horizontal ~= 0 or vertical ~= 0 then
        dir = Vector3.New()
        dir.x = horizontal
        dir.y = -vertical
        transform:Translate(dir)
    end]]
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.W) then
        characterController:SimpleMove(-transform.up * UnityEngine.Time.deltaTime * 250)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.S) then
        characterController:SimpleMove(transform.up * UnityEngine.Time.deltaTime * 220)
    end
    
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.A) then
        transform:Rotate(Vector3.back * 2)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.D) then
        transform:Rotate(Vector3.forward * 2)
    end
    
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.P) then
    --加載子彈(按下鼠標(biāo)左鍵)
    --if UnityEngine.Input.GetMouseButtonDown(0) then
        print(bullet)
        --獲取子彈
        temp = newObject(bullet)
        
        --把每一個發(fā)射的子彈存入戰(zhàn)斗子彈管理類
        BattleCtrl.GetInstance().Bullets[temp] = bc
        
        --將每個發(fā)射的子彈單個實例
        bc =  BulletCtrl:New(nil,temp)

        table.insert(bullets,bc)
        
        --設(shè)置父物體
        temp.transform:SetParent(firPos,false)
        temp.transform.localScale = Vector3(1,1,1)
        --temp.transform.localScale = Vector3.one
        temp.transform.localPosition = Vector3(0,0,0)
        
        temp.transform.parent = nil
        --取消設(shè)置父物體
        temp.transform.DetachChildren(firPos)
        
        
    end
    
    if table.getn(bullets) > 0 then
        for i,v in ipairs(bullets) do
            v:Update()
        end
    end
    
end

7.掛在所有敵人身上用于反饋自身及撞擊子彈


image.png

using LuaFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyTankCtrl : MonoBehaviour {

    //tank檢測到碰撞
    private void OnTriggerEnter(Collider other)
    {
        //調(diào)用亂函數(shù)獲取射擊的子彈以及被擊中的坦克
        Util.CallMethod("BattleCtrl", "OnTriggerEnter", new object[] { this.gameObject, other });

        //將other傳給lua

    }
}

8.子彈掛的腳本


image.png
using LuaFramework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletCtrl : MonoBehaviour {

    public void Awake()
    {
        Util.CallMethod("BulletCtrl", "Awake", gameObject);
    }
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    //void Update()
    //{
    //    //Util.CallMethod("BulletCtrl", "Update", gameObject);
    //    //if (gameObject != null)
    //    //{
    //    //    Destroy(gameObject,5);
    //    //}

    //}
}

BulletCtrl = {}

local this = BulletCtrl

BulletCtrl.gameObject = nil

BulletCtrl.transform = nil

--[[local gameObject = nil

local transform = nil--]]

function BulletCtrl:New(o,go)
    --print(o)
    o = o or{}
    
    o = setmetatable(o,self)
    
    self.__index = self
    
    o.gameObject = go
    
    o.transform = o.gameObject.transform
    
    return o
end 

--[[function BulletCtrl.Awake(go)
    gameObject = go
    
    transform = gameObject.transform
end--]]

function BulletCtrl:Update()
    
    self.transform:Translate(-self.transform.forward * UnityEngine.Time.deltaTime * 50)
    
end

--[[--碰撞完處理攻擊業(yè)務(wù)
function BulletCtrl.Attack(bullet,enemy)
    --bullet.self = nil
    destroy(bullet)
    destroy(enemy)
end--]]
--模擬一個子彈類
BattleCtrl = {}

local this = BattleCtrl

BattleCtrl.Bullets = {}

function BattleCtrl.GetInstance()
    return this
end

function BattleCtrl.OnTriggerEnter(...)
    local res = {...}
     --tanke
    local enemyTank = res[1].gameObject
    print("我是坦克.................."..enemyTank.name)
    --zidan
    local bullet = res[2].gameObject
    print("我是子彈.................."..bullet.name)
    
    
    destroy(bullet)
    --print("我是子彈.................."..bullet.name)
    destroy(enemyTank)
    --print("我是坦克.................."..enemyTank.name)
    
    
    
    --[[bulletCtrl = this.Bullets[bullet]
    
    
    
        --把子彈和野怪(被擊中的敵人)傳遞給bulletCtrl
        bulletCtrl.Attack(bullet, enemyTank)--]]
    
    
    
end

9.坦克管理類

require "Battle/BulletCtrl"

TankCtrl = {}

local this = TankCtrl

local gameObject

local transform

local bullet--子彈

local firPos--父物體

--儲存子彈的表
local bullets = { }

--角色控制器
local characterController

function TankCtrl.GetInstance()
     return this
end

function TankCtrl.Awake(go)
    
    gameObject = go
    
    transform = go.transform
    
    characterController = gameObject:GetComponent("CharacterController")
    
    --子彈加載(返回到回調(diào)函數(shù)中)
    resMgr:LoadPrefab("Bullet",{"bc"},TankCtrl.loadHandler)

    firPos = transform:Find("FirePos")
    
    print(firPos)
    
end


function TankCtrl.loadHandler(gos)
    print(gos[0])
    bullet = gos[0]
end

function TankCtrl.Update()
    horizontal = UnityEngine.Input.GetAxis("Horizontal")
    vertical = UnityEngine.Input.GetAxis("Vertical")
    
    --[[if horizontal ~= 0 or vertical ~= 0 then
        dir = Vector3.New()
        dir.x = horizontal
        dir.y = -vertical
        transform:Translate(dir)
    end]]
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.W) then
        characterController:SimpleMove(-transform.up * UnityEngine.Time.deltaTime * 250)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.S) then
        characterController:SimpleMove(transform.up * UnityEngine.Time.deltaTime * 220)
    end
    
    if UnityEngine.Input.GetKey(UnityEngine.KeyCode.A) then
        transform:Rotate(Vector3.back * 2)
    elseif UnityEngine.Input.GetKey(UnityEngine.KeyCode.D) then
        transform:Rotate(Vector3.forward * 2)
    end
    
    --if UnityEngine.Input.GetKey(UnityEngine.KeyCode.P) then
    --加載子彈(按下鼠標(biāo)左鍵)
    if UnityEngine.Input.GetMouseButtonDown(0) then
        print(bullet)
        --獲取子彈
        temp = newObject(bullet)
        
        --把每一個發(fā)射的子彈存入戰(zhàn)斗子彈管理類
        BattleCtrl.GetInstance().Bullets[temp] = bc
        
        --將每個發(fā)射的子彈單個實例
        bc =  BulletCtrl:New(nil,temp)

        table.insert(bullets,bc)
        
        --設(shè)置父物體
        temp.transform:SetParent(firPos,false)
        temp.transform.localScale = Vector3(1,1,1)
        --temp.transform.localScale = Vector3.one
        temp.transform.localPosition = Vector3(0,0,0)
        
        temp.transform.parent = nil
        --取消設(shè)置父物體
        temp.transform.DetachChildren(firPos)
        
        
    end
    
    if table.getn(bullets) > 0 then
        for i,v in ipairs(bullets) do
            v:Update()
        end
    end
    
end
ezgif.com-video-to-gif.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荠雕,一起剝皮案震驚了整個濱河市稳其,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炸卑,老刑警劉巖既鞠,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異盖文,居然都是意外死亡嘱蛋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門五续,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洒敏,“玉大人,你說我怎么就攤上這事疙驾⌒谆铮” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵它碎,是天一觀的道長函荣。 經(jīng)常有香客問我显押,道長,這世上最難降的妖魔是什么傻挂? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任乘碑,我火速辦了婚禮,結(jié)果婚禮上踊谋,老公的妹妹穿的比我還像新娘蝉仇。我一直安慰自己旋讹,他們只是感情好殖蚕,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沉迹,像睡著了一般睦疫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鞭呕,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天蛤育,我揣著相機(jī)與錄音,去河邊找鬼葫松。 笑死瓦糕,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的腋么。 我是一名探鬼主播咕娄,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼珊擂!你這毒婦竟也來了圣勒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤摧扇,失蹤者是張志新(化名)和其女友劉穎圣贸,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扛稽,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吁峻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了在张。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锡搜。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瞧掺,靈堂內(nèi)的尸體忽然破棺而出耕餐,到底是詐尸還是另有隱情,我是刑警寧澤辟狈,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布肠缔,位于F島的核電站夏跷,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏明未。R本人自食惡果不足惜槽华,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望趟妥。 院中可真熱鬧猫态,春花似錦、人聲如沸披摄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疚膊。三九已至义辕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寓盗,已是汗流浹背灌砖。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留傀蚌,地道東北人基显。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像善炫,于是被迫代替她去往敵國和親撩幽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容