OOP, наследование - зачем это надо?
Добавлено: 02 сен 2018, 10:43
Я раньше как то обходился без наследования классов, но тут ударило в голову, что раз есть такие возможности, то надо их использовать. Целый день разбирался как сделать редактируемый список предметов для игры. И когда наконец что-то получилось, то особой радости не испытал. На что это повлияет? Сэкономит много памяти?
Можно было оставить класс предметов одинаковый для всех. Просто если предмет не оружие, то у него damage и range равны нулю. А так чего я добился? Много памяти сэкономил?
По ощущениям стало даже хуже. Потому что каждый раз когда нажимаешь галку "оружие", то редактор на секунду подвисает, чтобы переписать ScriptableObject.
Синтаксис:
Используется csharp
using UnityEngine;
public class TestItem : ScriptableObject {
public string name;
public int price;
}
public class TestItem : ScriptableObject {
public string name;
public int price;
}
Синтаксис:
Используется csharp
public class TestWeapon : TestItem
{
public int damage, range;
}
{
public int damage, range;
}
Синтаксис:
Используется csharp
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
public class TestItemsEditor : EditorWindow
{
TestClasses main;
void OnGUI()
{
if (!main)
main = FindObjectOfType<TestClasses>();
if (GUILayout.Button("Add"))
{
main.list.Add(CreateInstance<TestItem>());
AssetDatabase.CreateAsset(main.list[main.list.Count - 1], "Assets/Item" + main.list.Count + ".asset");
AssetDatabase.SaveAssets();
}
for (int i = 0; i < main.list.Count; i++)
{
TestItem item = main.list[i];
GUILayout.BeginHorizontal();
item.name = EditorGUILayout.TextField(item.name, GUILayout.Width(100));
item.price = EditorGUILayout.IntField(item.price, GUILayout.Width(100));
bool itemIsWeapon = item.GetType() == typeof(TestWeapon);
EditorGUI.BeginChangeCheck();
itemIsWeapon = EditorGUILayout.Toggle(itemIsWeapon, GUILayout.Width(20));
if (EditorGUI.EndChangeCheck())
{
string pathAndName = AssetDatabase.GetAssetPath(item);
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(item));
if (itemIsWeapon)
{
TestWeapon result = new TestWeapon();
main.list[i] = result = Cast(main.list[i], result);
AssetDatabase.CreateAsset(result, pathAndName);
}
else
{
TestItem result = new TestItem();
main.list[i] = result = Cast(main.list[i], result);
AssetDatabase.CreateAsset(result, pathAndName);
}
}
if (itemIsWeapon)
{
TestWeapon weapon = (TestWeapon)main.list[i];
weapon.damage = EditorGUILayout.IntField(weapon.damage, GUILayout.Width(100));
weapon.range = EditorGUILayout.IntField(weapon.range, GUILayout.Width(100));
}
EditorGUILayout.Space();
if (GUILayout.Button("X", GUILayout.Width(20)))
{
main.list.RemoveAt(i--);
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(item));
}
GUILayout.EndHorizontal();
Undo.RecordObject(main.list[i], "Edit item qualities");
EditorUtility.SetDirty(main.list[i]);
}
}
T Cast<T, U>(U source, T result)
{
System.Type resultType = typeof(T);
System.Reflection.FieldInfo[] fields = typeof(TestItem).GetFields();
foreach (var field in fields)
{
var propToSet = resultType.GetField(field.Name);
propToSet.SetValue(result, field.GetValue(source));
}
return result;
}
}
[CustomEditor(typeof(TestClasses))]
public class TestItemsButton : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (GUILayout.Button("Open editor"))
{
TestItemsEditor window = (TestItemsEditor)EditorWindow.GetWindow(typeof(TestItemsEditor), false, "Items Editor");
window.position = new Rect(100, 100, 1400, 900);
//TestWeaponsEditor page2 = EditorWindow.GetWindow<TestWeaponsEditor>("Weapons Editor", typeof(TestItemsEditor));
//window.Focus();
}
}
}
#endif
public class TestClasses : MonoBehaviour
{
public List<TestItem> list = new List<TestItem>();
}
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
public class TestItemsEditor : EditorWindow
{
TestClasses main;
void OnGUI()
{
if (!main)
main = FindObjectOfType<TestClasses>();
if (GUILayout.Button("Add"))
{
main.list.Add(CreateInstance<TestItem>());
AssetDatabase.CreateAsset(main.list[main.list.Count - 1], "Assets/Item" + main.list.Count + ".asset");
AssetDatabase.SaveAssets();
}
for (int i = 0; i < main.list.Count; i++)
{
TestItem item = main.list[i];
GUILayout.BeginHorizontal();
item.name = EditorGUILayout.TextField(item.name, GUILayout.Width(100));
item.price = EditorGUILayout.IntField(item.price, GUILayout.Width(100));
bool itemIsWeapon = item.GetType() == typeof(TestWeapon);
EditorGUI.BeginChangeCheck();
itemIsWeapon = EditorGUILayout.Toggle(itemIsWeapon, GUILayout.Width(20));
if (EditorGUI.EndChangeCheck())
{
string pathAndName = AssetDatabase.GetAssetPath(item);
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(item));
if (itemIsWeapon)
{
TestWeapon result = new TestWeapon();
main.list[i] = result = Cast(main.list[i], result);
AssetDatabase.CreateAsset(result, pathAndName);
}
else
{
TestItem result = new TestItem();
main.list[i] = result = Cast(main.list[i], result);
AssetDatabase.CreateAsset(result, pathAndName);
}
}
if (itemIsWeapon)
{
TestWeapon weapon = (TestWeapon)main.list[i];
weapon.damage = EditorGUILayout.IntField(weapon.damage, GUILayout.Width(100));
weapon.range = EditorGUILayout.IntField(weapon.range, GUILayout.Width(100));
}
EditorGUILayout.Space();
if (GUILayout.Button("X", GUILayout.Width(20)))
{
main.list.RemoveAt(i--);
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(item));
}
GUILayout.EndHorizontal();
Undo.RecordObject(main.list[i], "Edit item qualities");
EditorUtility.SetDirty(main.list[i]);
}
}
T Cast<T, U>(U source, T result)
{
System.Type resultType = typeof(T);
System.Reflection.FieldInfo[] fields = typeof(TestItem).GetFields();
foreach (var field in fields)
{
var propToSet = resultType.GetField(field.Name);
propToSet.SetValue(result, field.GetValue(source));
}
return result;
}
}
[CustomEditor(typeof(TestClasses))]
public class TestItemsButton : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (GUILayout.Button("Open editor"))
{
TestItemsEditor window = (TestItemsEditor)EditorWindow.GetWindow(typeof(TestItemsEditor), false, "Items Editor");
window.position = new Rect(100, 100, 1400, 900);
//TestWeaponsEditor page2 = EditorWindow.GetWindow<TestWeaponsEditor>("Weapons Editor", typeof(TestItemsEditor));
//window.Focus();
}
}
}
#endif
public class TestClasses : MonoBehaviour
{
public List<TestItem> list = new List<TestItem>();
}
Можно было оставить класс предметов одинаковый для всех. Просто если предмет не оружие, то у него damage и range равны нулю. А так чего я добился? Много памяти сэкономил?
По ощущениям стало даже хуже. Потому что каждый раз когда нажимаешь галку "оружие", то редактор на секунду подвисает, чтобы переписать ScriptableObject.