【Unity】QFramework通用背包系统优化:使用Odin优化编辑器

本文主要是介绍【Unity】QFramework通用背包系统优化:使用Odin优化编辑器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

在学习凉鞋老师的课程《QFramework系统设计:通用背包系统》第四章时,笔者使用了Odin插件,对Item和ItemDatabase的SO文件进行了一些优化,使物品页面更加紧凑、更易拓展。

核心逻辑和功能没有改动,整体代码量减少了,并且增加了一个复制ItemConfig的小功能。

需要注意:

  • 在ItemConfigGroup的列表中中删除ItemConfig时,应该点红色的X按钮,不要点最右侧的叉号,不然关联的ItemConfig SO文件不会被同时删除;
  • QFramework带有的自定义属性功能可能会和Odin冲突,建议只使用其中一种;

为了和原教程区分,下文将使用ItemConfig和ItemConfigGroup类来代替Item和ItemDatabase类。

修改前后对比:
请添加图片描述

代码

IItem接口:

using UnityEngine;namespace QFramework
{public interface IItem{string GetKey { get; }string GetName { get; }string GetDescription { get; }Sprite GetIcon { get; }bool GetStackable { get; }bool GetHasMaxStackableCount { get; }int GetMaxStackableCount { get; }ItemLanguagePackage.LocalItem LocalItem { get; set; }bool GetBoolean(string propertyName);}
}

ItemConfig类:

using Sirenix.OdinInspector;
using UnityEditor;
using UnityEngine;namespace QFramework
{[CreateAssetMenu(menuName = "@ItemKit/Create ItemConfig")]public class ItemConfig : ScriptableObject, IItem{public ItemConfigGroup ItemConfigGroup { get; set; }[HideLabel][PreviewField(48, ObjectFieldAlignment.Left)][HorizontalGroup("名称类型", 54), VerticalGroup("名称类型/left")]public Sprite Icon = null;private void OnValidate(){this.name = Key;}[VerticalGroup("名称类型/left")][Button("X"), GUIColor(1, 0, 0)]private void RemoveThisConfig(){if (EditorUtility.DisplayDialog("删除物品", "确定要删除吗?\n(此操作不可恢复)", "删除", "取消")){ItemConfigGroup.ItemConfigs.Remove(this);AssetDatabase.RemoveObjectFromAsset(this);AssetDatabase.SaveAssets();AssetDatabase.Refresh();}}[VerticalGroup("名称类型/left")][Button("Dup"), GUIColor("yellow")]private void DuplicateThisConfig() // 增加复制/插入功能{if (ItemConfigGroup == null){Debug.LogError("ItemConfigGroup is null!");return;}ItemConfigGroup.DuplicateItemConfig(ItemConfigGroup.ItemConfigs.IndexOf(this), this);}[VerticalGroup("名称类型/right"), LabelWidth(42)][LabelText("名称")]public string Name = string.Empty;[VerticalGroup("名称类型/right"), LabelWidth(42)][LabelText("描述")][TextArea(minLines: 1, maxLines: 4)]public string Description = string.Empty;[VerticalGroup("名称类型/right"), LabelWidth(42)][LabelText("关键字")]public string Key = string.Empty;[VerticalGroup("名称类型/right"), LabelWidth(42)][LabelText("是武器")]public bool IsWeapon = false;[HorizontalGroup("属性")][VerticalGroup("属性/stackable"), LabelWidth(66)][LabelText("可堆叠")]public bool IsStackable = true;[ShowIf("IsStackable")][VerticalGroup("属性/stackable"), LabelWidth(66)][Indent][LabelText("有最大值")]public bool HasMaxStackableCount = false;[ShowIf("IsStackable"), EnableIf("HasMaxStackableCount")][DisplayIf(new string[] { "IsStackable", "HasMaxStackableCount" }, new[] { false, false })][VerticalGroup("属性/stackable"), LabelWidth(66)][Indent(2)][LabelText("最大值")]public int MaxStackableCount = 99;public string GetName => ItemKit.CurrentLanguage == ItemKit.DefaultLanguage ? Name : LocalItem.Name;public string GetKey => Key;public string GetDescription => ItemKit.CurrentLanguage == ItemKit.DefaultLanguage ? Description : LocalItem.Description;public Sprite GetIcon => Icon;public bool GetStackable => IsStackable;public bool GetHasMaxStackableCount => HasMaxStackableCount;public int GetMaxStackableCount => MaxStackableCount;public ItemLanguagePackage.LocalItem LocalItem { get; set; }public bool GetBoolean(string propertyName){if (propertyName == "IsWeapon"){return IsWeapon;}return false;}}
}

ItemConfigGroup类:

using Sirenix.OdinInspector;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
using UnityEditor;namespace QFramework
{[CreateAssetMenu(menuName = "@ItemKit/Create Item ConfigGroup")]public class ItemConfigGroup : ScriptableObject{public string NameSpace = "QFramework.Example";[Searchable][TableList(ShowIndexLabels = true)]public List<ItemConfig> ItemConfigs = new List<ItemConfig>();[Button("添加 ItemConfig", ButtonSizes.Large), GUIColor("yellow")]private void AddItemConfig(){// 创建一个新的 ItemConfig 实例ItemConfig itemConfig = CreateInstance<ItemConfig>();itemConfig.ItemConfigGroup = this;itemConfig.name = nameof(ItemConfig);itemConfig.Name = "新物品";itemConfig.Key = "item_new";// 将新创建的 itemConfig 添加到 ItemConfigGroup 的资源中AssetDatabase.AddObjectToAsset(itemConfig, this);// 在 ItemConfigs 列表中添加一个新的元素ItemConfigs.Add(itemConfig);// 保存所有更改到资源AssetDatabase.SaveAssets();// 刷新资源AssetDatabase.Refresh();}public void DuplicateItemConfig(int index, ItemConfig itemConfig){// 创建一个新的 ItemConfig 实例ItemConfig itemConfigSO = CreateInstance<ItemConfig>();itemConfigSO.ItemConfigGroup = this;itemConfigSO.name = itemConfig.Key;itemConfigSO.Name = string.Empty;itemConfigSO.Key = "item_new";itemConfigSO.IsWeapon = itemConfig.IsWeapon;itemConfigSO.IsStackable = itemConfig.IsStackable;itemConfigSO.HasMaxStackableCount = itemConfig.HasMaxStackableCount;itemConfigSO.MaxStackableCount = itemConfig.MaxStackableCount;// 将新创建的 itemConfig 添加到 ItemConfigGroup 的资源文件中AssetDatabase.AddObjectToAsset(itemConfigSO, this);// 在 ItemConfigs 列表中添加一个新的元素ItemConfigs.Insert(index + 1, itemConfigSO);// 保存所有更改到资源AssetDatabase.SaveAssets();// 刷新资源AssetDatabase.Refresh();}[Button("生成 Items 代码", ButtonSizes.Large), GUIColor("green")]private void GenerateCode(){var itemDatabase = this;// 获取当前 ItemDatabase 脚本的文件路径,并确定生成代码的保存位置string filePath = AssetDatabase.GetAssetPath(itemDatabase).GetFolderPath() + "/Items.cs";// 使用 QFramework 中的代码生成功能// 创建一个代码作用域树,用于生成代码结构ICodeScope rootCode = new RootCode()// 添加命名空间.Using("UnityEngine").Using("QFramework")// 空一行.EmptyLine()// 定义命名空间.Namespace(itemDatabase.NameSpace, ns =>{// 在命名空间中定义一个类ns.Class("Items", String.Empty, false, false, c =>{// 为每个 itemDB.ItemConfigs 生成一个静态字符串字段foreach (ItemConfig itemConfig in itemDatabase.ItemConfigs){c.Custom($"public static string {itemConfig.Key} = \"{itemConfig.Key}\";");Debug.Log(itemConfig.Key);}});});// 创建或覆盖文件,并准备写入生成的代码// 使用 using 语句自动管理 StreamWriter 的生命周期。// 当离开 using 代码块的作用域时,fileWriter 的 Dispose 方法会被自动调用,确保文件资源被正确关闭。using StreamWriter fileWriter = File.CreateText(filePath);// 创建一个代码写入器,将代码作用域树转换为字符串FileCodeWriter codeWriter = new FileCodeWriter(fileWriter);// 生成代码并写入文件rootCode.Gen(codeWriter);// 保存所有未保存的资源更改AssetDatabase.SaveAssets();// 刷新 Unity 编辑器的资源数据库AssetDatabase.Refresh();}private void OnValidate(){foreach (ItemConfig itemConfig in ItemConfigs){if (itemConfig != null){itemConfig.name = itemConfig.Key;}elseItemConfigs.Remove(itemConfig);}}}
}

这篇关于【Unity】QFramework通用背包系统优化:使用Odin优化编辑器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/691878

相关文章

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java String字符串的常用使用方法

《JavaString字符串的常用使用方法》String是JDK提供的一个类,是引用类型,并不是基本的数据类型,String用于字符串操作,在之前学习c语言的时候,对于一些字符串,会初始化字符数组表... 目录一、什么是String二、如何定义一个String1. 用双引号定义2. 通过构造函数定义三、St

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

Pydantic中Optional 和Union类型的使用

《Pydantic中Optional和Union类型的使用》本文主要介绍了Pydantic中Optional和Union类型的使用,这两者在处理可选字段和多类型字段时尤为重要,文中通过示例代码介绍的... 目录简介Optional 类型Union 类型Optional 和 Union 的组合总结简介Pyd

Vue3使用router,params传参为空问题

《Vue3使用router,params传参为空问题》:本文主要介绍Vue3使用router,params传参为空问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录vue3使用China编程router,params传参为空1.使用query方式传参2.使用 Histo

使用Python自建轻量级的HTTP调试工具

《使用Python自建轻量级的HTTP调试工具》这篇文章主要为大家详细介绍了如何使用Python自建一个轻量级的HTTP调试工具,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录一、为什么需要自建工具二、核心功能设计三、技术选型四、分步实现五、进阶优化技巧六、使用示例七、性能对比八、扩展方向建

使用Python实现一键隐藏屏幕并锁定输入

《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro