【Unity实战】手戳一个自定义角色换装系统——2d3d通用(附项目源码)

news2024/11/20 16:35:37

文章目录

  • 每篇一句
  • 前言
  • 素材
  • 开始
    • 切换头型
    • 添加更改颜色
    • 随机控制头型和颜色
    • 新增眼睛
    • 同样的方法配置人物的其他部位
    • 设置相同颜色部位
    • 全部部位随机
    • 绘制UI并添加点击事件
    • 通过代码控制点击事件
    • 添加颜色修改的事件
    • 其他部位效果UI切换
    • 添加随机按钮
    • 保存角色变更数据
    • 跳转场景显示角色数据
  • 源码
  • 完结

每篇一句

你进步的速度,取决于你学习的速度,昨天的我,也跟今天的你一样。

前言

本文我们来手戳一个自定义角色换装系统,它包括基本的人物部位、颜色修改,并跨场景显示修改的人物信息,2d3d通用

最终效果
在这里插入图片描述

素材

链接:https://pan.baidu.com/s/1dubEMMBO-ZSm3gQWPkvmsA?pwd=5zi6
提取码:5zi6

开始

切换头型

新建PositionedSprite脚本,保存图片和位置位置

using UnityEngine;

[System.Serializable]
public class PositionedSprite
{
    public Sprite Sprite; // Sprite对象
    public Vector3 PositionModifier; // 位置修正器
}

新建CustomizableElement脚本,控制图片切换

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; // 更新位置
    }
}

挂载并配置参数
在这里插入图片描述

效果
在这里插入图片描述

添加更改颜色

[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]; // 更新颜色
}

配置
在这里插入图片描述
效果
在这里插入图片描述

随机控制头型和颜色

[ContextMenu(itemName: "随机化")]
public void Randomize()
{
    SpriteIndex = Random.Range(0, _spriteOptions.Count); // 随机选择一个Sprite索引
    ColorIndex = Random.Range(0, _colorOptions.Count); // 随机选择一个颜色索引
    UpdateSprite();
    UpdateColor();
}

效果
在这里插入图片描述

新增眼睛

同理,添加眼睛,并配置眼睛的位置
在这里插入图片描述
效果
在这里插入图片描述

同样的方法配置人物的其他部位

效果
在这里插入图片描述

设置相同颜色部位

可能我们不希望所有部位都真的随机变色,比如我希望角色的肤色颜色保持一致
在这里插入图片描述
修改代码

[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 代码

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并添加点击事件

效果

通过代码控制点击事件

一个个配置按钮事件太麻烦了,我们可以通过脚本来控制

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获取当前的颜色

public Color CurrentColor => _colorOptions.Count == 0 ? Color.white : _colorOptions[ColorIndex]; //获取当前的颜色

修改UI_CustomizationPicker,添加颜色切换事件

[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,定义随机按钮事件

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 脚本,定义不同部位类型

using UnityEngine;

[CreateAssetMenu]
public class CustomizationType : ScriptableObject
{
    
}

添加各个部位配置
在这里插入图片描述
新增CustomizationData脚本,定义各种数据

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

[SerializeField]
private CustomizationType _type;

public CustomizationData GetCustomizationData(){
    return new CustomizationData(_type, _spriteOptions[SpriteIndex], _spriteRenderer.color);
}

绑定对应数据
在这里插入图片描述

新增CustomizedCharacter,保存人物各个部位数据

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

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脚本,用来渲染角色各个部位的图片和颜色

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脚本,添加跳转场景方法

//跳转场景
SceneManager.LoadScene("Game");

效果
在这里插入图片描述

源码

https://gitcode.net/unity1/unity-customcharacters
在这里插入图片描述

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。点赞越多,更新越快哦!当然,如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,于是最近才开始自习unity。如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我可能也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1149567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机考研 | 2009年 | 计算机组成原理真题

【计算机组成原理2009年真题43题-10分】 某计算机的CPU主频为500MHz&#xff0c;CPI为5(即执行每条指令平均需5个时钟周期)。假定某外设的数据传输率为0.5MB/s&#xff0c;采用中断方式与主机进行数据传送&#xff0c;以32位为传输单位&#xff0c;对应的中断服务程序包含18条…

Spring MVC的常用注解(设置响应篇)

目录 1.返回静态页面 2.返回数据 3.返回HTML代码片段 4.返回json 5.设置状态码 6.设置Header &#xff08;1&#xff09;.设置 Content-Type &#xff08;2&#xff09;.设置其他Header 推荐先看前篇博客Spring MVC的常用注解&#xff08;接收请求数据篇&#xff09; 接收…

火山引擎 ByteHouse:只需 2 个方法,增强 ClickHouse 数据导入能力

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 作为企业数字化建设的必备要素&#xff0c;易用的数据引擎能帮助企业提升数据使用效率&#xff0c;更好提升数据应用价值&#xff0c;夯实数字化建设基础。 数据导…

基于SpringBoot+Vue实现前后端分离的旅游网站系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java前端、后台、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

【网络安全 --- 任意文件上传漏洞靶场闯关 6-15关】任意文件上传漏洞靶场闯关,让你更深入了解文件上传漏洞以及绕过方式方法,思路技巧

一&#xff0c;工具资源下载 百度网盘资源下载链接地址&#xff1a; 百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固&#xff0c;支持教育网加速&#xff0c;支持手机端。注册使用百度网盘即可享受免费存储空间https://pan…

【LeetCode刷题日志】88.合并两个有序数组

&#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;C/C领域新星创作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;LeetCode 刷题日志&#x1f91d;希望作者的文章能对你有所帮助&#xff0c;有不足的地方请在评论区留言指正&#xff0c;…

markMan(马克鳗)前端标注工具

马克鳗一款很好用的标注、测量工具&#xff0c;前端必备神器。当需求给我们的原型没有标注颜色&#xff0c;尺寸数据&#xff0c;我们就可以用马克鳗自己标出来。 1.进入官网进行下载 官网网址&#xff1a;http://www.getmarkman.com/ 功能演示&#xff1a; 打开markMan需要拖…

企业金蝶KIS软件服务器中了locked勒索病毒怎么办,勒索病毒解密

最近一段时间&#xff0c;网络上的locked勒索病毒又开始了新一波的攻击&#xff0c;给企业的正常生产生活带来了严重影响。经过最近一段时间云天数据恢复中心对locked勒索病毒的解密&#xff0c;为大家整理了以下有关locked勒索病毒的相关信息。近期locked勒索病毒主要攻击金蝶…

Xamarin.Forms更改AndroidManifest.xml导致错误:没有兼容的代码在线程上运行

想在APP中加一个打开摄像头的功能&#xff0c;按照该博主的方法&#xff1a;https://blog.csdn.net/zhenweied09/article/details/82287761 设置好后&#xff0c;再运行就出现上图的错误&#xff0c;于是查找原因&#xff0c;定位到是更改AndroidManifest.xml文件导致的&#…

用软件模拟IPC的RTSP流,对接烟火识别算法服务,做实时的烟火检测、人员入侵检测、抽烟检测等算法

最近在研发烟火识别的算法&#xff0c;想要检验算法集成到视频分析服务之后的效果&#xff0c;发现线上的摄像机很难发现火情&#xff0c;有的很长时间都不会有检测的结果&#xff0c;于是我就需要用已经被检验过的视频文件&#xff0c;模拟一路IPC的RTSP流&#xff0c;来测试烟…

Spring@Lazy是如何解决构造函数循环依赖问题

Spring实例化源码解析之循环依赖CircularReference这章的最后我们提了一个构造函数形成的循环依赖问题&#xff0c;本章就是讲解利用Lazy注解如何解决构造函数循环依赖和其原理。 准备工作 首先创建两个构造函数循环依赖的类&#xff0c;TestA和TestB&#xff0c;代码如下&am…

MFC 重绘Button按钮,使用png、jpg图片贴图

使用MFC实现Button按钮实现png和jpg贴图功能&#xff0c;底部有实现代码的工程链接&#xff0c;免费下载 此工程使用了第三方库GDI 实现文件如下&#xff1a; CGdiPlusBitmap.h GdipButton.cpp GdipButton.h MemDC.h 一、在启动cpp里面增加GDI初始化与释放 Gdiplus::Gdiplus…

“2024中国信息通信展览会”促进全球通信领域交流合作的重要桥梁

2024中国国际信息通信展览会&#xff08;PT展&#xff09; China International PT Expo 时间:2024年9月25-27日 地点:北京.国家会议中心 主办单位&#xff1a; 工业和信息化部 协办单位&#xff1a; 中国通信标准化协会 中国通信企业协会 中国电信 中国移动 中国联通…

【Java每日一题】——第四十三题:编程用多态实现打印机.。分为黑白打印机和彩色打印机,不同类型的打印机打印效果不同。(2023.10.30)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

[Unity][VR]透视开发系列4-解决只看得到Passthrough但看不到Unity对象的问题

【视频资源】 视频讲解地址请关注我的B站。 专栏后期会有一些不公开的高阶实战内容或是更细节的指导内容。 B站地址: https://www.bilibili.com/video/BV1Zg4y1w7fZ/ 我还有一些免费和收费课程在网易云课堂(大徐VR课堂): https://study.163.com/provider/480000002282025/…

你还在找什么赚钱的项目吗?真心话坦白局系统源码

它具有匿名信息的神秘感 但又会给你一点小提示 能让你有无限挖掘下去的好奇感 也能让你说出那些不敢说出口的话 敢来一场坦白局吗&#xff01; 坦白局这个功能类似于悄悄话&#xff0c;只不过是匿名的悄悄话。 有时候我们有些话是开不了口的&#xff0c;坦白局给了我们一个…

颠覆传统:跨境电商借助DTC模式掀起新浪潮

跨境电商领域正经历着一场前所未有的革命&#xff0c;直接到消费者&#xff08;Direct-to-Consumer&#xff0c;DTC&#xff09;模式崭露头角&#xff0c;成为这一领域的一股强大力量。 传统的跨境电商模式受到了挑战&#xff0c;DTC模式正重新定义着全球电商的规则和格局。本…

STM32单片机智能小车一PWM方式实现小车调速和转向

目录 1. 电机模块开发 2. 让小车动起来 3. 串口控制小车方向 4. 如何进行小车PWM调速 5. PWM方式实现小车转向 1. 电机模块开发 L9110s概述 接通VCC&#xff0c;GND 模块电源指示灯亮&#xff0c; 以下资料来源官方&#xff0c;具体根据实际调试 IA1输入高电平&#xff…

销售流程管理实践及工具-Leangoo免费看板工具

销售管理既可以提高企业的销售业绩&#xff0c;又可以跟客户建立良好的关系。所以企业实施销售管理是非常有必要的。Leangoo免费看板不仅可以管理任务&#xff0c;它也可以成为一个绝佳的销售管理工具&#xff0c;帮助销售理清思路&#xff0c;达成目标。 首先在Leangoo中创建…

如何用加密狗保护工业软件核心技术?

工业软件的抄袭风险 1.1 反编译直窥软件的核心 工业软件代表着技术进步和创新&#xff0c;其中蕴含的算法、数据处理流程和功能模块往往是企业的核心竞争力。但随着技术的发展&#xff0c;反编译工具变得越来越先进&#xff0c;让不法分子可以“解剖”软件&#xff0c;看到它的…