unity开发游戏实现角色筛选预览

RenderTexture通俗解释

RenderTexture就像是Unity中的"虚拟相机胶片",它可以:

  1. 捕获3D内容:将3D场景或对象"拍照"记录下来
  1. 实时更新:不是静态图片,而是动态视频,角色可以动起来
  1. 用作纹理:可以显示在UI界面上

在角色预览系统中的作用

从你的截图和代码中可以看出:

  1. 分离渲染:CharacterPreviewRT(512×512分辨率)专门用来渲染角色模型
  1. 桥梁作用:连接了3D世界和2D界面
  • 3D世界:CharacterPreviewCamera(相机)拍摄放在CharacterPosition(位置)的角色模型
  • 2D界面:通过RawImage显示这个"拍摄"结果
  1. 性能优化:
  • 只渲染需要的角色,不渲染整个场景
  • 可以控制渲染质量(如你设置的2×抗锯齿)
  1. 交互实现:
  • 你的代码中的HandleCharacterRotation()方法让用户可以旋转预览角色

实现思路(我的界面结构参考)

 

创建一个显示的面板(CharacterInfoPanel),并且添加组件(重要)

界面参考布局

相机配置注意配置Culling Mask为对应的层级

 

代码参考:

using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using Game.Managers;namespace Game.UI
{/// <summary>/// 角色选择面板,处理角色浏览、选择和预览功能/// </summary>public class CharacterSelectPanel : BasePanel{[Header("角色列表")][SerializeField] private Transform characterListContainer; // 角色列表容器[SerializeField] private GameObject characterItemPrefab;   // 角色选项预制体[SerializeField] private ScrollRect characterScrollRect;   // 角色列表滚动视图[Header("角色预览")][SerializeField] private RawImage characterPreviewImage;   // 角色预览图像[SerializeField] private Transform characterPosition;      // 角色位置[Header("按钮")][SerializeField] private Button confirmButton;             // 确认按钮[Header("旋转设置")][SerializeField] private float rotationSpeed = 30f;        // 旋转速度// 角色数据private List<CharacterData> characterDataList = new List<CharacterData>();// 预览相关private GameObject currentPreviewCharacter;private bool isDragging = false;private float lastMouseX;private int selectedCharacterIndex = -1;private List<CharacterItemUI> characterItemUIs = new List<CharacterItemUI>();protected override void Initialize(){base.Initialize();Debug.Log("[CharacterSelectPanel] 初始化面板");// 验证组件引用if(characterPosition == null)Debug.LogError("[CharacterSelectPanel] characterPosition未设置,请将预览位置拖拽到Inspector面板");if(characterPreviewImage == null)Debug.LogError("[CharacterSelectPanel] characterPreviewImage未设置,请将RawImage拖拽到Inspector面板");if(characterItemPrefab == null)Debug.LogError("[CharacterSelectPanel] characterItemPrefab未设置,请将角色项预制体拖拽到Inspector面板");// 检查角色项预制体是否包含必要组件CharacterItemUI testItemUI = characterItemPrefab.GetComponent<CharacterItemUI>();if(testItemUI == null)Debug.LogError("[CharacterSelectPanel] 角色项预制体必须包含CharacterItemUI组件!请在预制体上添加此组件");// 初始化组件引用if (confirmButton != null){confirmButton.onClick.AddListener(OnConfirmButtonClicked);confirmButton.interactable = false; // 初始状态下禁用确认按钮}// 加载角色数据LoadCharacterData();// 初始化角色列表PopulateCharacterList();}protected override void SetupButtons(){base.SetupButtons();// 可以在这里添加其他按钮的监听器}void Update(){// 处理角色旋转HandleCharacterRotation();}/// <summary>/// 处理角色旋转/// </summary>private void HandleCharacterRotation(){if (characterPreviewImage == null || currentPreviewCharacter == null) return;// 检查预览图片上的鼠标事件if (RectTransformUtility.RectangleContainsScreenPoint(characterPreviewImage.rectTransform, Input.mousePosition)){// 鼠标按下开始拖动if (Input.GetMouseButtonDown(0)){isDragging = true;lastMouseX = Input.mousePosition.x;}}// 松开鼠标停止拖动if (Input.GetMouseButtonUp(0)){isDragging = false;}// 拖动时旋转角色if (isDragging && currentPreviewCharacter != null){float deltaX = Input.mousePosition.x - lastMouseX;currentPreviewCharacter.transform.Rotate(0, -deltaX * rotationSpeed * Time.deltaTime, 0);lastMouseX = Input.mousePosition.x;}}/// <summary>/// 加载角色数据/// </summary>private void LoadCharacterData(){Debug.Log("[CharacterSelectPanel] 加载角色数据");// 理想情况下,这些数据应该从DataManager或资源文件加载// 这里为演示创建一些测试数据characterDataList.Clear();// 简化测试数据,只包含必要信息characterDataList.Add(new CharacterData(0, "战士", "", "Characters/Warrior"));characterDataList.Add(new CharacterData(1, "忍者", "", "Characters/Ninja"));characterDataList.Add(new CharacterData(2, "魔法师", "", "Characters/Mage"));characterDataList.Add(new CharacterData(3, "武僧", "", "Characters/Monk"));Debug.Log($"[CharacterSelectPanel] 已加载{characterDataList.Count}个角色数据");}/// <summary>/// 填充角色列表/// </summary>private void PopulateCharacterList(){if (characterListContainer == null){Debug.LogError("[CharacterSelectPanel] characterListContainer未设置,无法填充角色列表");return;}if (characterItemPrefab == null){Debug.LogError("[CharacterSelectPanel] characterItemPrefab未设置,无法填充角色列表");return;}Debug.Log("[CharacterSelectPanel] 填充角色列表");// 清空现有列表和记录foreach (Transform child in characterListContainer){Destroy(child.gameObject);}characterItemUIs.Clear();// 为每个角色创建列表项for (int i = 0; i < characterDataList.Count; i++){CharacterData data = characterDataList[i];GameObject item = Instantiate(characterItemPrefab, characterListContainer);item.name = $"CharacterItem_{data.name}";// 配置角色项CharacterItemUI itemUI = item.GetComponent<CharacterItemUI>();if (itemUI != null){int index = i; // 创建局部变量以便在闭包中使用itemUI.Setup(data);itemUI.OnItemSelected += () => OnCharacterItemSelected(index);characterItemUIs.Add(itemUI);Debug.Log($"[CharacterSelectPanel] 创建角色列表项: {data.name}");}else{Debug.LogError($"[CharacterSelectPanel] 角色列表项预制体上没有CharacterItemUI组件!");}}}/// <summary>/// 角色项被选中/// </summary>private void OnCharacterItemSelected(int index){if (index < 0 || index >= characterDataList.Count) return;Debug.Log($"[CharacterSelectPanel] 选择角色: {characterDataList[index].name}");// 更新选中的角色索引selectedCharacterIndex = index;CharacterData data = characterDataList[index];// 更新角色项UI状态for (int i = 0; i < characterItemUIs.Count; i++){if (characterItemUIs[i] != null){characterItemUIs[i].SetSelected(i == index);}}// 加载角色预览LoadCharacterPreview(data.prefabPath);// 启用确认按钮if (confirmButton != null)confirmButton.interactable = true;}/// <summary>/// 加载角色预览/// </summary>private void LoadCharacterPreview(string prefabPath){Debug.Log($"[CharacterSelectPanel] 开始加载角色预览: {prefabPath}");if (characterPosition == null){Debug.LogError("[CharacterSelectPanel] characterPosition未设置,无法加载角色预览");return;}// 清除当前预览角色if (currentPreviewCharacter != null){Destroy(currentPreviewCharacter);currentPreviewCharacter = null;}// 加载角色预制体GameObject characterPrefab = Resources.Load<GameObject>(prefabPath);if (characterPrefab == null){Debug.LogError($"[CharacterSelectPanel] 无法加载角色预制体: {prefabPath},请检查路径是否正确并且确保预制体存在于Resources目录");return;}Debug.Log($"[CharacterSelectPanel] 成功加载角色预制体: {prefabPath}");// 实例化新角色currentPreviewCharacter = Instantiate(characterPrefab, characterPosition);// 设置层和位置int previewLayer = LayerMask.NameToLayer("CharacterPreview");if (previewLayer < 0){Debug.LogError("[CharacterSelectPanel] 未找到'CharacterPreview'层,请在项目设置中添加此层");previewLayer = 0; // 使用默认层}currentPreviewCharacter.layer = previewLayer;SetLayerRecursively(currentPreviewCharacter, previewLayer);// 重置位置和旋转currentPreviewCharacter.transform.localPosition = Vector3.zero;currentPreviewCharacter.transform.localRotation = Quaternion.identity;// 播放待机动画(如果有)Animator animator = currentPreviewCharacter.GetComponent<Animator>();if (animator != null){animator.Play("Idle");Debug.Log("[CharacterSelectPanel] 已播放Idle动画");}else{Debug.Log("[CharacterSelectPanel] 角色没有Animator组件,跳过动画播放");}Debug.Log($"[CharacterSelectPanel] 角色预览加载完成: {prefabPath}");}/// <summary>/// 递归设置物体及其子物体的层/// </summary>private void SetLayerRecursively(GameObject obj, int layer){obj.layer = layer;foreach (Transform child in obj.transform){SetLayerRecursively(child.gameObject, layer);}}/// <summary>/// 确认按钮点击事件/// </summary>private void OnConfirmButtonClicked(){if (selectedCharacterIndex < 0){Debug.LogWarning("请先选择一个角色");return;}// 保存选择的角色if (DataManager.Instance != null){DataManager.Instance.SetSelectedCharacter(selectedCharacterIndex);}Debug.Log($"确认选择角色: {characterDataList[selectedCharacterIndex].name}");// 隐藏角色选择面板Hide();// 进入战斗场景if (GameManager.Instance != null){GameManager.Instance.ChangeState(GameState.Battle);}}protected override void OnPanelShow(){base.OnPanelShow();Debug.Log("[CharacterSelectPanel] 显示面板");// 重置选择状态selectedCharacterIndex = -1;if (confirmButton != null)confirmButton.interactable = false;// 清除当前预览if (currentPreviewCharacter != null){Destroy(currentPreviewCharacter);currentPreviewCharacter = null;}}protected override void OnBackButtonClicked(){Debug.Log("[CharacterSelectPanel] 返回按钮点击");Hide();// 返回难度选择界面UIManager.Instance.ShowDifficultySelectPanel();}}/// <summary>/// 角色数据类/// </summary>[System.Serializable]public class CharacterData{public int id;public string name;public string description;public string prefabPath;public CharacterData(int id, string name, string description, string prefabPath){this.id = id;this.name = name;this.description = description;this.prefabPath = prefabPath;}}
} 

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

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

相关文章

Spring源码主线全链路拆解:从启动到关闭的完整生命周期

Spring源码主线全链路拆解&#xff1a;从启动到关闭的完整生命周期 一文看懂 Spring 框架从启动到销毁的主线流程&#xff0c;结合原理、源码路径与伪代码三位一体&#xff0c;系统学习 Spring 底层机制。 1. 启动入口与环境准备 原理说明 Spring Boot 应用入口是标准 Java 应…

SAP RF 移动屏幕定制

SAP RF 移动屏幕定制 ITSmobile 是 SAP 当前将移动设备连接到 SAP 系统的技术基础。它基于 SAP Internet Transaction Server (ITS)&#xff0c;从 Netweaver 2004 开始作为 Netweaver 平台的一部分提供。ITSmobile 提供了一个框架&#xff0c;用于为任何 SAP 事务生成基于 HT…

Spark,数据提取和保存

以下是使用 Spark 进行数据提取&#xff08;读取&#xff09;和保存&#xff08;写入&#xff09;的常见场景及代码示例&#xff08;基于 Scala/Java/Python&#xff0c;不含图片操作&#xff09;&#xff1a; 一、数据提取&#xff08;读取&#xff09; 1. 读取文件数据&a…

如何用mockito+junit测试代码

Mockito 是一个流行的 Java 模拟测试框架&#xff0c;用于创建和管理测试中的模拟对象(mock objects)。它可以帮助开发者编写干净、可维护的单元测试&#xff0c;特别是在需要隔离被测组件与其他依赖项时。 目录 核心概念 1. 模拟对象(Mock Objects) 2. 打桩(Stubbing) 3. 验…

最新缺陷检测模型:EPSC-YOLO(YOLOV9改进)

目录 引言:工业缺陷检测的挑战与突破 一、EPSC-YOLO整体架构解析 二、核心模块技术解析 1. EMA多尺度注意力模块:让模型"看得更全面" 2. PyConv金字塔卷积:多尺度特征提取利器 3. CISBA模块:通道-空间注意力再进化 4. Soft-NMS:更智能的重叠框处理 三、实…

【Linux网络与网络编程】12.NAT技术内网穿透代理服务

1. NAT技术 之前我们说到过 IPv4 协议中IP 地址数量不充足的问题可以使用 NAT 技术来解决。还提到过本地主机向公网中的一个服务器发起了一个网络请求&#xff0c;服务器是怎么将应答返回到该本地主机呢&#xff1f;&#xff08;如何进行内网转发&#xff1f;&#xff09; 这就…

uniapp的适配方式

文章目录 前言✅ 一、核心适配方式对比&#x1f4cf; 二、rpx 单位&#xff1a;uni-app 的核心适配机制&#x1f9f1; 三、默认设计稿适配&#xff08;750宽&#xff09;&#x1f501; 四、字体 & 屏幕密度适配&#x1f6e0; 五、特殊平台适配&#xff08;底部安全区、刘海…

JAVA EE(进阶)_进阶的开端

别放弃浸透泪水的昨天&#xff0c;晨光已为明天掀开新篇 ——陳長生. ❀主页&#xff1a;陳長生.-CSDN博客❀ &#x1f4d5;上一篇&#xff1a;JAVA EE_HTTP-CSDN博客 1.什么是Java EE Java EE&#xff08;Java Pla…

SQL脚本规范

主要作用&#xff1a;数据库的备份和迁移 SQL脚本规范 每一个sql语句必须与;结束 脚本结构&#xff1a; { 删库&#xff0c;建库 删表&#xff0c;建表 插入初始数据 } 建库语法&#xff1a; CREATE DATABASE 数据库名CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CHARA…

std::ratio<1,1000> 是什么意思?

author: hjjdebug date: 2025年 05月 14日 星期三 09:45:24 CST description: std::ratio<1,1000> 是什么意思&#xff1f; 文章目录 1. 它是一种数值吗&#xff1f;2. 它是一种类型吗&#xff1f;3. std:ratio 是什么呢&#xff1f;4. 分析一个展开后的模板函数5.小结: …

测试--测试分类 (白盒 黑盒 单元 集成)

一、按照测试目标分类&#xff08;测试目的是什么&#xff09; 主类别细分说明1. 界面测试UI内容完整性、一致性、准确性、友好性&#xff0c;布局排版合理性&#xff0c;控件可用性等2. 功能测试检查软件功能是否符合需求说明书&#xff0c;常用黑盒方法&#xff1a;边界值、…

整理了 2009 - 2025 年的【199 管综真题 + 解析】PDF,全套共 34 份文件

每年真题原卷 ✅ 每年详细解析 ✅ &#x1f4c2;【管综真题 2009-2025】 &#x1f4c2;【管综解析 2009-2025】 目录树&#xff1a; ├── 2009-2025管综真题 PDF │ ├── 2009年199管综真题.pdf │ ├── 2010年199管综真题.pdf │ ├── 2011年199管综真题.pd…

用golang实现二叉搜索树(BST)

目录 一、概念、性质二、二叉搜索树的实现1. 结构2. 查找3. 插入4. 删除5. 中序遍历 中序前驱/后继结点 一、概念、性质 二叉搜索树&#xff08;Binary Search Tree&#xff09;&#xff0c;简写BST&#xff0c;又称为二叉查找树 它满足&#xff1a; 空树是一颗二叉搜索树对…

自动化:批量文件重命名

自动化&#xff1a;批量文件重命名 1、前言 2、效果图 3、源码 一、前言 今天来分享一款好玩的自动化脚&#xff1a;批量文件重命名 有时候呢&#xff0c;你的文件被下载下来文件名都是乱七八糟毫无规律&#xff0c;但是当时你下载的时候没办法重名或者你又不想另存为重新重…

VueUse/Core:提升Vue开发效率的实用工具库

文章目录 引言什么是VueUse/Core&#xff1f;为什么选择VueUse/Core&#xff1f;核心功能详解1. 状态管理2. 元素操作3. 实用工具函数4. 浏览器API封装5. 传感器相关 实战示例&#xff1a;构建一个拖拽上传组件性能优化技巧与原生实现对比常见问题解答总结 引言 在现代前端开发…

stm32 ADC单通道转换

stm32c8t6仅有12位分辨率 1、单次转换 非扫描 1、初始化 void Ad_Init() {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//配置ADCCLK时钟分频,ADC的输入时钟不得超过14MHzRCC_ADCCLKConfig(RCC_PCLK2_Div6);G…

2KW压缩机驱动参考设计【SCH篇】

实物展示&#xff1a; ACDC: VAC和VAC-为交流电压检测&#xff1a; 1.C33 C34作为Y电容走线宽度要求&#xff1a; Y电容一般用于L/N到地之间&#xff08;L-PE 或 N-PE&#xff09;&#xff0c;主要作用是抑制共模干扰。其走线的电流非常小&#xff0c;推荐使用 ≥ 1mm 宽的走…

python05——循环结构

1、while循环 n0 #初始条件 while n<5: #判断print(hello python) #要重复执行的代码print(n) #注意同级代码缩进相同n1 #计数器结果&#xff1a; hello python 0 hello python 1 hello python 2 hello python 3 hello python 4 hello python 5 #求阶乘和 sum0 n1 whil…

LINUX编译、运行、测试lowcoder_CN

参考 二者没有太大差异。 LINUX编译、运行、测试lowcoder-CSDN博客 下载 git clone https://github.com/mousheng/lowcoder_CN 或 git clone https://gitcode.com/gh_mirrors/lo/lowcoder_CNcd lowcoder_CN三个模块 node-service api-service client 每个模块都有自己的…

Python 基础之函数命名

几个问题 使用描述性蛇形命名法&#xff08;snake_case&#xff09;Python函数名应使用什么大小写格式&#xff1f;为什么函数名要具有描述性&#xff1f;方法的命名规范是什么&#xff1f;函数、变量和类的命名有何区别&#xff1f; Python函数的命名有一些不可违背的硬性规…