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

发布于:2025-05-20 ⋅ 阅读:(18) ⋅ 点赞:(0)

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;
        }
    }
} 


网站公告

今日签到

点亮在社区的每一天
去签到