强化界面布局如下

强化界面

StrengthenView

1
2
3
4
5
6
7
8
9

[BindPrefab(Path.STRENGTHEN_VIEW)]
public class StrengthenView : ViewBase
{
protected override void InitChild()
{
UIUtil.Get("Switchplayer").Go.AddComponent<SwitchPlayer>();
}
}

Path内的路径自己添加即可

给SwitchPlayer对象添加SwitchPlayer脚本,SwitchPlayer脚本也是一个继承了ViewBase的脚本

修改ViewBase的逻辑

switchPlayer虽然是StrengthView的子物体,但我们依然可以给它单独添加脚本,同样继承ViewBase。只不过我们此时需要修改ViewBase,比如父物体的View被设定为Hide时,所有子物体的View也要被设定Hide。否则子物体肯定会出现问题。

我们先给ViewBase添加InitSubView方法,每个父UI元素动态挂载View脚本时,都会调用这个方法来缓存自己子物体中的View脚本。并且使用HashSet来缓存。

但是InitSubView方法需要在Init里面调用,并且必须在子物体都动态挂载完毕View脚本后才能调用InitSubView,很容易被忽略,所以我们可以在ViewBase里面添加抽象方法,强制View脚本首先实现动态挂载的逻辑。

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
using System.Collections.Generic;
using UnityEngine;

public abstract class ViewBase : MonoBehaviour, IView//改为抽象方法
{
private HashSet<ViewBase> _views;
private UIUtil m_UIUtil;
protected UIUtil UIUtil
{
get
{
if (m_UIUtil == null)
{
m_UIUtil = gameObject.AddComponent<UIUtil>();
m_UIUtil.Init();
}
return m_UIUtil;
}
}
public virtual void Init()//添加初始化方法
{
InitChild();
InitSubView();//+++
foreach (ViewBase view in _views)//+++
{
view.Init();
}
}
protected abstract void InitChild();//添加抽象方法
private void InitSubView()//+++
{
_views = new HashSet<ViewBase>();
ViewBase view = null;
foreach (Transform trans in transform)
{
view = trans.GetComponent<ViewBase>();
if (view != null)
{
_views.Add(view);
}
}
}
public virtual void Hide()
{
foreach (ViewBase view in _views)//+++
{
view.Hide();
}
gameObject.SetActive(false);//父物体要最后隐藏,否则可能会出现问题
}


public virtual void Show()
{
gameObject.SetActive(true);
foreach (ViewBase view in _views)//+++
{
view.Show();
}
}
}

修改SelectedHeroViewInit方法不需要重载了

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
using UnityEngine;

[BindPrefab(Path.SELECT_HERO_VIEW)]
public class SelectedHeroView : ViewBase
{
protected override void InitChild()//+++
{
UIUtil.Get("Heros").Go.AddComponent<SelectHero>();
UIUtil.Get("OK/Start").AddListener(() =>
{
//TODO: 切换到选择关卡界面
});
UIUtil.Get("Exit").AddListener(() =>
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.ExitPlaymode();
#endif
Application.Quit();
});
UIUtil.Get("Strengthen").AddListener(() =>
{
//TODO: 切换到强化界面
});
}
}

修改StartView

1
2
3
4
5
6
7
8
9
10
11
[BindPrefab(Path.START_VIEW)]
public class StartView : ViewBase
{
protected override void InitChild()
{
UIUtil.Get("Start").AddListener(() =>
{
UIMgr.Instance.Show(Path.SELECT_HERO_VIEW);
});
}
}

SwitchPlayer

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
using System;
using System.Collections.Generic;
using UnityEngine;

public class SwitchPlayer : ViewBase
{
private int _id;//标记当前正在选择中的飞机id
private Dictionary<int,List<Sprite>> _planeSprites;
private Action<int> _onSwitch;
protected override void InitChild()
{
UIUtil.Get("Left").AddListener(() => { Switch(ref _id, -1); });
UIUtil.Get("Right").AddListener(() => { Switch(ref _id, 1); });
LoadSprite();
}
private void LoadSprite()
{
_planeSprites = new Dictionary<int,List<Sprite>>();
Sprite[] sprites = LoadMgr.Instance.LoadAll<Sprite>(Path.PLAYER_PICTURE_FOLDER);
foreach (Sprite sprite in sprites)
{
string[] idData = sprite.name.Split('_');
int playerId = int.Parse(idData[0]);
if (!_planeSprites.ContainsKey(playerId))
{
_planeSprites.Add(playerId, new List<Sprite>());
}
_planeSprites[playerId].Add(sprite);
}
}
public override void Show()
{
_id = DataMgr.Instance.Get<int>(DataKeys.PLANE_ID);
Switch(ref _id, 0);
}
private void Switch(ref int id,int direction)
{
UpdateId(ref id,direction);
UpdateSprite(id);
_onSwitch?.Invoke(id);
}
private void UpdateId(ref int id,int direction)
{
int min = 0;
int max = _planeSprites.Count;
id += direction;
id = id < 0 ? min : id >= max ? max - 1 : id;
}
public void OnSwitchAction(Action<int> action)
{
_onSwitch = action;
}
private void UpdateSprite(int id)
{
int level = DataMgr.Instance.Get<int>(DataKeys.LEVEL);//从存档获取当前等级
UIUtil.Get("Icon").SetSprite(_planeSprites[id][level]);
}
}

我们的飞机有4个种类,每个种类有4个等级。先用_planeSprites字典把所有的飞机都缓存起来,这个字典的Count代表了所有飞机种类(4个)。按照这个数值来确定选择飞机的边界。

LoadSprite方法中,初始化_planeSprites字典

UpdateId方法中检测当前选择的id,确保不会越界,注意方法内使用了嵌套的三元运算。

UpdateSprite方法中确定当前选择的战机的等级,并显示。

注意这里重载了Show方法,但是没有调用base.Show,可能会出现问题

DataKeys

在配置文件中的变量名,我们自己写一个文件对应好。在Scripts——Const文件夹内新建DataKeys

1
2
3
4
5
6
7
8
9
10
public class DataKeys 
{
public const string LIFE = "life";
public const string ATTACK = "attack";
public const string FIRE_RATE = "direRate";
public const string STAR = "star";
public const string DIAMOND = "diamond";
public const string PLANE_ID = "PlaneId";
public const string LEVEL = "level";
}

增加加载API

ILoaderResourceLoaderLoadMgr添加加载任意类型的API

1
2
3
4
5
6
7
8
9
10
using System;
using UnityEngine;

public interface ILoader
{
public GameObject LoadPrefab(string path, Transform parent = null);
void LoadConfig(string path,Action<object> onComplete);
T Load<T>(string path) where T : UnityEngine.Object;
T[] LoadAll<T>(string path) where T: UnityEngine.Object;
}
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
public class ResourceLoader : ILoader
{
//...
public T Load<T>(string path) where T : UnityEngine.Object
{
T item = Resources.Load<T>(path);
if (item == null)
{
Debug.LogError("未在路径中找到对象:" + path);
return null;
}
else
return item;
}
public T[] LoadAll<T>(string path) where T : UnityEngine.Object
{
T[] items = Resources.LoadAll<T>(path);
if (items == null || items.Length == 0)
{
Debug.LogError("未在路径中找到对象:" + path);
return null;
}
else
return items;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
public class LoadMgr : NormalSingleton<LoadMgr>, ILoader
{
//...
public T Load<T>(string path) where T : UnityEngine.Object
{
return m_Loader.Load<T>(path);
}
public T[] LoadAll<T>(string path) where T : UnityEngine.Object
{
return m_Loader.LoadAll<T>(path);
}
}

SelectedHeroView

在其中添加打开强化界面的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using UnityEngine;

[BindPrefab(Path.SELECT_HERO_VIEW)]
public class SelectedHeroView : ViewBase
{
protected override void InitChild()
{
//...
UIUtil.Get("Strengthen").AddListener(() =>
{
UIMgr.Instance.Show(Path.STRENGTHEN_VIEW);
});
}
}