文章目录
每篇一句
你进步的速度,取决于你学习的速度,昨天的我,也跟今天的你一样。
前言
本文我们来手戳一个自定义角色换装系统,它包括基本的人物部位、颜色修改,并跨场景显示修改的人物信息,2d3d通用
最终效果
素材
链接:https://pan.baidu.com/s/1dubEMMBO-ZSm3gQWPkvmsA?pwd=5zi6
提取码:5zi6
开始
切换头型
新建PositionedSprite脚本,保存图片和位置位置
csharp
using UnityEngine;
[System.Serializable]
public class PositionedSprite
{
public Sprite Sprite; // Sprite对象
public Vector3 PositionModifier; // 位置修正器
}
新建CustomizableElement脚本,控制图片切换
csharp
using System.Collections.Generic;
using UnityEngine;
public class CustomizableElement : MonoBehaviour
{
[SerializeField]
private SpriteRenderer _spriteRenderer; // Sprite渲染器
[SerializeField]
private List<PositionedSprite> _spriteOptions; // 可选的Sprite列表
[SerializeField]
private List<Color> _colorOptions; // 可选的颜色列表
[field: SerializeField]
public int ColorIndex { get; set; } // 颜色索引
[field: SerializeField]
public int SpriteIndex { get; private set; } // Sprite索引
[ContextMenu(itemName: "下一个图片")]
public PositionedSprite NextSprite()
{
SpriteIndex = Mathf.Min(SpriteIndex + 1, _spriteOptions.Count - 1); // 切换到下一个Sprite
UpdateSprite();
return _spriteOptions[SpriteIndex];
}
[ContextMenu(itemName: "上一个图片")]
public PositionedSprite PreviousSprite()
{
SpriteIndex = Mathf.Max(SpriteIndex - 1, 0); // 切换到上一个Sprite
UpdateSprite();
return _spriteOptions[SpriteIndex];
}
private void UpdateSprite()
{
if(_spriteOptions.Count == 0) return;
SpriteIndex = Mathf.Clamp(SpriteIndex, 0, _spriteOptions.Count - 1); // 限制Sprite索引在合法范围内
var positionedSprite = _spriteOptions[SpriteIndex];
_spriteRenderer.sprite = positionedSprite.Sprite; // 更新Sprite
transform.localPosition = positionedSprite.PositionModifier; // 更新位置
}
}
挂载并配置参数
效果
添加更改颜色
csharp
[ContextMenu(itemName: "下一个颜色")]
public Color NextColor()
{
ColorIndex = Mathf.Min(ColorIndex + 1, _colorOptions.Count - 1); // 切换到下一个颜色
UpdateColor();
return _colorOptions[ColorIndex];
}
[ContextMenu(itemName: "上一个颜色")]
public Color PreviousColor()
{
ColorIndex = Mathf.Max(ColorIndex - 1, 0); // 切换到上一个颜色
UpdateColor();
return _colorOptions[ColorIndex];
}
private void UpdateColor()
{
if(_colorOptions.Count == 0) return;
_spriteRenderer.color = _colorOptions[ColorIndex]; // 更新颜色
}
配置
效果
随机控制头型和颜色
csharp
[ContextMenu(itemName: "随机化")]
public void Randomize()
{
SpriteIndex = Random.Range(0, _spriteOptions.Count); // 随机选择一个Sprite索引
ColorIndex = Random.Range(0, _colorOptions.Count); // 随机选择一个颜色索引
UpdateSprite();
UpdateColor();
}
效果
新增眼睛
同理,添加眼睛,并配置眼睛的位置
效果
同样的方法配置人物的其他部位
效果
设置相同颜色部位
可能我们不希望所有部位都真的随机变色,比如我希望角色的肤色颜色保持一致
修改代码
csharp
[SerializeField]
private List<SpriteRenderer> _copyColorTo; // 需要拷贝颜色的SpriteRenderer列表
// ...
private void UpdateColor()
{
if(_colorOptions.Count == 0) return;
var newColor = _colorOptions[ColorIndex]; // 获取新的颜色
_spriteRenderer.color = newColor; // 更新当前SpriteRenderer的颜色
// 将颜色拷贝到其他SpriteRenderer
_copyColorTo.ForEach(sr => sr.color = newColor);
}
配置
当我们更新头颜色时,手会同步更新,保持头跟手颜色一样
效果
全部部位随机
新增CustomizationRandomizer 代码
csharp
using UnityEngine;
public class CustomizationRandomizer : MonoBehaviour
{
[ContextMenu(itemName: "随机全部")]
public void Randomize()
{
var elements = GetComponentsInChildren<CustomizableElement>(); // 获取所有CustomizableElement组件
foreach (var element in elements)
{
element.Randomize(); // 调用CustomizableElement的Randomize方法,随机化每个元素
}
}
}
挂载脚本,效果
绘制UI并添加点击事件
效果
通过代码控制点击事件
一个个配置按钮事件太麻烦了,我们可以通过脚本来控制
csharp
public class UI_CustomizationPicker : MonoBehaviour
{
[SerializeField]
private CustomizableElement _customizableElement; // 自定义元素对象
[SerializeField]
private Button _previousSpriteButton;
[SerializeField]
private Button _nextSpriteButton;
[SerializeField]
private TMP_Text _spriteId;
private void Start()
{
UpdateSpriteId();
// 为按钮添加点击事件
_previousSpriteButton.onClick.AddListener(() =>
{
_customizableElement.PreviousSprite(); // 切换到上一个Sprite
UpdateSpriteId(); // 更新Sprite的ID文本
});
_nextSpriteButton.onClick.AddListener(() =>
{
_customizableElement.NextSprite(); // 切换到下一个Sprite
UpdateSpriteId(); // 更新Sprite的ID文本
});
}
private void UpdateSpriteId()
{
// 更新Sprite的ID文本
_spriteId.SetText(_customizableElement.SpriteIndex.ToString().PadLeft(2, '0'));
}
}
配置参数
效果
添加颜色修改的事件
修改CustomizableElement获取当前的颜色
csharp
public Color CurrentColor => _colorOptions.Count == 0 ? Color.white : _colorOptions[ColorIndex]; //获取当前的颜色
修改UI_CustomizationPicker,添加颜色切换事件
csharp
[SerializeField]
private Button _previousColorButton;
[SerializeField]
private Button _nextColorButton;
[SerializeField]
private Image _colorIcon;
private void Start()
{
// 。。。
if(_colorIcon != null){
_previousColorButton.onClick.AddListener(() =>
{
_customizableElement.PreviousColor();
UpdateColorIcon();
});
_nextColorButton.onClick.AddListener(() =>
{
_customizableElement.NextColor();
UpdateColorIcon();
});
}
}
private void UpdateColorIcon()
{
_colorIcon.color = _customizableElement.CurrentColor;
}
效果
其他部位效果UI切换
跟前面一样配置各个部位的切换即可,配置其他部位最终效果
效果
添加随机按钮
新增脚本UI_CustomizationUI,定义随机按钮事件
csharp
public class UI_CustomizationUI : MonoBehaviour
{
private List<UI_CustomizationPicker> _pickers; // 自定义选择器列表
void Start()
{
_pickers = GetComponentsInChildren<UI_CustomizationPicker>().ToList(); // 获取所有自定义选择器组件并转换为列表
}
// 更新所有选择器的状态
public void UpdatePickersState()
{
_pickers.ForEach(picker =>
{
picker._customizableElement.Randomize();//随机修改
picker.UpdateSpriteId(); // 更新Sprite的ID文本
picker.UpdateColorIcon(); // 更新颜色图标
});
}
}
挂载脚本
效果
保存角色变更数据
新增CustomizationType 脚本,定义不同部位类型
csharp
using UnityEngine;
[CreateAssetMenu]
public class CustomizationType : ScriptableObject
{
}
添加各个部位配置
新增CustomizationData脚本,定义各种数据
csharp
using UnityEngine;
using System;
[Serializable]
public class CustomizationData
{
// 使用情况:指定自定义类型
[field:SerializeField]
public CustomizationType Type { get; private set; }
// 使用情况:指定带位置的精灵
[field:SerializeField]
public PositionedSprite Sprite { get; private set; }
// 使用情况:指定颜色
[field:SerializeField]
public Color Color { get; private set; }
// CustomizationData 类的构造函数
public CustomizationData(CustomizationType t, PositionedSprite s, Color c)
{
Type = t;
Sprite = s;
Color = c;
}
}
修改CustomizableElement
csharp
[SerializeField]
private CustomizationType _type;
public CustomizationData GetCustomizationData(){
return new CustomizationData(_type, _spriteOptions[SpriteIndex], _spriteRenderer.color);
}
绑定对应数据
新增CustomizedCharacter,保存人物各个部位数据
csharp
using UnityEngine;
using System.Collections.Generic;
[CreateAssetMenu]
public class CustomizedCharacter : ScriptableObject
{
// Usage: 包含所有自定义数据的列表
[field:SerializeField]
public List<CustomizationData> Data { get; private set; }
// 收集所有可定制元素的自定义数据
public void GatherCustomizationData()
{
// 查找场景中的所有可定制元素
var customizableElements = FindObjectsOfType<CustomizableElement>();
// 创建一个新的自定义数据列表
Data = new List<CustomizationData>();
// 遍历所有可定制元素并添加它们的自定义数据到列表中
foreach (var element in customizableElements)
{
Data.Add(element.GetCustomizationData());
}
}
}
新增人物配置
新增CustomizableCharacter
csharp
using UnityEngine;
public class CustomizableCharacter : MonoBehaviour
{
[SerializeField]
private CustomizedCharacter _character;
// Usage: 在编辑器中的上下文菜单中添加 "Randomize All" 选项
[ContextMenu(itemName: "Randomize All")]
// Usage: 随机化所有可定制元素的外观
public void Randomize()
{
// 获取所有子物体中的 CustomizableElement 组件数组
var elements = GetComponentsInChildren<CustomizableElement>();
// 遍历每个可定制元素,随机化其外观
foreach (var element in elements)
{
element.Randomize();
}
}
// Usage: 存储定制信息
public void StoreCustomizationInformation()
{
// 获取所有子物体中的 CustomizableElement 组件数组
var elements = GetComponentsInChildren<CustomizableElement>();
// 清空已有的定制数据
_character.Data.Clear();
// 遍历每个可定制元素,获取其定制数据并添加到角色的数据列表中
foreach (var element in elements)
{
_character.Data.Add(element.GetCustomizationData());
}
}
}
挂载脚本,配置数据
新增按钮用于跳转和保持角色数据
效果,数据被保存在了Player里
跳转场景显示角色数据
新增CustomizedCharacterElement脚本,用来渲染角色各个部位的图片和颜色
csharp
using UnityEngine;
using System.Linq;
public class CustomizedCharacterElement : MonoBehaviour
{
// Usage: 指定该元素的自定义类型
[field:SerializeField]
public CustomizationType Type { get; private set; }
// Usage: 指定所属的自定义角色
[SerializeField]
private CustomizedCharacter _character;
private SpriteRenderer _spriteRenderer;
// Start 方法在对象实例化时调用
private void Start()
{
// 获取 SpriteRenderer 组件
_spriteRenderer = GetComponent<SpriteRenderer>();
// 查找自定义角色中指定类型的自定义数据
var customization = _character.Data.FirstOrDefault(d => d.Type == Type);
// 如果找不到匹配的自定义数据,则返回
if (customization == null)
{
return;
}
// 应用自定义数据中的颜色和精灵到元素上
_spriteRenderer.color = customization.Color;
_spriteRenderer.sprite = customization.Sprite.Sprite;
// 应用自定义数据中的位置修正器到元素上
transform.localPosition = customization.Sprite.PositionModifier;
}
}
新建场景,挂载脚本,添加配置角色属性
修改CustomizableCharacter脚本,添加跳转场景方法
csharp
//跳转场景
SceneManager.LoadScene("Game");
效果
源码
为了防止大家变懒,源码就不提供了,大家直接可以照着文章思路进行学习
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。点赞越多,更新越快哦!当然,如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~