任务奖励界面

任务奖励界面

在这个界面中,任务的名称和任务的奖励信息都是通过配置直接读取就可以,而任务的ID以及进度信息和是否领取就需要配置服务器通信了

任务奖励配置

配置表

客户端和服务端的配置类都是继承BaseData

客户端配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TaskRewardCfg : BaseData<TaskRewardCfg>
{
public string taskName;
public int count;
public int exp;
public int coin;

}
public class TaskRewardData:BaseData<TaskRewardData>
{
public int prgs;
public bool taked;
}

这里的TaskRewardData类并不是配置类,而是用来让客户端读取服务端发送过来的任务进度的类

服务端配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TaskRewardCfg : BaseData<TaskRewardCfg>
{
//服务端不需要读取任务的名字,只留任务的ID就可以
public int count;
public int exp;
public int coin;

}
public class TaskRewardData:BaseData<TaskRewardData>
{
public int prgs;
public bool taked;
}

服务端的TaskRewardData与客户端相反,是用来让服务端读取客户端发送过来的任务进度

服务端保存进度的PlayerData

PlayerData使用一个string[]来保存任务进度

1
public string[] taskArr;

数据库中存储一个长字符串来保存任务进度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#region TaskArr
//数据示意:1|0|0#2|0|0#3|0|0#4|0|0#,第一个数是ID,第二个数是进度,第三个数是是否领取
string[] taskAwardStrArr = mySqlDataReader.GetString("task").Split('#');
string[] _taskArr = new string[6];
for (int i = 0; i < taskAwardStrArr.Length; i++)
{
if (taskAwardStrArr[i] == "") continue;//最后一个#号会被分割为空字符串
else if (taskAwardStrArr[i].Length >= 5)//数据安全性的校验,每个“1|0|0”的字符串长度不小于5
{
_taskArr[i] = taskAwardStrArr[i];
}
else
{
throw new Exception("DataErr");
}
}
playerData.taskArr = _taskArr;
#endregion

后面的的数据库操作参考强化配置的写法即可。

客户端UI界面技巧

客户端的任务UI需要动态加载,先制成相应的UIPrefab,然后再动态加载到Scroll View的Contents里面

TaskWnd动态加载部分代码RefreshUI

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
private void RefreshUI()
{
trdList.Clear();
List<TaskRewardData> todoList = new List<TaskRewardData>();
List<TaskRewardData> doneList = new List<TaskRewardData>();
string[] taskArr = playerData.taskArr;
for (int i = 0; i < taskArr.Length; i++)
{
if (taskArr[i] == "") continue;
string[] taskInfo = taskArr[i].Split('|');
TaskRewardData taskReward = new TaskRewardData();
taskReward.ID = int.Parse(taskInfo[0]);
taskReward.prgs = int.Parse(taskInfo[1]);
taskReward.taked = taskInfo[2].Equals("1");
if (taskReward.taked)
{
doneList.Add(taskReward);
}
else
{
todoList.Add(taskReward);
}

}
trdList.AddRange(todoList);//先把未完成的Task放在总列表里
trdList.AddRange(doneList);//再把已完成的Task放在总列表后面
for (int i = 0; i < content.childCount; i++)
{
Destroy(content.GetChild(i).gameObject);
}
for (int i = 0; i < trdList.Count; i++)
{
GameObject itemTaskUI = resSvc.LoadPrefab(PathDefine.TaskItemPrefab, true);
itemTaskUI.transform.SetParent(content);
itemTaskUI.transform.localPosition = Vector3.zero;
itemTaskUI.transform.localScale = Vector3.one;
itemTaskUI.name = "taskItem_" + i;

TaskRewardData trd = trdList[i];
TaskRewardCfg trf = resSvc.GetTaskRewardCfg(trd.ID);

SetText(GetTrans("txtName", itemTaskUI),trf.taskName);
SetText(GetTrans("txtPrg", itemTaskUI), trd.prgs + "/" + trf.count);
SetText(GetTrans("txtExp", itemTaskUI), "奖励:<sprite=\"itemexp\" index=0>经验" + trf.exp);
SetText(GetTrans("txtCoin", itemTaskUI), "<sprite=\"coin\" index=0>金币" + trf.coin);
Image imgPrg = GetTrans("prgBar/prgVal", itemTaskUI).GetComponent<Image>();
float prgVal = trd.prgs * 1.0f / trf.count;
imgPrg.fillAmount = prgVal;

Button btnTake = GetTrans("btnTake",itemTaskUI).GetComponent<Button>();
btnTake.onClick.AddListener(() =>
{
ClickTakeBtn(itemTaskUI.name);
});

Transform transComp = GetTrans("imgComp", itemTaskUI);
if (trd.taked)
{
btnTake.interactable = false;
SetActive(transComp);
}
else
{
SetActive(transComp, false);
if(trd.prgs == trf.count) btnTake.interactable = true;
else btnTake.interactable = false;
}
}
}

TaskReward网络通信协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#region 任务奖励相关
[System.Serializable]
public class ReqTakeTaskReward
{
public int id;
}
[System.Serializable]
public class RspTaskReward
{
public int cion;
public int lv;//涉及到exp奖励,就需要计算等级
public int exp;
public string[] taskArr;//更新进度完成信息
}
#endregion

服务端TaskSys逻辑

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

public class TaskSys : SingletonPattern<TaskSys>
{
private CacheSvc _cacheSvc;
private CfgSvc _cfgSvc;
public void Init()
{
_cacheSvc = CacheSvc.Instance;
_cfgSvc = CfgSvc.Instance;
PECommon.Log("TaskSys Init Done");
}
public void ReqTakeTaskReward(MsgPack msgPack)
{
ReqTakeTaskReward reqData = msgPack.msg.reqTakeTaskReward;

GameMsg msg = new GameMsg()
{
cmd = (int)CMD.RspTaskReward
};

PlayerData pd = _cacheSvc.GetPalyerDataBySession(msgPack.session);
TaskRewardCfg trc = _cfgSvc.GetTaskRewardCfg(reqData.id);
TaskRewardData trd = CalcTaskRewardData(pd,reqData.id);

if (trd.prgs == trc.count && !trd.taked)//校验数据
{
pd.coin += trc.coin;
PECommon.CalcExp(pd,trc.exp);//将之前在GuideSys的CalcExp方法转移到PECommon之中
trd.taked = true;

CalcTaskArr(pd, trd);

if (!_cacheSvc.UpdatePlayerData(pd.id, pd))
{
msg.err = (int)ErrorCode.UpdateDBError;
}
else
{
msg.rspTaskReward = new RspTaskReward
{
cion = pd.coin,
lv = pd.lv,
exp = pd.exp,
taskArr = pd.taskArr,
};
}
}
else
{
msg.err = (int)ErrorCode.ClientDataError;//新增客户端错误码
}
msgPack.session.SendMsg(msg);
}

//从Player的taskArr里找出当前id对应的Task字符串,并转化为TaskRewardData
public TaskRewardData CalcTaskRewardData(PlayerData pd,int id)
{
TaskRewardData trd = null;
for (int i = 0; i < pd.taskArr.Length; i++)
{
string[] taskInfo = pd.taskArr[i].Split('|');
var rid = int.Parse(taskInfo[0]);
if (rid == id)
{
trd = new TaskRewardData()
{
ID = rid,
prgs = int.Parse(taskInfo[1]),
taked = taskInfo[2].Equals("1"),
};
break;
}
}
return trd;
}
//将TaskRewardData转化为字符串并写回playerdata的taskarr中
public void CalcTaskArr(PlayerData pd, TaskRewardData trd)
{
string result = trd.ID + "|" + trd.prgs + "|" + (trd.taked ? 1 : 0);
int index = -1;
for (int i = 0; i < pd.taskArr.Length; i++)
{
string[] taskinfo = pd.taskArr[i].Split('|');
if (int.Parse(taskinfo[0]) == trd.ID)
{
index = i; break;
}
}
pd.taskArr[index] = result;
}
}