UMVCL3——使用MVC思想制作UI逻辑

使用MVC的UI逻辑制作实例

还是和上一章相同的UI需求

假设我们有一个主面板,它的各个UI控件需要的效果如下

image

有一个选角面板,它的各个UI控件需要的效果如下

image

该UI的MVC的代码逻辑如下:

Model层

Model层主要负责存储管理数据,及数据相关的操作,同时,对Controller层开放更新数据方法,更新数据时,执行Controller层的监听数据更新的函数

具体实现:

  1. 初始化,读取数据
  2. 更新数据(同时让Controller层脚本监听数据的更新)
  3. 保存数据
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
using UnityEngine;
using UnityEngine.Events;

public class PlayerModel
{
//Model层主要负责存储管理数据,及数据相关的操作
// 初始化,读取数据
// 更新数据
// 保存数据

private static PlayerModel instance = null;
public static PlayerModel Instance
{
get
{
if (instance == null)
{
instance = new PlayerModel();
instance.Init();
}
return instance;
}
}
private PlayerModel() { }

//数据内容
private string name;
private int level;
private int money;
private int gem;
private int power;

private int hp;
private int atk;
private int def;
private int crit;
private int miss;
private int luck;

#region 对外开放的属性
public string Name => name;
public int Level => level;
public int Money => money;
public int Gem => gem;
public int Power => power;

public int Hp => hp;
public int Atk => atk;
public int Def => def;
public int Crit => crit;
public int Miss => miss;
public int Luck => luck;

#endregion

//通知外部更新的事件
private event UnityAction<PlayerModel> updateEvent;

//数据相关的操作
//初始化
private void Init()
{
name = PlayerPrefs.GetString("PlayerName", "SevenL");
level = PlayerPrefs.GetInt("PlayerLev", 1);
money = PlayerPrefs.GetInt("PlayerMoney", 9999);
gem = PlayerPrefs.GetInt("PlayerGem", 8888);
power = PlayerPrefs.GetInt("PlayerPower", 99);

hp = PlayerPrefs.GetInt("PlayerHp", 100);
atk = PlayerPrefs.GetInt("PlayerAtk", 20);
def = PlayerPrefs.GetInt("PlayerDef", 10);
crit = PlayerPrefs.GetInt("PlayerCrit", 20);
miss = PlayerPrefs.GetInt("PlayerMiss", 10);
luck = PlayerPrefs.GetInt("PlayerLuck", 40);
}

//更新
public void LevelUp()
{
//升级 改变内容
level += 1;
hp += level;
atk += level;
def += level;
crit += level;
miss += level;
luck += level;

SaveData();
}

//保存
private void SaveData()
{
PlayerPrefs.SetString("PlayerName", name);
PlayerPrefs.SetInt("PlayerLev", level);
PlayerPrefs.SetInt("PlayerMoney", money);
PlayerPrefs.SetInt("PlayerGem", gem);
PlayerPrefs.SetInt("PlayerPower", power);

PlayerPrefs.SetInt("PlayerHp", hp);
PlayerPrefs.SetInt("PlayerAtk", atk);
PlayerPrefs.SetInt("PlayerDef", def);
PlayerPrefs.SetInt("PlayerCrit", crit);
PlayerPrefs.SetInt("PlayerMiss", miss);
PlayerPrefs.SetInt("PlayerLuck", luck);

UpdateInfo();
}

//添加对数据更新的监听函数,监听函数参数为自己
public void AddEventListener(UnityAction<PlayerModel> function)
{
updateEvent += function;
}

//移除对数据更新的监听函数
public void RemoveEventListener(UnityAction<PlayerModel> function)
{
updateEvent -= function;
}

//数据更新时执行各个监听函数
private void UpdateInfo()
{
updateEvent(this);
}
}

View层

View层主要负责管理UI控件,将用户行为传入Control层,对Control层开放更新控件显示方法

具体实现:

  1. 管理控件
  2. 更新控件显示

MainView.cs

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

public class MainView : MonoBehaviour
{
//管理控件
//提供面板更新相关方法

public Text txtName;
public Text txtLev;
public Text txtMoney;
public Text txtGem;
public Text txtPower;

public Button btnRole;

public void UpdateInfo(PlayerModel data)
{
txtName.text = data.Name;
txtLev.text = "LV." + data.Level.ToString();
txtMoney.text = data.Money.ToString();
txtGem.text = data.Gem.ToString();
txtPower.text = data.Power.ToString();
}
}

RoleView.cs

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

public class RoleView : MonoBehaviour
{
public Text txtLev;
public Text txtHp;
public Text txtAtk;
public Text txtDef;
public Text txtCrit;
public Text txtMiss;
public Text txtLuck;

public Button btnClose;
public Button btnLevUp;

public void UpdateInfo(PlayerModel data)
{
txtLev.text = "LV." + data.Level.ToString();
txtHp.text = data.Hp.ToString();
txtAtk.text = data.Atk.ToString();
txtDef.text = data.Def.ToString();
txtCrit.text = data.Crit.ToString();
txtMiss.text = data.Miss.ToString();
txtLuck.text = data.Luck.ToString();
}

}

Controller层

Control层主要负责控制面板的显隐,监听View层传入的用户行为,执行View层的更新方法,执行Model的操作数据方法,监听Model层的数据更新

具体实现:

  1. 界面的显隐
  2. 界面事件的监听 来处理对应的业务逻辑(触发Model层提供的操作数据方法)
  3. 监听Model层的数据更新
  4. 执行View层的控件更新方法

MainController.cs

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


public class MainController : MonoBehaviour
{
//界面的显隐
//界面事件的监听 来处理对应的业务逻辑
//界面的更新

private static MainController controller = null;
public static MainController Instance => controller;

//Controller中需要得到界面
private MainView mainView;

private void Start()
{
mainView = GetComponent<MainView>();
mainView.UpdateInfo(PlayerModel.Instance);
PlayerModel.Instance.AddEventListener(UpdateInfo);
//界面事件的监听,来处理对应的业务逻辑
mainView.btnRole.onClick.AddListener(() =>
{
//显示角色面板
RoleController.ShowMe();
});
}

private void OnDestroy()
{
PlayerModel.Instance.RemoveEventListener(UpdateInfo);
}

private void UpdateInfo(PlayerModel player)
{
if (mainView != null)
mainView.UpdateInfo(player);
}

public static void ShowMe()
{
if (controller == null)
{
//实例化面板对象
GameObject res = Resources.Load<GameObject>("UI/MainPanel");
GameObject obj = Instantiate(res);
obj.transform.SetParent(GameObject.Find("Canvas").transform, false);
controller = obj.GetComponent<MainController>();
}
controller.gameObject.SetActive(true);
}

public static void HideMe()
{
if (controller != null)
{
controller.gameObject.SetActive(false);
}
}
}

RoleController.cs

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

public class RoleController : MonoBehaviour
{
private RoleView roleView;

private static RoleController controller = null;

public static RoleController Controller => controller;

void Start()
{
roleView = GetComponent<RoleView>();
roleView.UpdateInfo(PlayerModel.Instance);
PlayerModel.Instance.AddEventListener(UpdateInfo);
roleView.btnClose.onClick.AddListener(() =>
{
HideMe();
});
roleView.btnLevUp.onClick.AddListener(() =>
{
PlayerModel.Instance.LevelUp();
});
}

private void OnDestroy()
{
PlayerModel.Instance.RemoveEventListener(UpdateInfo);
}

private void UpdateInfo(PlayerModel player)
{
if (roleView != null)
roleView.UpdateInfo(player);
}

public static void ShowMe()
{
if (controller == null)
{
//实例化面板对象
GameObject res = Resources.Load<GameObject>("UI/RolePanel");
GameObject obj = Instantiate(res);
obj.transform.SetParent(GameObject.Find("Canvas").transform, false);
controller = obj.GetComponent<RoleController>();
}
controller.gameObject.SetActive(true);
}

public static void HideMe()
{
if (controller != null)
{
controller.gameObject.SetActive(false);
}
}
}

使用MVC带来的改变

很显然,使用MVC的思路来编写UI脚本,数据管理,业务逻辑,用户界面这三块逻辑得到了分离
虽然脚本因此变的更多,但是面板交互的逻辑更加清晰了,各个类的职责也更加的清晰

MVC具体带来的改变在下一章具体讲解