IGuideBehaviour
在Scripts文件夹中新建Guide——Frame文件夹,新建IGuideBehavior
文件
OnEnter
方法初始化引导行为,OnExit
方法退出行为。
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
| using System;
public interface IGuideBehaviour : IGuide {
}
public abstract class GuideBehaviourBase : IGuideBehaviour { private Action _callBack; public virtual void OnEnter(Action callBack) { _callBack = callBack; OnEnterLogic(); } public virtual void Update() {
} protected abstract void OnEnterLogic();
protected virtual void OnExit() { OnExitLogic(); _callBack?.Invoke(); } protected abstract void OnExitLogic(); }
|
IGuideGroup
需要配置每个Group内部的IGuideBehaviour
Group也可以嵌套Group,因为有时会有多个Group组合的情况,我们使用GuideGroupGroupBase
作为这种情况的基类。
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| using System.Collections.Generic; using System;
public interface IGuideGroup : IGuide { }
public abstract class GuideGroupBase<T> : IGuideGroup where T : IGuide { private Queue<T> _guideItems; private Action _complete; protected abstract bool IsTrigger { get; } protected abstract int GroupID { get; } protected int _dataId; private bool _firstExecute;
public GuideGroupBase(int parentId) { if (parentId < 0) { _dataId = parentId; return; } _dataId = GetDataId(parentId); } private int GetDataId(int parentId) { return parentId << 8 + GroupID; } public void OnEnter(Action action) { if (GuideDataMgr.Instance.GetData(_dataId)) { return; } SaveData(); _firstExecute = true; _complete = action; _guideItems = GetGuideItems(); } private void SaveData() { if (_dataId < 0) { return; }
GuideDataMgr.Instance.SaveData(_dataId); } public virtual void Update() { if (IsTrigger && _firstExecute) { _firstExecute = false; ExecuteGuideItem(); } } protected abstract Queue<T> GetGuideItems();
private bool ExecuteGuideItem() { if (_guideItems.Count > 0) { T item = _guideItems.Dequeue(); item.OnEnter(QueueEnd); return true; } return false; }
private void QueueEnd() { if (!ExecuteGuideItem()) { _complete?.Invoke(); } } }
public abstract class GuideBehaviourGroupBase : GuideGroupBase<IGuideBehaviour> { public GuideBehaviourGroupBase(int parentId) : base(parentId) {
} }
public abstract class GuideGroupGroupBase : GuideGroupBase<IGuideGroup> { public GuideGroupGroupBase(int parentId) : base(parentId) {
} }
|
IGuide和IGuideRoot
在Guide——Frame文件夹,新建IGuide
文件,配置内部的IGuideGroup
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 44 45 46 47 48 49
| using System; using System.Collections.Generic;
public interface IGuide { void OnEnter(Action callback = null); void Update(); } public interface IGuideRoot : IGuide { string GetViewName(); }
public abstract class GuideBase : IGuideRoot { private Queue<IGuideGroup> _groups; protected abstract int GuideID { get; } public virtual void OnEnter(Action callback = null) { _groups = GetGroups(); ExecuteChildEnter(); } public abstract string GetViewName(); public void Update() { if (_groups == null) return;
foreach (var group in _groups) { group.Update(); } } protected abstract Queue<IGuideGroup> GetGroups();
private void ExecuteChildEnter() { foreach (IGuideGroup group in _groups) { group.OnEnter(); } } }
|
GuideMgrBase和GuideMgr
Frame文件夹,新建GuideMgrBase
文件
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
| using System.Collections.Generic; using UnityEngine;
public abstract class GuideMgrBase<T> where T : new() { protected static T m_Instance; public static T Instance => m_Instance ??= new T(); private Dictionary<string, IGuideRoot> _viewGuidesDic; private IGuideRoot _currentGuide; public virtual void InitGuide() { _viewGuidesDic = GetViewGuidesDic(); } protected abstract Dictionary<string, IGuideRoot> GetViewGuidesDic(); protected void ShowUI(string uiPath) { if (_viewGuidesDic.ContainsKey(uiPath)) { _currentGuide = _viewGuidesDic[uiPath]; _currentGuide.OnEnter(); } } protected void HideUI(string uiPath) { if (_currentGuide.GetViewName() == uiPath) { _currentGuide = null; } } public void Update() => _currentGuide?.Update(); }
|
在Guide文件夹中新建Demo文件夹,在其中新建GuideMgr
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
| using System.Collections.Generic;
public class GuideMgr : GuideMgrBase<GuideMgr>, IUpdate { public int Times { get; set; } public int UpdateTimes { get; }
public override void InitGuide() { base.InitGuide(); UIMgr.Instance.AddHideListener(HideUI); UIMgr.Instance.AddShowListener(ShowUI); LifeCycleMgr.Instance.Add(LifeName.UPDATE, this); }
public void UpdateFun() { Update(); }
protected override Dictionary<string, IGuideRoot> GetViewGuidesDic() { Dictionary<string, IGuideRoot> dic = new(); IGuideRoot guide = new DemoViewGuide(); dic.Add(guide.GetViewName(), guide); return dic; } }
|
在GameRoot
中调用GuideMgr.InitGuide
GuideDataMgr
用来持久化Guide的数据,为了模块的独立性,所以单独实现一套数据持久化的方法。
这里使用了PlayerPrefs
来存储引导的进度数据,可以根据实际情况调整。
注意:GuideGroupGroup
这种套娃引导组不需要传入自己的Queue<IGuideGroup>
内的Group的构造函数的Key,因为这样一个套娃组对应的存档会出现多份,而一个套娃组只需要一份存档就可以,整个组代表的是一次完整的引导。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class GuideDataMgr { protected static GuideDataMgr m_Instance; public static GuideDataMgr Instance => m_Instance ??= new GuideDataMgr(); public void SaveData(int key, bool value = true) { UnityEngine.PlayerPrefs.SetInt(key.ToString(), value ? 1 : 0); } public bool GetData(int key) { int result = UnityEngine.PlayerPrefs.GetInt(key.ToString(), 0); return result == 1; } }
|
Demo举例
在Demo文件夹内新建Demo
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
| using System.Collections.Generic;
public class DemoViewGuide : GuideBase { protected override int GuideID { get; } protected override Queue<IGuideGroup> GetGroups() { Queue<IGuideGroup> groups = new(); groups.Enqueue(new DemoGuideGroupGroupA(GuideID)); groups.Enqueue(new DemoGuideBehaviourGroupA(GuideID)); return groups; }
public override string GetViewName() { return Pathes.START_VIEW; } }
public class DemoGuideGroupGroupA : GuideGroupGroupBase { public DemoGuideGroupGroupA(int parentId) : base(parentId) { }
protected override bool IsTrigger { get; }
protected override int GroupID { get; }
protected override Queue<IGuideGroup> GetGuideItems() { Queue<IGuideGroup> guideGroups = new(); guideGroups.Enqueue(new DemoGuideBehaviourGroupA()); guideGroups.Enqueue(new DemoGuideBehaviourGroupB()); return guideGroups;
} }
public class DemoGuideBehaviourGroupA : GuideBehaviourGroupBase { public DemoGuideBehaviourGroupA(int parentId = -1) : base(parentId) { }
protected override bool IsTrigger { get { return true; } }
protected override int GroupID { get; }
protected override Queue<IGuideBehaviour> GetGuideItems() { Queue<IGuideBehaviour> behaviours = new(); behaviours.Enqueue(new ClickButtonA()); return behaviours; } }
public class DemoGuideBehaviourGroupB : GuideBehaviourGroupBase { public DemoGuideBehaviourGroupB(int parentId = -1) : base(parentId) { }
protected override bool IsTrigger { get { return true; } } protected override int GroupID { get; } protected override Queue<IGuideBehaviour> GetGuideItems() { Queue<IGuideBehaviour> behaviours = new(); behaviours.Enqueue(new ClickButtonA()); return behaviours; } } public class ClickButtonA : GuideBehaviourBase { protected override void OnEnterLogic() { }
protected override void OnExitLogic() { } }
|