Unity3D 游戏开发:背包数据界面 存储数据绑定Editor Windows中的参数变量(16)

348 阅读3分钟

一、脚本编程

using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using System.Collections.Generic;
using System;
using System.Linq;

public class ItemEditor : EditorWindow 
{
    private ItemDataList_SO dataBase;

    private List<ItemDetails> itemList  = new List<ItemDetails>();
    //    
    private VisualTreeAsset itemRowTemplate;
    
    private ListView itemlistView;

    private ItemDetails activeItem;
    
    private ScrollView itemDetailsSection;

    //默认浏览图片
    private Sprite defultIcon;

    private VisualElement iconPreview;
    
    [MenuItem("Lzj/ItemEditor")] 
    public static void ShowExample()
    {
        ItemEditor wnd = GetWindow<ItemEditor>();
        wnd.titleContent = new GUIContent("ItemEditor");
    }

    public void CreateGUI()
    {
        // Each editor window contains a root VisualElement object
        VisualElement root = rootVisualElement;

       // Import UXML
        var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UI Builder/ItemEditor.uxml");
        VisualElement labelFromUXML = visualTree.Instantiate();
        root.Add(labelFromUXML);

        //拿到模板数据
        itemRowTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/UI Builder/ItemRowTemplates.uxml");

        //拿到默认Icon图片
        defultIcon = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/M Studio/Art/Items/Icons/Lzj.jpg");

        //变量赋值,获得控制权
        itemlistView = root.Q<VisualElement>("ItemList").Q<ListView>("ListView");
        itemDetailsSection = root.Q <ScrollView>("ItemDetails");
        iconPreview = itemDetailsSection.Q<VisualElement>("Icon");
        //加载数据
        LoadDataBase();

        //生成ListView
        GenerateListView(); 

    }
    
    
    private void LoadDataBase()
    {
        var dataArray = AssetDatabase.FindAssets("ItemDataList_SO");

        if (dataArray.Length > 1)
        { 
            var path=AssetDatabase.GUIDToAssetPath(dataArray[0]);
            dataBase = AssetDatabase.LoadAssetAtPath(path, typeof(ItemDataList_SO)) as ItemDataList_SO ;
        }

        itemList = dataBase.itemDataList;

        EditorUtility.SetDirty(dataBase);
   }
    
    
    private void GenerateListView()
    { 
        Func<VisualElement>makeItem=()=>itemRowTemplate.CloneTree();

        Action<VisualElement, int> bindItem = (e, i) =>
        {
            if (i < itemList.Count)
            {
                if (itemList[i].itemIcon!= null )
                    e.Q<VisualElement>("Icon").style.backgroundImage = itemList[i].itemIcon.texture;

                e.Q<Label>("Name").text = itemList[i]== null ? "No ITEM": itemList[i].itemName;
            }
        };
        
        itemlistView.fixedItemHeight=50;
        itemlistView.itemsSource = itemList;
        itemlistView.makeItem = makeItem;
        itemlistView.bindItem= bindItem;

        itemlistView.onSelectionChange += OnListSelectionChane;
        //右侧信息不可见
        itemDetailsSection.visible= false;
    }

    private void OnListSelectionChane(IEnumerable<object> selectedItem)
    {
        activeItem=(ItemDetails)selectedItem.First();
        GetItemDetails();
        itemDetailsSection.visible = true;
    }

    private void GetItemDetails()
    {
        itemDetailsSection.MarkDirtyRepaint ();

        itemDetailsSection.Q <IntegerField>("ItemID").value=activeItem.itemID;
        itemDetailsSection.Q<IntegerField>("ItemID").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemID = evt.newValue;
        });

        itemDetailsSection.Q<TextField>("ItemName").value = activeItem.itemName;
        itemDetailsSection.Q<TextField>("ItemName").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemName = evt.newValue;
            itemlistView.Rebuild();
        });

        itemDetailsSection.Q<EnumField>("ItemType").value = activeItem.itemType;
        itemDetailsSection.Q<EnumField>("ItemType").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemType = (ItemType)Enum.Parse(typeof(ItemType), evt.newValue.ToString());
        });

        iconPreview.style.backgroundImage = activeItem.itemIcon == null ? defultIcon.texture : activeItem.itemIcon.texture;
        itemDetailsSection.Q<ObjectField>("ItemIcon").value = activeItem.itemIcon;
        itemDetailsSection.Q<ObjectField>("ItemIcon").RegisterValueChangedCallback(evt =>
        {
            Sprite newIcon=evt.newValue as Sprite;
            activeItem .itemIcon = newIcon;
            
            iconPreview.style.backgroundImage = newIcon==null ?defultIcon.texture: newIcon.texture;
            itemlistView.Rebuild();
        });

        itemDetailsSection.Q<ObjectField>("ItemSprite").value = activeItem.itemOnWorldSprite;
        itemDetailsSection.Q<ObjectField>("ItemSprite").RegisterValueChangedCallback(evt =>
        {
            Sprite newIcon = evt.newValue as Sprite;
            activeItem.itemOnWorldSprite = newIcon;
        });

        itemDetailsSection.Q<TextField>("Description").value = activeItem.itemDescription;
        itemDetailsSection.Q<TextField>("Description").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemDescription = evt.newValue;
        });

        itemDetailsSection.Q<IntegerField>("ItemUseRadius").value = activeItem.itemUseRadius;
        itemDetailsSection.Q<IntegerField>("ItemUseRadius").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemUseRadius=evt.newValue;
        });

        itemDetailsSection.Q<Toggle>("CanPickup").value = activeItem.canPickup;
        itemDetailsSection.Q<Toggle>("CanPickup").RegisterValueChangedCallback(evt=>
        { 
            activeItem.canPickup=evt.newValue;
        });

        itemDetailsSection.Q<Toggle>("CanDropped").value=activeItem.canDropped;
        itemDetailsSection.Q<Toggle>("CanDropped").RegisterValueChangedCallback(evt=>
        { 
            activeItem.canDropped=evt.newValue;
        });

        itemDetailsSection.Q<Toggle>("CanCarried").value = activeItem.canCarried;
        itemDetailsSection.Q<Toggle>("CanCarried").RegisterValueChangedCallback(evt=>
        { 
            activeItem.canCarried=evt.newValue;
        });

        itemDetailsSection.Q<IntegerField>("Price").value = activeItem.itemPrice;
        itemDetailsSection.Q<IntegerField>("Price").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemPrice = evt.newValue;
        });

        itemDetailsSection.Q<Slider>("SellPercentage").value = activeItem.sellPercentage;
        itemDetailsSection.Q<Slider>("SellPercentage").RegisterValueChangedCallback(evt=>
        { 
            activeItem.sellPercentage = evt.newValue;
        });
    } 
} 

image.png

二、初步了解脚本编程和API接口

1、声明变量,规划控制权

    private ItemDetails activeItem;

    private ScrollView itemDetailsSection;

    //默认浏览图片
    private Sprite defultIcon;

    private VisualElement iconPreview;
    //获得Visual Element 
    

ScrollView 是一种 C# 中的数据类型,表示一个可滚动的视图控件。它通常用于显示大量数据或需要滚动查看的内容,比如长文字、图片列表等。在 Xamarin.Forms 开发中,ScrollView 也被广泛应用于移动应用程序的开发。

ScrollView 提供了一种简单的方式来扩展内容区域,当内容超出 ScrollView 的边界时,用户可以使用滚动条或手势来滑动视图以查看更多内容。ScrollView 还支持滚动到指定位置、支持滚动事件等特性。

在 C# 中,我们可以通过在代码中创建 ScrollView 实例,并设置其中的一些属性和事件来自定义它的行为和外观。比如,下面的示例演示了如何创建一个包含多个 Label 控件的 ScrollView 对象:

函数赋值方式为:

2、赋予控制权

        //拿到默认Icon图片
        defultIcon = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/M Studio/Art/Items/Icons/Lzj.jpg");

        //变量赋值,获得控制权
        itemDetailsSection = root.Q <ScrollView>("ItemDetails");
        iconPreview = itemDetailsSection.Q<VisualElement>("Icon");

3、

            itemlistView.onSelectionChange += OnListSelectionChane;
            //右侧信息不可见
            itemDetailsSection.visible= false;
  • itemlistView 表示一个 Unity 引擎中的 ScrollView 控件实例,通常用于在界面上显示一个滚动区域。
  • .onSelectionChange 是 ScrollView 的事件之一,可用于监听 ScrollView 中选中项的变化。
  • += 表示添加事件处理函数,即将 OnListSelectionChane 方法添加到 .onSelectionChange 事件上,以便在 ScrollView 中选中项发生变化时调用该方法。
  • OnListSelectionChane 是一个方法名,表示当 ScrollView 中选中项发生变化时要执行的回调方法,具体内容需要根据实际需求来编写。
  • itemDetailsSection 表示一个 UIElements 中的 VisualElement 实例,通常用于在界面上显示一些信息或控件。
  • .visible 是 VisualElement 实例的属性之一,用于设置该元素是否可见。当该属性设置为 false 时,表示该元素在 UI 界面上不可见,即不会被渲染出来。

综上,这段代码的作用是:将 OnListSelectionChane 方法添加到 ScrollView 中选中项发生变化的事件处理函数中,并设置 itemDetailsSection 不可见。该代码片段通常用于初始化代码中,其目的是在 UI 界面上首次加载时隐藏 itemDetailsSection 区域,等用户从 ScrollView 选择一项后再根据选中项显示相应的详细信息。

4、

    private void OnListSelectionChane(IEnumerable<object> selectedItem)
    {
        activeItem=(ItemDetails)selectedItem.First();
        GetItemDetails();
        itemDetailsSection.visible = true;
    }

三、未完问题待续(不知道有没有掘友知道其他解决方法)

1、不知道为什么枚举变量调用无法实现

itemDetailsSection.Q<EnumField>("ItemType").value = activeItem.itemType;
        itemDetailsSection.Q<EnumField>("ItemType").RegisterValueChangedCallback(evt =>
        {
            activeItem.itemType = (ItemType)Enum.Parse(typeof(ItemType), evt.newValue.ToString());
        });

2、枚举变量同步数据问题终于解决了:

        itemDetailsSection.Q<EnumField>("ItemType").Init(activeItem.itemType);
        itemDetailsSection.Q<EnumField>("ItemType").value = activeItem.itemType;
        var 容器 = itemDetailsSection.Q<EnumField>("ItemType").value;
        itemDetailsSection.Q<EnumField>("ItemType").RegisterValueChangedCallback(evt =>
        {
           activeItem.itemType = (ItemType)Enum.Parse(typeof(ItemType), evt.newValue.ToString());
        });

阅读更多作者文章:

# Unity3D 游戏开发:用户界面(Editor)使用Unity Editor和ListView生成自定义物品管理界面(15)