![](/img/trans.png)
[英]How to fix 'The type or namespace name could not be found ' error in unity?
[英]Unity build error: The type or namespace name 'Editor' could not be found
我有一个脚本Item.cs负责设置玩家库存中项目的参数。 在其中,我连接 Unity 编辑器库并创建一个继承自编辑器 class 的 class。 直到最近,我还在使用 Unity 版本2020.3.0f1 ,一切正常,但现在我安装了2021.3.9f1 ,但我开始遇到问题。
构建项目时,出现以下错误:
Assets\Inventory\Items.cs(31,31):错误 CS0246:找不到类型或命名空间名称“Editor”(您是否缺少 using 指令或程序集引用?)
Assets\Inventory\Items.cs(30,5):错误 CS0246:找不到类型或命名空间名称“CustomEditorAttribute”(您是否缺少 using 指令或程序集引用?)
Assets\Inventory\Items.cs(30,5):错误 CS0246:找不到类型或命名空间名称“CustomEditor”(您是否缺少 using 指令或程序集引用?)
Assets\Inventory\Items.cs(32,28): 错误 CS0115: 'Items.ItemsEditor.OnInspectorGUI()': 找不到合适的方法来覆盖
代码:
using UnityEngine;
using UnityEditor;
public class Items : MonoBehaviour {
public enum itemTypes { Weapon, Potion, Amulet }
public enum potionType { Health, Poison, Strong, Beer }
public enum amuletType { Health, Defense, Speed }
[Header("Main Settings")]
public itemTypes ItemTypes;
[HideInInspector] public GameObject Model;
[HideInInspector] public Texture2D Icon;
[HideInInspector] public string itemName;
[HideInInspector] public int itemNum;
// Weapon
[HideInInspector] public float damage;
[HideInInspector] public float atackSpeed;
[HideInInspector] public int broken;
// Potion
[HideInInspector] public potionType Potion = potionType.Health;
[HideInInspector] public float healthOfset;
[HideInInspector] public bool processingEffect;
// Amulet
[HideInInspector] public amuletType Amulet = amuletType.Health;
[HideInInspector] public float amuletValue;
[CustomEditor(typeof(Items))]
public class ItemsEditor : Editor {
public override void OnInspectorGUI() {
base.OnInspectorGUI();
Items items = (Items) target;
DrawMain(items);
EditorGUILayout.Space();
switch (items.ItemTypes) {
case itemTypes.Weapon:
WeaponSettings();
break;
case itemTypes.Potion:
PotionSettings();
break;
case itemTypes.Amulet:
AmuletSettings();
break;
}
serializedObject.ApplyModifiedProperties();
}
void DrawMain(Items items) {
EditorGUILayout.PropertyField(serializedObject.FindProperty("Icon"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("Model"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("itemNum"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("itemName"));
EditorGUILayout.Space();
}
void WeaponSettings() {
EditorGUILayout.PropertyField(serializedObject.FindProperty("damage"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("atackSpeed"));
}
void PotionSettings() {
EditorGUILayout.PropertyField(serializedObject.FindProperty("Potion"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("healthOfset"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("processingEffect"));
}
void AmuletSettings() {
EditorGUILayout.PropertyField(serializedObject.FindProperty("Amulet"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("amuletValue"));
}
}
}
您需要继承Editor
。
在 class 行中,您应该将其替换为MonoBehaviour
。
public class Items : Editor {
请注意,现在这个脚本不是MonoBehaviour
,所以它不会让你做某些事情。 例如,可能不会调用 Update 和 Start。
(在您的情况下,您可能不需要这个)如果您当前的 class 需要成为 MonoBehaviour,我会推荐一个新的 class 继承编辑器并保持这个相同。 您可以在新的 class 中执行所有 gui。
TL;DR 继承Editor
。
public class Items : Editor {
顾名思义, UnityEditor
命名空间仅在 Unity 编辑器本身中可用,在编译构建时完全剥离/根本不包括在内。
通常有三种方法可以防止在构建期间编译编辑器代码
在您的情况下,最简单的方法是将与UnityEditor
命名空间相关的所有内容包装在#if - #endif
预处理器中,因为您将编辑器嵌入到类型本身中。
我通常更喜欢相同的顺便说一句,因为嵌入编辑器会产生一些优势,恕我直言:
nameof
而不是硬编码的字符串 -> 容易出错且维护密集nameof
顺便说一句,我不会直接接触target
,而是通过serializedObject
完全接触 go 。
using UnityEngine;
#if UNITY_EDITOR // => Ignore from here to next endif if not in editor
using UnityEditor;
#endif
public class Items : MonoBehaviour
{
public enum itemTypes { Weapon, Potion, Amulet }
public enum potionType { Health, Poison, Strong, Beer }
public enum amuletType { Health, Defense, Speed }
[Header("Main Settings")]
public itemTypes ItemTypes;
public GameObject Model;
public Texture2D Icon;
public string itemName;
public int itemNum;
// Weapon
public float damage;
public float atackSpeed;
public int broken;
// Potion
public potionType Potion = potionType.Health;
public float healthOfset;
public bool processingEffect;
// Amulet
public amuletType Amulet = amuletType.Health;
public float amuletValue;
#if UNITY_EDITOR // => Ignore from here to next endif if not in editor
[CustomEditor(typeof(Items))]
public class ItemsEditor : Editor
{
private SeriaizdProperty itemTypes;
private SeriaizdProperty icon;
private SeriaizdProperty model;
private SeriaizdProperty itemNum;
private SeriaizdProperty itemName;
private SeriaizdProperty damage;
private SeriaizdProperty atackSpeed;
private SeriaizdProperty potion;
private SeriaizdProperty healthOfset;
private SeriaizdProperty processingEffect;
private SeriaizdProperty amulet;
private SeriaizdProperty amuletValue;
private void OnEnable()
{
// it is enough to do these ONCE when the inspector is loaded
// note that one huge advantage of having the Editor embedded into your class is that you can
// - and imho SHOULD - directly use "nameof" instead of going by hardcoded strings (-> error prone and maintenance intense)
itemTypes = serializedObject.FindProperty(nameof(ItemTypes));
icon = serializedObject.FindProperty(nameof(Icon));
model = serializedObject.FindProperty(nameof(model));
itemNum = serializedObject.FindProperty(nameof(itemNum));
itemName = serializedObject.FindProperty(nameof(itemName));
damage = serializedObject.FindProperty(nameof(damage));
atackSpeed = serializedObject.FindProperty(nameof(atackSpeed));
potion = serializedObject.FindProperty(nameof(Potion));
healthOfset = serializedObject.FindProperty(nameof(healthOfset));
processingEffect = serializedObject.FindProperty(nameof(processingEffect));
amulet = serializedObject.FindProperty(nameof(Amulet));
amuletValue = serializedObject.FindProperty(nameof(amuletValue));
}
public override void OnInspectorGUI()
{
//base.OnInspectorGUI();
// This is also required so the serialized poperties get updated
// with the current actual values
serializedObject.Update();
DrawMain(items);
EditorGUILayout.Space();
switch (items.ItemTypes)
{
case itemTypes.Weapon:
WeaponSettings();
break;
case itemTypes.Potion:
PotionSettings();
break;
case itemTypes.Amulet:
AmuletSettings();
break;
}
serializedObject.ApplyModifiedProperties();
}
void DrawMain(Items items)
{
EditorGUILayout.PropertyField(icon);
EditorGUILayout.PropertyField(model);
EditorGUILayout.PropertyField(itemNum);
EditorGUILayout.PropertyField(itemName);
EditorGUILayout.Space();
}
void WeaponSettings()
{
EditorGUILayout.PropertyField(damage);
EditorGUILayout.PropertyField(atackSpeed);
}
void PotionSettings()
{
EditorGUILayout.PropertyField(potion);
EditorGUILayout.PropertyField(healthOfse);
EditorGUILayout.PropertyField(processingEffect);
}
void AmuletSettings()
{
EditorGUILayout.PropertyField(amulet);
EditorGUILayout.PropertyField(amuletValue);
}
}
#endif
}
现在请允许我问:为什么不使用正确的 inheritance 并在根本不需要任何自定义编辑器的情况下执行以下操作?
public abstract class Items : MonoBehaviour
{
[Header("Main Settings")]
public GameObject Model;
public Texture2D Icon;
public string itemName;
public int itemNum;
}
然后(当然每个都在单独的脚本文件中)
public class Weapon : Items
{
[Header("Weapon Settings")]
public float damage;
public float atackSpeed;
public int broken;
}
public class Potion : Items
{
public enum PotionType { Health, Poison, Strong, Beer }
[Header("Potion Settings")]
public PotionType potionType;
public float healthOfset;
public bool processingEffect;
}
public class Amulet : Items
{
public enum AmuletType { Health, Defense, Speed }
[Header("Amulet Settings")]
public AmuletType amuletType;
public float amuletValue;
}
现在,每当您需要在不同项目之间进行区分时,您只需执行
Items item = <Get from somewhere>;
switch(item)
{
// This combines a type check and casting to the according type
// in one go. Basically similar to former using
// if(item is Weapon weapon){ ... } else if(item is Potion potion) { ... }
case Weapon weapon:
// do something with a weapon e.g.
Debug.Log($"weapon damage = {weapon.damage}", item);
break;
case Potion potion:
// do something if it is a potion
Debug.Log($"potion type = {potion.potionType}", item);
break;
case Amulet amulet:
// do something if it is an amulet
Debug.Log($"amulet type = {amulet.amuletType}", item);
break;
default:
// a type you haven't handled so far -> either ignore or implement properly
throw new ArgumentOutOfRangeException($"Type {item.GetType.AssemblyQualifiedName} is not handled yet!");
break;
}
最后,这是否需要成为MonoBehaviour
? 看起来这可能是一个ScriptableObject
或只是一个通用的
[Serializable]
public class Items
{
...
}
然后,您宁愿为此实现自定义PropertyDrawer
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.