3.Unity 场景有限状态机(FSM)管理(最详细)
现在用FSM进行游戏场景管理还是比较多,主要是场景的进入退出处理任务和逻辑起比较清晰简单,当然现在一般xlua的hotfix来做热补丁的场景处理也多起来(以便于后期有副本的场景加载更新)。本篇(公司游戏没加场景动态更新前的)只介绍用c#处理的场景管理(后面有时间加一篇动态的更新的场景管理):
1.FSM场景管理 代码架构图:
2 代码块搭建说明:
(1)定义 接口Istate。
(2).定义所有场景状态机的父类ScenceState,并且继承接口Istate。
(3).定义条件转换类TransationPipe。
(4).定义录场景LoaginSatae,场景控制器LonginControll,场景显示接口LonginPresenter;主场景MainState......;战斗场景BattleState......。
(5).定义场景管理器SceneStateManger;并且创建登录场景LoaginSatae及相关转出条件;主场景MainState及相关转出条件;战斗场景BattleState及相关转出条件。
(6)定义游戏管理器GameManger,并且创建场景管理器SceneStateManger.调用场景入口。
3 具体代码
(1).接口Istate:
[code]public interface IState { //场景进入调用方法 void OnEnter (); //场景中轮询调用方法 void Tick (); //场景退出调用方法 void OnExit(); }
(2).类ScenceState:
[code]using UnityEngine; using System.Collections; using System.Collections.Generic; using UnityEngine.SceneManagement; public class SceneState :IState { /// <summary> /// 这个状态的持有者 /// </summary> protected SceneStateManager Owner; /// <summary> /// 这个状态的名字 /// </summary> public string name; private List<TransationPipe> pipelines = new List<TransationPipe>(); /// <summary> /// 关闭无参数的构造函数 /// </summary> private SceneState (){} //设置状态的持有者(场景管理器) public SceneState(string _name , SceneStateManager myOwner) { name = _name; Owner = myOwner; } //场景进入调用方法 public virtual void OnEnter() { } /// <summary> /// 转移条件检测 /// </summary> /// <returns>要跳转到哪里去.</returns> public string CheckTransation() { for(int i = 0; i < pipelines.Count; i++) { if (pipelines [i].condition != null) { if (pipelines [i].condition ()) { return pipelines [i].target; } } } return GameSceneNames.NO_OUPT; } public virtual void Tick() { } public virtual void OnExit() { Debug.Log(this.name + " :场景退出了"); } //添加转移条件 public void AddPipe(TransationPipe tp) { if (pipelines.Contains(tp)) Debug.Log("已经有了此条件"); else pipelines.Add(tp); } }
(3).场景转移条件类TransationPipe:
[code]public class TransationPipe { public delegate bool Check(); //获取转出条件的方法 public Check condition; //场景转出目的场景的名字 public string target; private TransationPipe(){} public TransationPipe(string des , Check _condition) { target = des; condition = _condition; } }
(4.1).登录场景状态机LonginState:
[code]using UnityEngine; using System.Collections; public class LonginState : SceneState { public LonginState (string name, SceneStateManager manager) : base (name ,manager){ } //场景需求的UI和模型对象引用(最好动态加载) LoginPresenter presenter; //场景进入调用 public override void OnEnter () { //设置场景条件为退出状态 SceneCtrl.Instance.isSureExit = true; presenter = GameObject.Find("Canvas").GetComponent<LoginPresenter>(); //登录场景中的场景控制器介入 LoginPanelController.Instance.Initalize (presenter); //添加相关监听(是否获取地块信息成功)。(mvc)并且在LoginPanelController中处理相关获取的 信息并且调用Presenter显示 GameManager.Instance.gameEventDispatcher.AddEventListener(GameEventType.BlockInfoSuccess, LoginPanelController.Instance.OnGetBlockInfoSuccess); //添加相关监听(是否获取地块信息失败) GameManager.Instance.gameEventDispatcher.AddEventListener(GameEventType.BlockInfoFailure, LoginPanelController.Instance.OnGetBlockInfoFailure); //添加相关监听(是否获取天气信息成功) GameManager.Instance.gameEventDispatcher.AddEventListener(GameEventType.WeatherInfoSuccess, LoginPanelController.Instance.OnGetWetherInfoSuccess); //添加相关监听(是否获取天气信息失败) GameManager.Instance.gameEventDispatcher.AddEventListener(GameEventType.WeatherInfoFailure, LoginPanelController.Instance.OnGetWetherInfoFailure); //添加相关监听(是否获取登录信息成功)登录 GameManager.Instance.gameEventDispatcher.AddEventListener(GameEventType.LoginSuccess, LoginPanelController.Instance.OnPlayerLoginSuccess); GameManager.Instance.gameEventDispatcher.AddEventListener(GameEventType.LoginFailure, LoginPanelController.Instance.OnPlayerLoginFailure); //开启音乐 AudioManager.Instance.PlayBGM("login"); //退出到主场景的条件开启可设置 SceneCtrl.Instance.isExitMainScene = false; GameManager.Instance.socketManager.ExitConectAgin(); SceneCtrl.Instance.loginSuccess = false; //登录场景通知按钮添加监听 presenter.noticeBtn.onClick.AddListener(LoginPanelController.Instance.OpenNotice); GameManager.Instance.gameInstance.RandomEventContainer.Clear (); } public override void Tick () { //计算时间 LoginPanelController.Instance.TimeTick(); } //场景退出 public override void OnExit () { //移除相关监听 GameManager.Instance.gameEventDispatcher.RemoveEventListener (GameEventType.LoginSuccess, LoginPanelController.Instance.OnPlayerLoginSuccess); GameManager.Instance.gameEventDispatcher.RemoveEventListener (GameEventType.LoginFailure, LoginPanelController.Instance.OnPlayerLoginFailure); GameManager.Instance.gameEventDispatcher.RemoveEventListener(GameEventType.BlockInfoSuccess, LoginPanelController.Instance.OnGetBlockInfoSuccess); GameManager.Instance.gameEventDispatcher.RemoveEventListener(GameEventType.BlockInfoFailure, LoginPanelController.Instance.OnGetBlockInfoFailure); GameManager.Instance.gameEventDispatcher.RemoveEventListener(GameEventType.WeatherInfoSuccess, LoginPanelController.Instance.OnGetWetherInfoSuccess); GameManager.Instance.gameEventDispatcher.RemoveEventListener(GameEventType.WeatherInfoFailure, LoginPanelController.Instance.OnGetWetherInfoFailure); GameManager.Instance.gameEventDispatcher.RemoveEventListener(GameEventType.QueryOwnerJobSuccess, LoginPanelController.Instance.OnGetOwnerJobSuccess); presenter.noticeBtn.onClick.RemoveListener (LoginPanelController.Instance.OpenNotice); SceneCtrl.Instance.loginSuccess = false; } }
登录场景显示对象接口LoginPresenter:
[code]using UnityEngine; using System.Collections; using UnityEngine.UI; public class LoginPresenter : MonoBehaviour { public LoginStartPresenter start_L_Presenter; public LoginRegisterPresenter register_L_Presenter; public LoginNewPsdPresenter newPsd_L_Presenter; public LoginAgreementPresenter agreement_L_Presenter; public OtherLoginResult loginResult; /// <summary> /// 公告按钮 /// </summary> public MyButton noticeBtn; #region invite panel //public GameObject inviteControl; //public Button inviteButton; //public InputField inputInvite; #endregion }
登录场景控制器LonginPanleController:
[code]public class LoginPanelController : BaseSingleton<LoginPanelController> { //veiw的调用接口对象 private LoginPresenter myPresenter; private string smsCode; //private string inviteCode=""; public OtherLoginResult.LoginType loginType = OtherLoginResult.LoginType.None; public bool mailSysSwitch = false; /// <summary> /// 登录场景 显示表现引用对象设置 /// </summary> private bool isLoginSecneLogin; public void Initalize(LoginPresenter presenter) { myPresenter = presenter; isLoginSecneLogin = true; myPresenter.start_L_Presenter.Initilize(); } //登录帐号和密码保存 public void RememberPassword(string account, string psd, string isOn, string loginType) { //2019.4.26清理帐号切换系统邮件的清理 string LastAcouut = PlayerPrefs.GetString("RememberAccount"); if(LastAcouut!= account) { GameInstance.mailSystem.Clear(); } PlayerPrefs.SetString("RememberAccount", account); PlayerPrefs.SetString("RememberPsd", psd); PlayerPrefs.SetString("ToggleIsOn", isOn); PlayerPrefs.SetString("LoginType", loginType); } /// <summary> /// 每帧执行 /// </summary> public void TimeTick() { myPresenter.register_L_Presenter.Tick(); myPresenter.newPsd_L_Presenter.Tick(); } /// <summary> /// 进入注册界面 /// </summary> public void SetRegisterState() { myPresenter.register_L_Presenter.Initilize(); } /// <summary> /// 进入重新申请密码界面 /// </summary> public void SetApplyNewPsdState() { myPresenter.newPsd_L_Presenter.Initilize(); } /// <summary> /// 设置开始界面 /// </summary> public void SetLoginStartState(bool isActive) { myPresenter.start_L_Presenter.gameObject.SetActive(isActive); } /// <summary> /// 进入用户协议展示 /// </summary> public void SetAgreementState() { myPresenter.agreement_L_Presenter.Initilize(); } /// <summary> /// 调用web网页服务 /// </summary> public void OpenNotice() { AndroidSDK.OpenWebView(GlobalSetting.NOTICE_URL); } public void Clear() { myPresenter.start_L_Presenter.Clear(); } #region 获取登录数据后触发的回调函数 public void OnPlayerLoginSuccess(GameEvent evt) { PlayerData data = evt.Param["PlayerData"] as PlayerData; GameInstance.heroDate = data; GameInstance.actions = evt.Param["actions"] as string; //记录切换职业时间 GameInstance.changeJobTime = MessageHeadInfo.GetDateTime(); //remember account psd string isOn = (myPresenter.start_L_Presenter.r_Psd_Toggle.isOn).ToString(); RememberPassword(myPresenter.start_L_Presenter.account.text, myPresenter.start_L_Presenter.userPwd.text, isOn, ((int)loginType).ToString()); GameInstance.userX = Mathf.FloorToInt(System.Convert.ToSingle(data.lastX)); GameInstance.userY = Mathf.FloorToInt(System.Convert.ToSingle(data.lastY)); //请求查询周围玩家数据 if (GameManager.Instance.locLimit == LocationLimit.Open) { Session.SendInquireAroundMessage(DeviceInfo.LATITUDE, DeviceInfo.LONGITUDE); } else { BlockPositionConvertResult res = OptionUtil.GetLoAndLaFromBlockPosition(System.Convert.ToSingle(GameInstance.heroDate.lastX), System.Convert.ToSingle(GameInstance.heroDate.lastY)); // World2Unity.Instance.hisLatitude = res.la; // World2Unity.Instance.hisLong = res.lo; Session.SendInquireAroundMessage(res.la, res.lo); } //登录场景登录成功 if (isLoginSecneLogin) { OptionUtil.PopErrorFrame(65); isLoginSecneLogin = false; } } //显示登录失败 public void OnPlayerLoginFailure(GameEvent evt) { string errorCode = (string)evt.Param["error code"]; Debug.Log("登陆失败,错误码:" + evt.Param["error code"]); OptionUtil.PopErrorFrame(StringUtil.ToInt(errorCode)); } //重服务器获取地块数据后触发的回调函数 public void OnGetBlockInfoSuccess(GameEvent type) { List<BlockData> dataList = type.Param["tiles"] as List<BlockData>; int userX = (int)type.Param["userX"]; int userY = (int)type.Param["userY"]; GameInstance.tiles = dataList; // GameInstance.userX = userX; // GameInstance.userY = userY; //Session.SendQueryTaskByBlockCoordinate(userX, userY); Session.SendQueryWeatherMessage(); // Debug.Log("请求地块数据成功,开始获取天气信息"); } public void OnGetBlockInfoFailure(GameEvent type) { string id = type.Param["code"] as string; OptionUtil.PopErrorFrame(int.Parse(id)); //Debug.Log("请求地块数据失败,Errcode==" + id); } //重服务器获取天启数据后触发的回调函数 public void OnGetWetherInfoSuccess(GameEvent type) { WeatherSystem.WeatherInfo info = new WeatherSystem.WeatherInfo(); int id = (int)type.Param["WeatherType"]; info.type = (WeatherSystem.WeatherType)id; info.weatherDescription = type.Param["WeatherDescription"].ToString(); GameManager.Instance.gameInstance.weatherInfo = info; Session.SendQueryDiseaseMessage(); //Debug.Log("请求天气数据成功,开始获取疾病信息"); } public void OnGetWetherInfoFailure(GameEvent evt) { string res = evt.Param["code"] as string; OptionUtil.PopErrorFrame(int.Parse(res)); //Debug.Log("请求天气数据失败,Errcode=="+res); } #region 第三方登陆 /// <summary> /// 调用SDK第三方登陆——QQ登录 /// </summary> public void qqLogin() { if (myPresenter.start_L_Presenter.agreeToggle.isOn) { #if UNITY_ANDROID Debug.Log("准备调用QQ登录"); using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity")) { jo.Call("toLoginQQ"); } } #endif #if UNITY_IOS myPresenter.loginResult.qqLoginButtonClick(); #endif } } /// <summary> /// 调用SDK第三方登陆——微信登录 /// </summary> public void wehchatLogin() { if (myPresenter.start_L_Presenter.agreeToggle.isOn) { #if UNITY_ANDROID Debug.Log("准备调用微信登陆"); using (AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { using (AndroidJavaObject jo = jc.GetStatic<AndroidJavaObject>("currentActivity")) { jo.Call("toLoginWeChat"); } } #endif #if UNITY_IOS myPresenter.loginResult.weixinLodinButtonClick(); #endif } } /// <summary> /// 微博登录 /// </summary> public void WeiBoLogin() { OptionUtil.PopErrorFrame(35); } #endregion }
(4.2)主场景状态机ManiScenceState:
[code]using UnityEngine; using System.Collections; using WeatherSystem; using System.Collections.Generic; using Map; using System.Linq; using System; public class MainSceneState : SceneState { //场景对象引用接口 private MainSceneStatePresnter presenter; ///主场景各种管理器...( 主场景UI架构的FSM管理器;天气管理;地图管理;角色管理;技能管理;任务管理;商店管理..等) public MainSceneState(string name, SceneStateManager manager) : base(name, manager) { } public override void OnEnter() { //初始化摄像机 InitCamera(); //主场景控制器介入 MainScenceStateController.Instance.Initalize(presenter); //初始化各种主场景需要使用的管理器并且调用其入口函数 //代码xxxxxxxx............. } //主场景调用轮询方法 public override void Tick() { } //退出 public override void OnExit() { //移除监听 } }
MianScenceStatePresnter: 调用主场景中各种管理器依附的引用对象和没有被管理器包含的引用对象的接口。代码...
MainScenceStateController: 各种监听函数,加载和操作显示。
(4.3)BatttleScenceState:
[code]using UnityEngine; using System.Collections; using WeatherSystem; using System.Collections.Generic; using Map; using System.Linq; using System; public class BattleSceneState : SceneState { //场景对象引用接口 private BattleSceneStatePresnter presenter; ///主场景各种管理器...( 主场景UI架构的FSM管理器;天气管理;地图管理;角色管理;技能管理;任务管理;商店管理..等) public MainSceneState(string name, SceneStateManager manager) : base(name, manager) { } public override void OnEnter() { //初始化摄像机 InitCamera(); //场景控制器介入 BattleScenceController.Instance.Initalize(presenter); //初始化场景中需要使用的管理器并且调用其入口函数 //代码xxxxxxxx............. } //主场景调用轮询方法 public override void Tick() { } //退出 public override void OnExit() { //移除监听 } }
BattleScenceStatePresnter: 调用主场景中各种管理器依附的引用对象和没有被管理器包含的引用对象的接口。代码...
BattleScenceStateController: 各种监听函数,对象加载和操作显示。
(5) .场景管理器ScenceStateManager:
[code]using UnityEngine; using System.Collections; using System.Collections.Generic; public class SceneStateManager { private MonoBehaviour owner; //状态机场景储存器 private Dictionary<string, SceneState> transationMap = new Dictionary<string, SceneState>(); private SceneStateManager() { } private bool forceStop = false; public SceneStateManager(MonoBehaviour myOwner)//, SceneState defaultScene) { owner = myOwner; //初始化各个场景状态机 InitalizeSceneFSM(); // ownScene = defaultScene; } private SceneState current; private SceneState last; //场景入口函数 public void SetDefaultState(SceneState initState) { current = initState; current.OnEnter(); } /// <summary> /// 初始化场景状态机 /// </summary> void InitalizeSceneFSM() { //创建登录场景 GameLoginState login = new GameLoginState(GameSceneNames.LOGIN_SCENE, mySceneStateManager); //加入第登录场景的装换条件,从哪里到哪里 ,这里有1个,从登陆到选人 TransationPipe pipe2Main = new TransationPipe(GameSceneNames.MAIN_SCENE, SceneCtrl.Instance.IsLoginSuccsee); //给登录场景添加转移条件 login.AddPipe(pipe2Main);、 //把登录场景添加到到储存器中 this.AddSceneState(login); //创建主场景 MainSceneState main = new MainSceneState(GameSceneNames.MAIN_SCENE, mySceneStateManager); //TransationPipe pipe2mainUI = new TransationPipe() #region 添加的主场景到登录界面的条件 TransationPipe mainToLogin = new TransationPipe(GameSceneNames.LOGIN_SCENE, SceneCtrl.Instance.IsExitMain); main.AddPipe(mainToLogin); #endregion //主场景跳转到战斗 TransationPipe main2battle = new TransationPipe(GameSceneNames.BATTLE_SCENE, SceneCtrl.Instance.ReadyToBattle); main.AddPipe(main2battle); this.AddSceneState(main); //创建战斗场景 BattleSceneState battle = new BattleSceneState(GameSceneNames.BATTLE_SCENE, mySceneStateManager); //战斗场景转主场景 TransationPipe battle2main = new TransationPipe(GameSceneNames.MAIN_SCENE, SceneCtrl.Instance.ReadyBattleToMain); battle.AddPipe(battle2main); this.AddSceneState(battle); //调用场景入口函数 this.SetDefaultState(login); } public SceneState GetCurrentState() { return current; } /// <summary> /// 每一帧都会被调用 /// </summary> public void Tick() { if (current == null) return; if (forceStop) return; string result = current.CheckTransation(); if (result != GameSceneNames.NO_OUPT) { SceneState target = transationMap[result]; last = current; current = target; last.OnExit(); Shutdown(); //Debug.Log("resoult==" + result); owner.StartCoroutine(MySceneManager.Instance.LoadSceneAsync(result)); } else { current.Tick(); } } public void EnterNextState() { current.OnEnter(); } /// <summary> /// 加入一个状态到状态机 /// </summary> /// <param name="state2Add">要加入的状态.</param> public void AddSceneState(SceneState state2Add) { if (state2Add.name == "" || state2Add.name == string.Empty) { Debug.LogError("your SceneState name is empty!!!!!!"); return; } if (transationMap.ContainsKey(state2Add.name)) { Debug.LogError("the state is already in machine : " + state2Add.name); return; } else { transationMap.Add(state2Add.name, state2Add); } } /// <summary> /// 从状态机内移除一个状态 /// </summary> /// <param name="name">要移除的状态名字.</param> public void RemoveSceneState(string name) { if (name == string.Empty || name == "") { Debug.LogError("your name is empty @ SceneFSM"); return; } if (transationMap.ContainsKey(name)) { transationMap.Remove(name); } else { Debug.LogError("Can NOT find your state BY your Name@ SCENE_FSM"); return; } } public void Shutdown() { forceStop = true; } public void Restart() { forceStop = false; } } public class GameSceneNames { public static readonly string NO_OUPT = string.Empty; public static readonly string LOGIN_SCENE = "game_login"; public static readonly string MAIN_SCENE = "Game_Main"; public static readonly string BATTLE_SCENE = "Battle"; public static readonly string Bridge_SCENE = "Empty"; }
(6),游戏管理器GameManger:
[code]using UnityEngine; using System.Text; using System.Collections.Generic; using InputEventSystem; using System.Runtime.InteropServices; using System; using UnityEngine.Events; using UnityEngine.Networking; public enum LocationLimit { None = 0, Open = 1,//开启了定位权限 Off = 2 } public class GameManager : MonoBehaviour { #if UNITY_IOS [DllImport("__Internal")] private static extern void GDMapInitLocationManager(); #endif private SceneStateManager mySceneStateManager; public GameInstance gameInstance; public SocketManager socketManager; public EventDispather gameEventDispatcher; private Queue<GameEvent> eventQueue; public InputDetector inputSystem; public ErrorInfoManager errorInfoManager; public AllXmlData allXmlData; //public PackageTimeLine myTimeLine = new PackageTimeLine(30f); public bool isNetworkReady = false; /// <summary> /// error popup /// </summary> public ActivityManager activity; /// <summary> /// ab包加载管理 /// </summary> public Resource_LoadManager abLoadManger; public SkinAudioPool skinSoundPool; LoadResources load; [SerializeField] Activity[] popActs; /// <summary> /// 语言配置表 /// </summary> //public LanguageManager languageManager; #region singleton private static GameManager _instance; public static GameManager Instance { get { return _instance; } } #endregion /// <summary> /// 定位权限 /// </summary> public LocationLimit locLimit = LocationLimit.Off; void Awake() { _instance = this; DontDestroyOnLoad(this.gameObject); //InitGetLocationLimit(); } void Start() { //更新 //ios地图管理器 #if UNITY_IOS && !UNITY_EDITOR GDMapInitLocationManager(); #endif //创建ab管理器 abLoadManger = new Resource_LoadManager(); //创建xml数据管理对象 allXmlData = new AllXmlData(); //创建声音对象池 skinSoundPool = new SkinAudioPool(); //创建事件队列 eventQueue = new Queue<GameEvent>(); //创建输入对象控制器 inputSystem = new InputDetector(); //创建弹窗管理器 activity = new ActivityManager(); foreach (var item in popActs) { activity.AddActivity(item); } //初始化场景状态机管理器 InitalizeSceneFSM(); //创建全局变量储存器 CreateGameInstance(); //创建事件发布器 InitEventDispather(); //创建网络管理器 InitalizeNetwork(); //设备管理器 InitGetDeviceInfo(); //UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneWasLoaded; //调用资源更新下载 GameObject Obj = new GameObject(); load = Obj.AddComponent<LoadResources>(); } /// <summary> /// 初始获取定位权限信息 /// </summary> private void InitGetLocationLimit() { string limit = AndroidSDK.GetLocationLimitSign(); if (limit == "true") locLimit = LocationLimit.Open; else locLimit = LocationLimit.Off; Debug.Log("获取定位权限信息limit==" + limit + "___权限==" + locLimit); } //加载下一个场景 //void OnSceneWasLoaded(UnityEngine.SceneManagement.Scene sce, UnityEngine.SceneManagement.LoadSceneMode mode) //{ // mySceneStateManager.EnterNextState(); // mySceneStateManager.Restart(); //} void Update() { //更新消息队列 if (eventQueue.Count != 0) { for (int i = 0; i < eventQueue.Count; i++) { gameEventDispatcher.Dispatch(eventQueue.Dequeue()); } } //触摸事件管理器 inputSystem.Process(); //更新场景管理器 mySceneStateManager.Tick(); } void FixedUpdate() { if (isNetworkReady) socketManager.Tick(); } /// <summary> /// 初始化场景状态机管理器 /// </summary> void InitalizeSceneFSM() { mySceneStateManager = new SceneStateManager(this); } //创建全局变量储存器 void CreateGameInstance() { gameInstance = new GameInstance(); } /// <summary> /// 初始化网络模块 /// </summary> void InitalizeNetwork() { try { socketManager = new SocketManager(); } catch (Exception e) { Debug.LogError("服务器分配出错:" + e); } } /// <summary> /// 创建事件发布器 /// </summary> void InitEventDispather() { gameEventDispatcher = new EventDispather(); gameEventDispatcher.AddEventListener(GameEventType.CanNotConnectToServer, SceneCtrl.Instance.OnConnectServer); gameEventDispatcher.AddEventListener(GameEventType.ConnectServerSuccess, SceneCtrl.Instance.OnConnectServer); } /// <summary> /// 获取手机设备信息 /// </summary> void InitGetDeviceInfo() { DeviceInfo.DEVICECODE = SystemInfo.deviceUniqueIdentifier; DeviceInfo.DEVICEMODEL = SystemInfo.deviceModel; DeviceInfo.CLIENTVERSION = "1.0"; DeviceInfo.SYSTEMVERSION = SystemInfo.operatingSystem; DeviceInfo.CHANNEL = SystemInfo.deviceType.ToString(); string sHostName = System.Net.Dns.GetHostName(); DeviceInfo.PLAYER_IPADDRESS = System.Net.Dns.GetHostAddresses(sHostName)[0].ToString(); // Debug.Log("DeviceInfo.PLAYER_IPADDRESS==" + DeviceInfo.PLAYER_IPADDRESS); GetGPSInfo(); Invoke("GetGPSInfo", 1.5f); } //获取jps信息 public void GetGPSInfo() { if (Input.location.status == LocationServiceStatus.Failed) { Debug.LogError("Unable to determine device location"); return; } else { if (locLimit == LocationLimit.Open) { //DeviceInfo.LATITUDE = Input.location.lastData.latitude; //DeviceInfo.LONGITUDE = Input.location.lastData.longitude; //Debug.Log(DeviceInfo.LATITUDE + " +++ " + DeviceInfo.LONGITUDE); #if !UNITY_EDITOR DeviceInfo.LATITUDE = AndroidSDK.GetLa(); DeviceInfo.LONGITUDE = AndroidSDK.GetLo(); //World2Unity.Instance.hisLatitude = DeviceInfo.LATITUDE; //World2Unity.Instance.hisLong = DeviceInfo.LONGITUDE; #endif } } } void OnDestroy() { //Debug.Log("aaaaaaaa"); //向服务器发送断开请求 Session.SendExitMessage(); socketManager.Close(); } }
Ok 场景框架打完收工也算是工作总结,用xlua 处理的话基本要重写一遍 ,工作量比较大。不涉及的运算的地方都可以用 ,本菜鸟还是觉得在场景管理器中添加各干个场景的时候对副本场景单独提出一个方法用xlua的热补丁处理,副本场景用一个链表,这样就不用所有代码都有lua写。
- 点赞
- 收藏
- 分享
- 文章举报
- Unity中使用有限状态机(FSM)来管理UI面板的切换(UGUI)
- Unity中FSM有限状态机
- 在Unity中实现FSM有限状态机
- Unity使用git管理项目时场景中丢失脚本的问题
- 【Unity】四叉树/八叉树管理和动态加载场景物件
- Unity FSM 有限状态机
- unity游戏开发中的有限状态机FSM经验
- UIFramework之Unity4.x 场景管理策略
- Unity 有限状态机FSM原理剖析
- unity 四叉树管理场景
- Unity场景渲染之Lighting 面板的参数设置用途详细总结
- Linux磁盘与文件系统管理详细总结
- [OpenGL] 场景管理四叉树demo
- Linux逻辑卷管理(LVM)详细教程
- Android中资源管理机制详细分析
- Asp.net 2.0 自定义控件开发专题[详细探讨页面状态(视图状态和控件状态)机制及其使用场景](示例代码下载)
- Unity 数据管理
- 威博文件管理系统应用场景与简介
- Unity 音效管理