#Custom editor drawer(s)
1 messages · Page 1 of 1 (latest)
So, I am a bit confused, what is the point of ItemStatistics? Could you say once more exactly what the end result is that you are wanting?
@hollow needle if I am understanding this right, you want to show different fields based on what ItemStatistics there are? If so, then you cannot use a PropertyDrawer for this, instead you use a Editor for the Item MonoBehaviour
let me get on my pc and i’ll explain
so what im trying to do, is that when you for example add two elements to the array, one for durability, and one for example for damage, there is an enum where you can pick a item statistic you want
and in the specific element
when you for example pick durability, i want it to show some specific fields in the inspector
below the enum
let me show you with screenshots
this is the axe item
and i want it to use durability and damage
so i just add them two
and now i need the specific fields in both elements
below the Statistic Type
Hmm, it might be more complicated than what you want. But I would probably change how you are doing this. I would have something like a ItemStat class that you inherit from, and each one has your stats like a HungerItemStats and DurabilityItemStats etc. Then in your Item class have a [SerializeReference] List<ItemStat> itemStats;. Then write a custom editor that has a list that lets you select the item stat you want to add to the list.
That way you don't have a bunch of fields on the class that cannot be used.
It would probably be about the same or less even editor scripting
this is what the code looks like at the moment
if u need to take a look
hasnt changed much
i have no idea what this is
In for runtime use you could do things like
public T GetStat<T>() where T : ItemStat
{
return itemStats.FirstOrDefault(i => i.GetType() == typeof(T));
}
// Usage
item.GetStat<DurabilityItemStat>().currentDurability = 5;
You don't need that at all.
For what you are saying you want to do, you want a custom editor not a property drawer
you sure?
100%
so what do i do
It isn't 'even possible' with PropertyDrawer
(it is, but you would be abusing the system and not how it is meant to be used at all)
@hollow needle this is what I recommend doing instead of what you are doing currently
Sure! Let me know when you have gotten as far as you can on your own 🙂
(@ or reply to me)
Okay
make an ItemStat class inside the Item script?
at the bottom
or make a new script
Okie
what should the itemstat inherit from?
or nothing
just monobehaviour?
oh wait will the Item be inheriting from the ItemStat?
ItemStat should inherit from nothing
Item should have a list of ItemStat. Classes that inherit from ItemStat should implement a set of fields. Like you should inherit from it and have one class have all of the durability related fields
And another with all of the damage related fields
im starting to think though, are all these still going to be found in the Item class?
because i need them there
because in my scripts for example
i check if item.damageUsed
No, that is what I am saying, you move them out to their own classes. Then you just add them to the items that need them.
You could do something like this
It does add a bit more code, but also separates it out better and makes it more modular. If you want to keep it as is, that is okay too! This is just my suggestion 🙂
whats wrong here
Idk, what does the error say? 😛
Forgot to add the using System.Collections.Generics at the top
ItemStat should not inherit from anything btw
okay
so now what would i do inside of ItemStat
Nothing inside of ItemStat, you just inherit from it
Create some classes that inherit from ItemStat that have the fields that you need
^
Up to you. Personally I like to follow the rule of one class per file as it makes it easier to find things
what would be the good name
DurabilityStat?
DamageStat?
just have Stat at the end
Sure! Or you could do DamageItemStat if you think you might have other places you would use similarly named stats
Like if you might have enemies, it would be good to specify that these are ItemStats and not just DamageStats. But for naming, it is what ever you feel like you would understand the easiest
true
i name them like that
this is the Item script now
ItemStat
and durability stat
correct so far?
Yup!
Nope, just put those in. And remove the attribute
Okie
We don't need it any more since we do want to see them now
yeah cause i dont need the HideInInspector anymore
alright let me just create all the classes
for different stats
now that Item inherits from ItemStat
im getting errors
in my other scripts
a lot of errors
Think of it like modules. An item is like an empty container, it just contains the basic info that all items contain like ID. Then you add modules (ItemStat) for different items. So if you have an axe you add the Damage(DamangeItemStat) and durability(DurabilityItemStat) modules to the item to give it that sort of functionality
It is kind of like the component system in Unity, where the Item acts like the gameobject and the ItemStat is like the components
If that makes it more confusing than just ignore it 😛
i get it
just need to make the recoil one
give me a sec
i have all of these now
Item looks a lot cleaner
Nice!
so what would i do now
Now we move on to the actual editor part. Create a new script in the Editor folder for the Item component and make it a custom editor (you can google setting up the very basics of a custom editor if you don't know)
Question, what version are you on, and do you want to use IMGUI or UIToolkit?
what is IMGUI?
let me google
That is the OnGUI and GUILayout etc
yeah
would it be harder to not use it?
That is IMGUI yes
yeah
i thought you were talking about something different 😅
like there would be a button on my scene window or something
So, at a high level, you will want to create a ReorderableList. And in the drawCallback you would just use a EditorGUI.PropertyField and in the addCallback you will populate the generic menu using the TypeChache class.
It will make more sense when you look up how to use ReorderableList
A little old but this looks like a decent source https://blog.terresquall.com/2020/03/creating-reorderable-lists-in-the-unity-inspector/
this is litterly what i was watching just now
😅
so what function will i need?
Start with making the ReorderableList
using UnityEditorInternal
do i keep going?
because im not sure where i should stop
or follow it to the end?
That should be good I guess
So, in the DrawElement method, use the SerializedObject and get the serializedproperty for the stats list, and then the serializedproperty element at index in that list
Then we draw it with EditorGUIPropertyField
i dont really know what you mean 😅
Yeah! Now you do itemStats.GetArrayElementAtIndex(index) to get whatever is at that index in ItemStats
alright
Then just plop the result of that in to a EditorGUI.PropertyField(rect, itemStat);
Oh hey, still at it? 😄
Use the result of GetArray... in the PropertyField
No, in DrawElement
We first get the property of all of the item stats (FindProperty(..)), we then get the item stat at the specific index (GetArratElementAtIndex(..)), and then we draw that item stat (PropertyField(..))
still trying to figure this out
its difficult when i have never touched reorderable lists
the drawElementCallback is called for every item in the bound SerializedProperty (the one given in the constructor). In this case you gave it itemStats so it is every item in itemStats.
var itemStatsProperty = serializedObject.FindProperty("itemStats");
var itemStatProperty = itemStatsProperty.GetArrayElementAtIndex(index);
EditorGUI.PropertyField(rect, itemStatProperty);
That is all ya need to do inside of the DrawElement callback method
What does the inspector look like right now
use DrawDefaultInspector instead of base.OnInspectorGUI
No need for base.
hmm, those errors do be funky
Debug.log itemStats to make sure it is being found
Just in OnEnable is fine
Make sure that the string is the same as the name of the field
it is
slap a public on it too just to be sure (the itemStats field)
coolio
?
OOh I know lol
Ya need to add [Serializable] to the ItemStat class and all derived classes
System namespace
yeah
no
done it
now try
Do you know what we just did?
Yup!
so Serializedobject gives us a representation of the serialized (savable to disk) data of a UnityEngine.Object. Normal C# classes and structs need to have the Serializable attribute on them though so that Unity knows that it should serialize them at all even. So the reason it was returning null was because the field was not being serialized at all so the SerializedObject could not find it
Does that make sense? Any questions?
ohh
yeah
wait so would you use serialize for like saving and loading
if it can save data to disk
No, SerializedObject is only for the editor. However things like unity's JsonUtility do use the Serializable attribute...iirc
alright
also why when i change the name from itemStats
to itemStatistics
here
and also change it in the editor script
its seperate
It wasn't because you changed the name, you just didn't see it since adding the Serializable attribute
That is expected, you can add the HideInInspector attribute to the field since we are handling drawing it our selves
just like that?
that worked
how can i move it down a bit?
its touching the itemID
GUILayout.Sacpe(200);
yup
LOL
Sort of... not xD
Almost done though! 😄
So ReorderableList has 2 callbacks for adding, one of them has like "menu" or "multi" or something in the name, we want to add a callback to that one
Did ya do that?
Name it what makes sense for what it is used for. OnAddItemStatDropdown or something
Nice, now we have two important glass we will use. The first is GenericMenu
okay
We create a instance of it and show it in that method. See if you can get a generic menu to show with a couple of dumby items that just Debug.Log when clicked
Don't just copy paste the example, that won't be helpful
Well it wasn't made to be copy pasted so you are going to have lots of issues
Sounds good @ me when ya are ready for some more help! 🙂
okay
we're inherating from Editor
but brackeys for example is inherating from EditorWindow
does that make a difference?
No, again you can use it anywhere. It is just easy for examples and tutorials to use an editor window because they are standalone and don't require other things like components.
also why are we making a window? what is it going to do
We are not making an editor window
You now, nvm here lets do this instead. It will be easier for you.
// inside of the dropdown callback method we made...
var menu = new GenericMenu();
var entryXName = new GUIContent("X");
bool isEntryXSelected = false;
GenericMenu.MenuFunction onEntryXClicked = () => {
Debug.Log("X has been clicked!");
};
menu.AddItem(entryXName, isEntryXSelected, onEntryXClicked);
menu.ShowAsContext();
Try that and see if it makes more sense to you @hollow needle
You need the System namespace
void MyMethod(Rect rect, ReordeableList list) is the signature of the method
Yeah!
thats so cool
so how do we add multiple buttons?
i mean not buttons
like the X
because there is 1 at the moment
How do you think?
😄
so should i make buttons for each of the item statistics now?
durability, damage etc
No need! That is were class number 2 comes in!
alright
Read the documentation and look at the example. I think you might be able to figure out how to do it from here!
But its okay if you can't
Did you read the doc page?
yeah
And you still are not sure what the method does?
It gives you a collection of all the types that inherit from the specified type
var itemStatTypes = TypeCahche.GetTypesDerivedFrom<ItemStat>();
Yeah
Then you loop over itemStatTypes and add an item to the generic menu for each one
Well that isn't going to work, since itemStatType is a System.Type and the first argument of AddItem takes a GUIContent
menu.AddItem(new GUIContent(itemStatType.Name), false, OnAddItem, (index, itemStatType));
// Add this method...
private void OnAddItem(object typeObject)
{
(int index, Type type) = ((int, Type))typeObject;
var itemStatsProperty = serializedObject.FindProperty("itemStatistics");
// Add an item to the array.
itemStatsProperty.arraySize++;
var itemStatProperty = itemStatsProperty.GetArrayElementAt(index);
var itemStat = Activator.CreateInstance(type);
itemStatProperty.managedReferenceValue = itemStat;
serializedObject.ApplyModifiesProperties();
}
Okay @hollow needle I gtg for an hour or so. But I think this should do it for you
Replace the contents of the foreach loop you have now with the menu.AddItem that is in that code block
you're the only person that actually understood what i wanted to do for like a week
lmao
lol
i couldnt get any progress for a week because i couldnt get help
also this
is exactly what i needed
Sorry it ended up being such a rabbit whole but I hope it will end up working well for you and you are able to learn some stuff! 😄
this doesnt work
if you could help
let me show you the error
its when i try and add a statistic
when you press on one of them
In AddItem you did (statisticType, statisticType) instead of (index, statisticType)
alright im gonna try that now
im gettin on my pc
@wind swan
Yeah... im gonna bee honest idk what I was thinking. We don't need an index at all https://paste.ofcode.org/37ZNpPTSJFEw5S7YTThmxev
alright
so that works now
it adds elements
how would i display the values now?
these under the correct stat
hmmm it should be showing them...
any idea why it isnt?
I could have gotten the code wrong for setting the managed reference so it is actually null still
Ah, you could change the inspector to debug mode to see if they are set properly
That is odd...
Sorry I'm not sure atm. And I gotta work so I can't help too much. I might be able to help later today. You could try debug.log other places. Another thing would be to create a simpler setup. Like, just a single field instead of a list so it is easier to debug what the issue might be. Start simple and make it more complicated as you go.
could you help me later then?
Yeah, I will try to 🙂
alright thanks
I tried to debug everything btw
And it shows everything as it should
Everything gets set
@wind swan i really dont wanna be annyoing
and i know u already helped me so much
if ur not busy later on today
could you help me?
I will see if I can't take a look. If you could post the code you have now (the editor stuff and the needed runtime code) that way I can just copy paste it in to a project to test it out my self that would be great