【Unity实战】手戳一个自定义角色换装系统——2d3d通用

news2024/9/23 5:23:46

文章目录

  • 每篇一句
  • 前言
  • 素材
  • 开始
    • 切换头型
    • 添加更改颜色
    • 随机控制头型和颜色
    • 新增眼睛
    • 同样的方法配置人物的其他部位
    • 设置相同颜色部位
    • 全部部位随机
    • 绘制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://xiangyu.blog.csdn.net

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

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

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

相关文章

Linux之J2EE的项目部署及发布

目录 前言 一、会议OA单体项目windows系统部署 1.检验工作 1. 检验jar项目包是否可以运行 2. 验证数据库脚本是否有误 3. 测试项目功能 2. 部署工作 2.1 传输文件 2.2 解压项目及将项目配置到服务器中 2.3 配置数据库 2.4 在服务器bin文件下点击startup.bat启动项目 …

Python----break关键字对while...else结构的影响

案例&#xff1a; 女朋友生气&#xff0c;要求道歉5遍&#xff1a;老婆大人&#xff0c;我错了。道歉到第三遍的时候&#xff0c;媳妇埋怨这一遍说的不真诚&#xff0c;是不是就是要退出循环了&#xff1f;这个退出有两种可能性&#xff1a; ① 更生气&#xff0c;不打算原谅…

最优秀的完整的数字音频工作站水果音乐FL Studio21.1.1.3750中文解锁版

FL Studio21.1.1.3750中文解锁版简称 FL 21&#xff0c;全称 Fruity Loops Studio 21&#xff0c;因此国人习惯叫它"水果"。目前最新版本是FL Studio21.1.1.3750中文解锁版版本&#xff0c;它让你的计算机就像是全功能的录音室&#xff0c;大混音盘&#xff0c;非常先…

连续离散混合系统控制与仿真

简单二阶系统 先研究最简单的二阶积分器串联型系统 x ˙ 1 x 2 x ˙ 2 u \begin{aligned} & \dot x_1 x_2 \\ & \dot x_2 u \\ \end{aligned} ​x˙1​x2​x˙2​u​ 使用零阶保持法离散化&#xff08;见附录&#xff09;&#xff0c; A [ 0 1 0 0 ] , B [ 0 …

Leetcode.1465 切割后面积最大的蛋糕

题目链接 Leetcode.1465 切割后面积最大的蛋糕 rating : 1445 题目描述 矩形蛋糕的高度为 h h h 且宽度为 w w w&#xff0c;给你两个整数数组 h o r i z o n t a l C u t s horizontalCuts horizontalCuts 和 v e r t i c a l C u t s verticalCuts verticalCuts&#xf…

Leetcode—66.加一【简单】

2023每日刷题&#xff08;十一&#xff09; Leetcode—66.加一 实现代码1 /*** Note: The returned array must be malloced, assume caller calls free().*/ int* plusOne(int* digits, int digitsSize, int* returnSize){int num 0;int i 0;int arr[110] {0};// 进位标识…

Linux MMC子系统 - 2.eMMC 5.1总线协议浅析

By: Ailson Jack Date: 2023.10.27 个人博客&#xff1a;http://www.only2fire.com/ 本文在我博客的地址是&#xff1a;http://www.only2fire.com/archives/161.html&#xff0c;排版更好&#xff0c;便于学习&#xff0c;也可以去我博客逛逛&#xff0c;兴许有你想要的内容呢。…

Java提升技术,进阶为高级开发和架构师的路线

原文网址&#xff1a;Java提升技术&#xff0c;进阶为高级开发和架构师的路线-CSDN博客 简介 Java怎样提升技术&#xff1f;怎样进阶为高级开发和架构师&#xff1f;本文介绍靠谱的成长路线。 首先点明&#xff0c;只写业务代码是无法成长技术的。提升技术的两个方法是&…

“从部署到优化,打造高效会议管理系统“

目录 引言一、部署单机项目 - 会议OA1.1 硬件和软件环境准备1.2 检查项目1.3 系统部署1.后端部署 二、部署前后端分离项目 - SPA项目后端部署2.前端部署 总结 引言 在现代化办公环境中&#xff0c;会议是组织沟通、决策和合作的重要方式之一。为了提高会议的效率和质量&#x…

MySQL-DQL【数据查询语言】(图码结合)

目录 一.DQL的定义 二.DQL—语法 三.DQL—基础查询(SELECT.. FROM) &#x1f449;查询多个字段 &#x1f449;设置别名 &#x1f449;去除重复记录 准备工作(建表&#xff0c;添加数据&#xff09; &DQL----基本查询的案例 五.DQL—条件查询(WHERE) 5.1 语法: 5…

基于 C# 实现样式与数据分离的打印方案

对于八月份的印象&#xff0c;我发现大部分都留给了出差。而九月初出差回来&#xff0c;我便立马投入了新项目的研发工作。因此&#xff0c;无论是中秋节还是国庆节&#xff0c;在这一连串忙碌的日子里&#xff0c;无不充满着仓促的气息。王北洛说&#xff0c;“活着不就是仓促…

数字化转型系列主题:数据中台知识体系

当前&#xff0c;大部分企业不再建设从源数据采集到分析应用的烟囱式系统&#xff0c;更倾向于数据集中采集、存储&#xff0c;并应用分层建设。这种方式一方面有利于应用系统的快速部署&#xff0c;另一方面也保证了数据的集中管理与运营&#xff0c;体现数据的资产、资源属性…

主动调度是如何发生的

计算机主要处理计算、网络、存储三个方面。计算主要是 CPU 和内存的合作&#xff1b;网络和存储则多是和外部设备的合作&#xff1b;在操作外部设备的时候&#xff0c;往往需要让出 CPU&#xff0c;就像上面两段代码一样&#xff0c;选择调用 schedule() 函数。 上下文切换主要…

初识《时间复杂度和空间复杂度》

目录 前言&#xff1a; 关于数据结构与算法 1.什么是数据结构&#xff1f; 2.什么是算法&#xff1f; 3.数据结构和算法的重要性 算法效率是什么&#xff1f; 1.怎样衡量一个算法的好坏呢&#xff1f; 2.算法的复杂度是个什么&#xff1f; 时间复杂度 1.时间复杂度的概…

Android Glide限定onlyRetrieveFromCache取内存缓存submit超时阻塞方式,Kotlin

Android Glide限定onlyRetrieveFromCache取内存缓存submit超时阻塞方式,Kotlin import android.os.Bundle import android.util.Log import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import com.b…

RK3568-pcie接口

pcie接口与sata接口 pcie总线pcie总线pcie控制器sata控制器nvme设备sata设备nvme协议ahci协议m-key接口b-key接口RC模式和EP模式 RC和EP分别对应主模式和从模式,普通的PCI RC主模式可以用于连接PCI-E以太网芯片或PCI-E的硬盘等外设。 RC模式使用外设一般都有LINUX驱动程序,安…

LLM系列 | 22 : Code Llama实战(下篇):本地部署、量化及GPT-4对比

引言 模型简介 依赖安装 模型inference 代码补全 4-bit版模型 代码填充 指令编码 Code Llama vs ChatGPT vs GPT4 小结 引言 青山隐隐水迢迢&#xff0c;秋尽江南草未凋。 小伙伴们好&#xff0c;我是《小窗幽记机器学习》的小编&#xff1a;卖热干面的小女孩。紧接…

36基于matlab的对分解层数和惩罚因子进行优化

基于matlab的对分解层数和惩罚因子进行优化。蚁狮优化算法优化VMD,算术优化算法优化VMD&#xff0c;遗传优化算法优化VMD&#xff0c;灰狼优化算法优化VMD&#xff0c;海洋捕食者优化算法优化VMD&#xff0c;粒子群优化VMD&#xff0c;麻雀优化算法优化VMD&#xff0c;鲸鱼优化…

如何使用 nvm-windows 这个工具来管理你电脑上的Node.js版本

nvm-windows 是一个用于管理在 Windows 上安装的多个 Node.js 版本的工具。以下是安装和使用 nvm-windows 的步骤&#xff1a; 第1步&#xff1a;下载 nvm-windows 访问 nvm-windows 的 GitHub发布页面.下载最新版本的 nvm-setup.zip 文件。 第2步&#xff1a;安装 nvm-wind…

KV STUDIO的安装与实践(一)

目录 什么是KV STUDIO&#xff1f; 如何安装KV STUDIO&#xff1f; 如何学习与使用KV STUDIO&#xff08;在现实中的应用&#xff09;&#xff1f; 应用一&#xff08;在现实生活中机器内部plc的读取与替换&#xff09; 读取 KV STUDIO实现显示器的检测&#xff01;&#…