UI事件响应
脸的尺寸和高度
设置脸的尺寸高度并应用到角色模型上。
sizeSlider.onValueChanged.AddListener(OnSizeSliderValueChanged);
heightSlider.onValueChanged.AddListener(OnHeightSliderValueChanged);
添加两个Slider的事件监听。
private void OnHeightSliderValueChanged(float height)
{
customCharacterData.CustomPartDataDic[(int)currentFacadeMenu_Tab.CharacterParType].Height = height;
CharacterCreator.Instance.SetHeight(currentFacadeMenu_Tab.CharacterParType, height);
}
private void OnSizeSliderValueChanged(float size)
{
customCharacterData.CustomPartDataDic[(int)currentFacadeMenu_Tab.CharacterParType].Size = size;
CharacterCreator.Instance.SetSize(currentFacadeMenu_Tab.CharacterParType, size);
}
先把数据存回customCharacterData,再调用玩家模型的Controller(CharacterCreator)去更改,进一步调用玩家模型的View(Player_View)完成实际的模型修改。
//CharacterCreator类
public void SetSize(CharacterParType characterParType,float size)
{
player_View.SetSize(characterParType,size);
}
public void SetHeight(CharacterParType characterParType, float height)
{
player_View.SetHeight(characterParType,height);
}
//Player_View类
/// <summary>
/// 设置某个部位的尺寸
/// </summary>
public void SetSize(CharacterParType characterParType, float size)
{
if (characterParType == CharacterParType.Face)
{
neckRootTransform.localScale = Vector3.one * size;
}
}
/// <summary>
/// 设置某个部位的高度
/// </summary>
public void SetHeight(CharacterParType characterParType, float height)
{
if (characterParType == CharacterParType.Face)
{
neckRootTransform.localPosition = new Vector3(-height,0,0);
}
}
这里传参数的时候额外传了一个职业类型,事实上只有脸部有高度和大小的调整逻辑,这里为了方便以后拓展保留了其他部位调整高度,大小的可能。
neckRoot是玩家头部的根节点。
if (UpdateUIView)
{
partNameText.text = partConfig.Name;
switch (parType)
{
case CharacterParType.Face:
//高度
//先设置值后设置范围
heightSlider.transform.parent.gameObject.SetActive(true);
heightSlider.value = customCharacterData.CustomPartDataDic[(int)CharacterParType.Face].Height;
heightSlider.minValue = 0;
heightSlider.maxValue = 0.1f;
//尺寸
sizeSlider.transform.parent.gameObject.SetActive(true);
sizeSlider.value = customCharacterData.CustomPartDataDic[(int)CharacterParType.Face].Size;
sizeSlider.minValue = 0.9f;
sizeSlider.maxValue = 1.1f;
在UI_窗口中完成Slider值的初始化,注意要先设置默认值再设置范围,设置范围本身会触发Slider的OnvalueChange方法更改customCharacterData里面的值。
最终结果。
设置颜色
先将颜色选择器添加到AAGroup中。
color1Button.onClick.AddListener(color1ButtonClick);
color2Button.onClick.AddListener(color2ButtonClick);
添加按钮事件监听。
private void color1ButtonClick()
{
//显示颜色选择器窗口
UIManager.Instance.Show<UI_ColorSelectorWindow>().Init(onColor1Selected, color1Button.image.color);
}
private void color2ButtonClick()
{
//显示颜色选择器窗口
UIManager.Instance.Show<UI_ColorSelectorWindow>().Init(onColor2Selected, color2Button.image.color);
}
按钮触发主色辅色修改的对应事件,先把调色盘显示出来,并把回调事件传进去,在调色盘更改完颜色会自动执行回调事件。
private void onColor1Selected(Color newColor)
{
//修改数据
GetCharacterPartData().Color1 = newColor;
//传给角色那边修改颜色
CharacterCreator.Instance.SetColor1(GetCurrentCharacterPartConfig(), newColor);
}
private void onColor2Selected(Color newColor)
{
//修改数据
GetCharacterPartData().Color2 = newColor;
//传给角色那边修改颜色
CharacterCreator.Instance.SetColor2(GetCurrentCharacterPartConfig(), newColor);
}
回调事件根据调色盘选取的颜色值,首先修改数据,再传给角色进行模型的颜色修改。
/// <summary>
/// 获取角色部位数据
/// </summary>
/// <returns></returns>
private CustomCharacterPartData GetCharacterPartData()
{
//确定当前是什么部位
CharacterParType currPartType = currentFacadeMenu_Tab.CharacterParType;
//数据层面部位数据
CustomCharacterPartData partData = customCharacterData.CustomPartDataDic[(int)currPartType];
return partData;
}
封装了根据当前部位类型获得对部位数据的逻辑。
/// <summary>
/// 拿到ProjectConfig中Index对应的部位配置
/// </summary>
private CharacterPartConfigBase GetCurrentCharacterPartConfig()
{
CharacterParType currPartType = currentFacadeMenu_Tab.CharacterParType;
int currIndex = characterConfigIndexDic[(int)currPartType];
int currID = projectConfig.CustomCharacterPartConfigIDDic[currPartType][currIndex];
CharacterPartConfigBase partConfig = ConfigTool.GetCharacterPartConfig(currPartType, currID);
return partConfig;
}
想让角色模型对应修改颜色,需要具体告诉其修改的ColorIndex(即使是同一个部位比如Cloth,不同的Cloth类型有不同的Mesh网格,修改主色/辅色时对应的ColorIndex也可能不同,要根据ColorIndex修改材质球),而ColorIndex包含在每个部位具体的一种配置中,所以需要把具体的配置(hairConfig_1)传给模型那边,逻辑与上节从ProjectConfig一步步获取相同,封装一层。
public void SetColor1(CharacterPartConfigBase partConfig, Color color)
{
player_View.SetColor1(partConfig, color);
}
public void SetColor2(CharacterPartConfigBase partConfig, Color color)
{
player_View.SetColor2(partConfig, color);
}
模型的Controller(CharacterCreator)做中转传给模型的View(Player_View)做实际逻辑。
/// <summary>
/// 设置颜色1
/// </summary>
public void SetColor1(CharacterPartConfigBase partConfig,Color color)
{
CharacterParType characterParType = partConfig.CharacterParType;
//根据不同的部位类型,确定具体要改主色时,材质球中对应修改哪个颜色
switch (characterParType)
{
case CharacterParType.Hair:
HairConfig hairConfig = partConfig as HairConfig;
partSkinnedMeshRenderers[1].sharedMaterial.SetColor("_Color0" + (hairConfig.ColorIndex + 1), color);
break;
case CharacterParType.Cloth:
ClothConfig clothConfig = partConfig as ClothConfig;
partSkinnedMeshRenderers[2].sharedMaterial.SetColor("_Color0" + (clothConfig.ColorIndex + 1), color);
break;
}
}
/// <summary>
/// 设置颜色2
/// </summary>
public void SetColor2(CharacterPartConfigBase partConfig, Color color)
{
CharacterParType characterParType = partConfig.CharacterParType;
//根据不同的部位类型,确定具体要改主色时,材质球中对应修改哪个颜色
switch (characterParType)
{
case CharacterParType.Cloth:
ClothConfig clothConfig = partConfig as ClothConfig;
partSkinnedMeshRenderers[2].sharedMaterial.SetColor("_Color0" + (clothConfig.ColorIndex2 + 1), color);
break;
}
}
Player_View从配置中拿到ColorIndex对应修改材质球即可,需要注意,不同部位有的只能修改一种颜色类型,这个逻辑是通过Switch case来手动指定的,Config中并不标记这种区别(没必要)。
最终结果。
同步颜色
同步按钮颜色
有两个地方需要同步,首先是同一个部位底下设置颜色的时候要把模型的颜色给UI。
//玩家确定了第一个颜色按钮的值
private void onColor1Selected(Color newColor)
{
//修改数据
GetCharacterPartData().Color1 = newColor;
//传给角色那边修改颜色
CharacterCreator.Instance.SetColor1(GetCurrentCharacterPartConfig(), newColor);
//修改颜色按钮的颜色值
color1Button.image.color = new Color(newColor.r ,newColor.g, newColor.b,0.6f);
}
仅仅这样做是不够的,只有在设置颜色时才会刷新按钮颜色,但在切换部位的过程中,不同部位的主色,辅色应该是不同的,也需要刷新,所以在切换部位确定要不要显示主辅色按钮时从数据中读取当前部位的颜色赋给按钮。
case CharacterParType.Hair:
heightSlider.transform.parent.gameObject.SetActive(false);
sizeSlider.transform.parent.gameObject.SetActive(false);
color2Button.gameObject.SetActive(false);
//根据配置的有效性来决定是否隐藏颜色
if ((partConfig as HairConfig).ColorIndex != -1)
{
color1Button.gameObject.SetActive(true);
//让颜色按钮的图片和当前配置一样
Color color = customCharacterData.CustomPartDataDic[(int)CharacterParType.Hair].Color1;
color1Button.image.color = new Color(color.r, color.g, color.b, 0.6f);
}
else
color1Button.gameObject.SetActive(false);
break;
切换同一部位下的不同类型串色问题
设置了一种头发颜色后,切换到其他头发颜色没变(除了不让改颜色的头发默认为白色)。
出现这种问题的原因是不同类型的头发主色修改时对应的ColorIndex不同,如果不同mesh网格改色和材质的Color一一对应,不需要这个操作。
因此在每次切换类型时,都要对模型重新应用一次颜色(也可以更新一个类型时把材质上其他类型对应的ColorIndex颜色也改成同样的颜色,但逻辑比较复杂)。
//更新模型
if(updateCharacterView)
{
//让角色修改模型
CharacterCreator.Instance.SetPart(partConfig);
//让角色重新应用一次颜色
switch (parType)
{
case CharacterParType.Hair:
CharacterCreator.Instance.SetColor1(partConfig,customCharacterData.CustomPartDataDic[(int)parType].Color1);
break;
case CharacterParType.Cloth:
CharacterCreator.Instance.SetColor1(partConfig, customCharacterData.CustomPartDataDic[(int)parType].Color1);
CharacterCreator.Instance.SetColor2(partConfig, customCharacterData.CustomPartDataDic[(int)parType].Color2);
break;
}
}
最终效果。