左右箭头切换部位
UI元素绑定事件
先把UI元件定义好并拖拽。
//左箭头按钮
[SerializeField] Button leftArrowButton;
//右箭头按钮
[SerializeField] Button rightArrowButton;
UI窗口初始化时添加鼠标响应事件。
leftArrowButton.onClick.AddListener(LeftArrowButtonClick);
rightArrowButton.onClick.AddListener(RightArrowButtonClick);
切换逻辑
两种方向切换部位,底层逻辑有共同之处,单独包一个方法减少代码重复。
private void RightArrowButtonClick()
{
ArrowButtonSelect(false);
}
private void LeftArrowButtonClick()
{
ArrowButtonSelect(true);
}
先做数据准备,把可能用到的数据全部获取到,当前的职业类型和部位类型从下级UI组件拿到。
由于切换部位要受到projectConfig的限制(规定了那些部位类型可以在自定义角色窗口中使用),所以实际上并不是简单的直接由部位类型和实际索引currID找到配置文件进行部位切换,而是先在ProjectConfig中的CustomCharacterPartConfigIDDic找到可用的索引(currID),再根据部位类型找到配置文件进行索引切换,所以要获取当前是在ProjectConfig中某个部位下的第几个可以用的配置,currID实际用不着(切换的指针由characterConfigIndexDic代理了)。
//ArrowButtonSelect(bool isLeft)方法
//当前的职业类型
ProfessionType professionType = currentProfessionButton.ProfessionType;
//当前的部位类型
CharacterParType currPartType = currentFacadeMenu_Tab.CharacterParType;
//当前索引-在ProjectConfig中第几个配置
int currIndex = characterConfigIndexDic[(int)currPartType];
//当前的索引-实际配置的ID 过时的,用不着
int currID = customCharacterData.CustomPartDataDic[(int)currPartType].Index;
定义characterConfigIndexDic用于记录在CustomCharacterPartConfigIDDic中遍历的过程中的当前位置(指针),可以结合图理解,并初始化每个部位从第一个元素开始遍历(第一个元素得是每种部位的默认配置,否则默认配置再切不出来并且第一轮顺序也不对),使用字典的原因是有多种CharacterType,要和Key一一对应。
//玩家当前每一个部位选择的是在Project的第几个配置
private Dictionary<int, int> characterConfigIndexDic;
public override void Init()
{
//获取配置
projectConfig = ConfigManager.Instance.GetConfig<ProjectConfig>(ConfigTool.ProjectConfigName);
characterConfigIndexDic = new Dictionary<int,int>(3);
characterConfigIndexDic.Add((int)CharacterParType.Face,0);
characterConfigIndexDic.Add((int)CharacterParType.Hair, 0);
characterConfigIndexDic.Add((int)CharacterParType.Cloth, 0);
........
}
如图,当前这种情况实际切换Face的部位时是在配置1-5之间切换的,对应指针就是0-4,由于记录了当前位置,即使不连贯比如约束只能在1,3,5之间切换,此时对应指针是0~2,配置文件的不连续不会影响切换,实际的索引只是指针对应的值。
指针移动并处理边界进行循环。
if (isLeft) currIndex -= 1;
else currIndex += 1;
//到达边界
if (currIndex < 0) currIndex = projectConfig.CustomCharacterPartConfigIDDic[currPartType].Count - 1;
else if (currIndex > projectConfig.CustomCharacterPartConfigIDDic[currPartType].Count - 1) currIndex = 0;
某些部位不支持特定职业(轻甲不能给坦克穿),所以指针移动实际切换补位之前要检查是否支持职业,获取某个部位某类型的professionType(支持的职业类型)是否包含当前职业类型即可,不包含自动跳下一个。
//检查职业有效性(先找部位,再找职业)
//通过currIndex知道当前是ProjectConfig中某个部位的第几个可用配置,根据这个位置从ProjectConfig取出实际的配置ID
while (!ConfigTool.GetCharacterPartConfig(currPartType, projectConfig.CustomCharacterPartConfigIDDic[currPartType][currIndex]).ProfessionTypes.Contains(professionType))
{
if (isLeft) currIndex -= 1;
else currIndex += 1;
//到达边界
if (currIndex < 0) currIndex = projectConfig.CustomCharacterPartConfigIDDic[currPartType].Count - 1;
else if (currIndex > projectConfig.CustomCharacterPartConfigIDDic[currPartType].Count - 1) currIndex = 0;
}
对判断逻辑进行单独的说明,最终目的是要判断切换的部位类型是否支持当前职业即XXX.ProfessionTypes.Contains(professionType),而部位的配置可以由ConfigTool获得,需要传部位类型和实际索引,currPartType之前已经由下层UI提供,实际的索引要从CustomCharacterPartConfigIDDic中获取(现在CustomCharacterPartData.Index存的是切换之前旧的数据,用不了),先根据CurrPartType获取某个部位的可用list,再根据记录的指针currIndex在list中即可拿到实际的索引。
ConfigTool.GetCharacterPartConfig(currPartType, projectConfig.CustomCharacterPartConfigIDDic[currPartType][currIndex]).ProfessionTypes.Contains(professionType)
//分解
XXX.ProfessionTypes.Contains(professionType)
XXX = ConfigTool.GetGetCharacterPartConfig(CharacterParType characterParType,int index)
index = list[currIndex]
list = projectConfig.CustomCharacterPartConfigIDDic[currPartType]
职业检查ok后记录更新之后的指针,并设置相应的部位,播放音效,当前配置类型的索引写回数据CustomPartDataDic[(int)currPartType].Index的逻辑交给SetPart方法做,这样初始化时的赋值也可以自动写回数据。
//到这里职业有效了
characterConfigIndexDic[(int)currPartType] = currIndex;
//数据放回CustomPartDataDic交给SetCharacterPart方法做
SetCharacterPart(currPartType, projectConfig.CustomCharacterPartConfigIDDic[currPartType][currIndex], true, true);
AudioManager.Instance.PlayOnShot(arrowClickAudioClip, Vector3.zero, 1);
最终效果(不同职业会有有些部位不能切换)。