左右箭头切换部位

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,配置文件的不连续不会影响切换,实际的索引只是指针对应的值。

alt

指针移动并处理边界进行循环。

        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);

最终效果(不同职业会有有些部位不能切换)。

alt