我们再次重构Game场景,引入层级来对Game场景中的对象进行管理。
修改SceneRoot预制体层级,添加MapMgr节点:
将MapMgr拉取进Resources——Prefab——Game中。并把SceneRoot预制体中的MapMgr节点删掉,仅保留Main Camera。
拉取一个小飞机到场景,命名为Player,并将Prefab保存到Resources——Prefab——Game中。
在Pathes
中添加这些Prefab的路径
1 2
| public const string PREFAB_MAP_MGR = PREFAB_GAME_FOLDER + "MapMgr"; public const string PREFAB_PLAYER = PREFAB_GAME_FOLDER + "Player";
|
在Enums
中添加GameLayer
枚举,这里设置成负数,方便在后面指定各个层级的z轴大小
1 2 3 4 5 6
| public enum GameLayer { BACKGROUND = 0, PLANE = -1, EFFECT = -2, }
|
SceneRoot
在Scripts——Logic文件夹中新建SceneRoot
,这个脚本负责当前场景所有逻辑脚本的初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| using UnityEngine;
public class SceneRoot : MonoBehaviour { public void Init() { var gameLayerMgr = gameObject.AddComponent<GameLayerMgr>(); gameLayerMgr.Init();
Transform camera = transform.Find("Main Camera"); camera.AddCo<CameraMove>();
var mapGo = LoadMgr.Instance.LoadPrefabAndInstantiate(Pathes.PREFAB_MAP_MGR); var mapmgr = mapGo.AddComponent<MapMgr>(); mapmgr.Init(camera); } }
|
修改SceneConfig
添加了SceneRoot
后,修改SceneConfig
的场景初始化逻辑
1 2 3 4 5 6 7 8 9 10 11
| private void AddLoaded() { SceneMgr.Instance.AddSceneLoaded(SceneName.Game, callback => PoolMgr.Instance.Init(callback)); SceneMgr.Instance.AddSceneLoaded(SceneName.Game, callback => { var go = LoadMgr.Instance.LoadPrefabAndInstantiate(Pathes.PREFAB_SCENEROOT); var root = go.AddComponent<SceneRoot>(); root.Init(); callback?.Invoke(); }); }
|
修改MapMgr
把初始化相机的逻辑转移到SceneRoot
中,并且让它继承BGView
(下面讲到)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| using UnityEngine;
public class MapMgr : BGView { public void Init(Transform camera) { Transform map1 = transform.Find("map_1"); Transform map0 = transform.Find("map_0"); float offset = Mathf.Abs(map1.position.y - map0.position.y); var item0 = map0.AddCo<MapItem>(); item0.Init(offset, camera); var item1 = map1.AddCo<MapItem>(); item1.Init(offset, camera); } }
|
GameLayerMgr
在Scripts——Logic文件夹中新建GameLayerMgr
,这个对象使用自己的单例,这个单例只在Game场景中起作用,离开Game场景后会被销毁。这个单例的创建和Init
方法关系密切,这和一般的Mono单例写法不同。
负责生成Game场景下各个层级物体的父对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| using System; using System.Collections.Generic; using UnityEngine;
public class GameLayerMgr : MonoBehaviour { private static GameLayerMgr instance; public static GameLayerMgr Instance { get { if (SceneMgr.Instance.IsScene(SceneName.Game)) { return instance; } else Debug.LogError("GameSceneMgr只能在Scene场景下运行"); return null; } } private Dictionary<GameLayer, Transform> _layerGoDic; public void Init() { instance = this; _layerGoDic = new Dictionary<GameLayer, Transform>(); foreach (GameLayer layer in Enum.GetValues(typeof(GameLayer))) { GameObject layerGo = new(layer.ToString()); layerGo.transform.position = Vector3.forward * (int)layer; layerGo.transform.SetParent(transform); _layerGoDic.Add(layer,layerGo.transform); } } public void SetLayerParent(IGameView gameView) { if (_layerGoDic.TryGetValue(gameView.GameLayer, out Transform parent)) { gameView.Self.SetParent(parent); } else Debug.LogError("当前层级并没有初始化进字典中:" + gameView.GameLayer.ToString()); } }
|
GameView
Game场景中的层级不同于UI,所有的UI基本的开闭逻辑都是相似的,而Game场景中的对象却是五花八门,所以需要新的接口进行管理。
在Scripts——Logic文件夹下新建View文件夹,在其中新建IGameView
IGameView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| using UnityEngine;
public interface IGameView : IInit { GameLayer GameLayer { get; } Transform Self { get; } } public abstract class GameViewBase : MonoBehaviour, IGameView { public abstract GameLayer GameLayer { get; }
public Transform Self => transform;
public virtual void Init() { } private void OnEnable() { if(GameLayerMgr.Instance != null) { GameLayerMgr.Instance.SetLayerParent(this); } Init(); } }
public class BGView : GameViewBase { public override GameLayer GameLayer => GameLayer.BACKGROUND; } public class PlaneView : GameViewBase { public override GameLayer GameLayer => GameLayer.PLANE; } public class EffectView : GameViewBase { public override GameLayer GameLayer => GameLayer.EFFECT; }
|