#Custom editor drawer(s)

1 messages · Page 1 of 1 (latest)

wind swan
#

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

hollow needle
#

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

wind swan
#

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

hollow needle
#

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

wind swan
#

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;
wind swan
#

For what you are saying you want to do, you want a custom editor not a property drawer

hollow needle
#

you sure?

wind swan
#

100%

hollow needle
#

so what do i do

wind swan
#

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)

wind swan
hollow needle
#

alright can we try that then?

#

im just gonna make a copy project

wind swan
#

Sure! Let me know when you have gotten as far as you can on your own 🙂

#

(@ or reply to me)

hollow needle
#

Okay

hollow needle
#

at the bottom

#

or make a new script

wind swan
#

New script

#

That is just a normal C# class

hollow needle
#

Okie

#

what should the itemstat inherit from?

#

or nothing

#

just monobehaviour?

#

oh wait will the Item be inheriting from the ItemStat?

wind swan
#

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

hollow needle
#

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

wind swan
#

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.

wind swan
hollow needle
wind swan
#

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 🙂

hollow needle
wind swan
#

Idk, what does the error say? 😛

hollow needle
#

oh is it because there isnt a list here

#

wait no

wind swan
# hollow needle

Forgot to add the using System.Collections.Generics at the top

wind swan
hollow needle
#

so now what would i do inside of ItemStat

wind swan
#

Nothing inside of ItemStat, you just inherit from it

hollow needle
#

oh

#

okay

#

so whats next

wind swan
#

Create some classes that inherit from ItemStat that have the fields that you need

hollow needle
#

do i need to make new scripts?

#

or just below

#

ItemStat

wind swan
#

Up to you. Personally I like to follow the rule of one class per file as it makes it easier to find things

hollow needle
#

what would be the good name

#

DurabilityStat?

#

DamageStat?

#

just have Stat at the end

wind swan
#

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

hollow needle
#

true

hollow needle
#

this is the Item script now

#

ItemStat

#

and durability stat

#

correct so far?

wind swan
#

Yup!

hollow needle
#

do i just put these in the DurabilityItemStat?

#

or do i need something else

wind swan
#

Nope, just put those in. And remove the attribute

hollow needle
#

Okie

wind swan
#

We don't need it any more since we do want to see them now

hollow needle
#

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

wind swan
#

No, item should not inherit from ItemStat

#

Item is a container for a set of ItemStats

hollow needle
#

so just mono behaviour

#

as it was

#

?

wind swan
#

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

hollow needle
#

thats cool

#

thats better than what i was going for

#

cleaner

wind swan
#

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 😛

hollow needle
#

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

wind swan
#

Nice!

hollow needle
#

so what would i do now

wind swan
#

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)

hollow needle
#

yeah i know how

#

give me a second

#

got that

wind swan
#

Question, what version are you on, and do you want to use IMGUI or UIToolkit?

hollow needle
#

2020.3.13f1

hollow needle
#

let me google

wind swan
#

That is the OnGUI and GUILayout etc

hollow needle
#

is it this?

wind swan
#

yeah

hollow needle
#

would it be harder to not use it?

wind swan
#

Uhh, in 2020.3, probably a bit harder?

#

I mean it would be harder to use UIToolkit

hollow needle
#

is this what youre talking about?

wind swan
#

That is IMGUI yes

hollow needle
#

cause i did this before

#

yes

#

then lets use it

wind swan
#

yeah

hollow needle
#

i thought you were talking about something different 😅

#

like there would be a button on my scene window or something

wind swan
#

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

hollow needle
#

alright let me look it up

#

is it this?

#

wait thats a property drawer

wind swan
hollow needle
#

this is litterly what i was watching just now

#

😅

#

so what function will i need?

wind swan
#

Start with making the ReorderableList

hollow needle
#

why is it in red

#

im following the tutorial

#

and on his it aint

wind swan
#

using UnityEditorInternal

hollow needle
#

ohhh

#

i did

#

UnityEngineInternal

hollow needle
#

because im not sure where i should stop

#

or follow it to the end?

wind swan
#

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

hollow needle
#

i dont really know what you mean 😅

wind swan
#

Yeah! Now you do itemStats.GetArrayElementAtIndex(index) to get whatever is at that index in ItemStats

hollow needle
#

alright

wind swan
#

Then just plop the result of that in to a EditorGUI.PropertyField(rect, itemStat);

hollow needle
#

okie

#

is that what its supposed to look like?

unkempt kiln
#

Oh hey, still at it? 😄

wind swan
#

Use the result of GetArray... in the PropertyField

hollow needle
#

so it goes in here?

wind swan
#

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(..))

hollow needle
#

i have no idea what i just did

#

lmao

wind swan
#

lol

#

Where are we at?

hollow needle
#

its difficult when i have never touched reorderable lists

wind swan
#

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.

hollow needle
#

so i have to do something similar to what he did?

wind swan
#
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

hollow needle
#

thats is?

#

alright

#

this is what i now have

wind swan
#

What does the inspector look like right now

hollow needle
#

a mess

#

lmao

#

let me show u

wind swan
#

use DrawDefaultInspector instead of base.OnInspectorGUI

hollow needle
wind swan
#

No need for base.

hollow needle
#

oh okay

wind swan
#

hmm, those errors do be funky

hollow needle
#

its the list.DoLayoutList();

wind swan
#

Debug.log itemStats to make sure it is being found

hollow needle
#

where do i put the debug

#

because is theres no update

#

😅

wind swan
#

Just in OnEnable is fine

hollow needle
#

Null

#

do i have to change something here?

wind swan
#

Make sure that the string is the same as the name of the field

hollow needle
#

it is

wind swan
#

slap a public on it too just to be sure (the itemStats field)

hollow needle
#

still null

wind swan
#

coolio

hollow needle
#

?

wind swan
#

OOh I know lol

#

Ya need to add [Serializable] to the ItemStat class and all derived classes

hollow needle
#

what am i doing wrong

wind swan
#

System namespace

hollow needle
#

oh

#

alright

#

so to all these as well?

wind swan
#

yeah

hollow needle
#

what about Item?

#

no?

wind swan
#

no

hollow needle
#

done it

wind swan
#

now try

hollow needle
#

no more error

#

wow

#

works

wind swan
#

Do you know what we just did?

hollow needle
#

no

#

can u explain?

wind swan
#

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?

hollow needle
#

ohh

#

yeah

#

wait so would you use serialize for like saving and loading

#

if it can save data to disk

wind swan
#

No, SerializedObject is only for the editor. However things like unity's JsonUtility do use the Serializable attribute...iirc

hollow needle
#

alright

#

also why when i change the name from itemStats

#

to itemStatistics

#

here

#

and also change it in the editor script

#

its seperate

wind swan
#

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

hollow needle
#

just like that?

#

that worked

#

how can i move it down a bit?

#

its touching the itemID

wind swan
#

GUILayout.Sacpe(200);

hollow needle
#

here right?

wind swan
#

yup

hollow needle
#

alright works

#

so whats next?

#

have we done the hard part?

#

😅 🤣

wind swan
#

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

hollow needle
#

alright

#

so

wind swan
#

Did ya do that?

hollow needle
#

which one is it

wind swan
#

yeah the dropdown one

#

onAddDropdownCallback

hollow needle
#

yup

#

let me make a function

#

for it

#

what should i name it

#

AddElement?

wind swan
#

Name it what makes sense for what it is used for. OnAddItemStatDropdown or something

hollow needle
#

got it

wind swan
#

Nice, now we have two important glass we will use. The first is GenericMenu

hollow needle
#

okay

hollow needle
wind swan
#

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

hollow needle
#

okay

#

oh

#

it has to be in a seperate class?

#

because here it uses EditorWindow

wind swan
#

No, no it is just an example of how to use it

#

you can use it anywhere

hollow needle
#

oh

#

alright

wind swan
#

Don't just copy paste the example, that won't be helpful

hollow needle
#

i wanna just copy and paste it

#

to see what it looks like

#

and then change it

wind swan
#

Well it wasn't made to be copy pasted so you are going to have lots of issues

hollow needle
#

im gonna watch a tutorial on it

#

gimme some time

wind swan
#

Sounds good @ me when ya are ready for some more help! 🙂

hollow needle
#

okay

hollow needle
#

but brackeys for example is inherating from EditorWindow

#

does that make a difference?

wind swan
#

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.

hollow needle
#

also why are we making a window? what is it going to do

wind swan
#

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

hollow needle
#

why is Action giving an error

wind swan
#

You need the System namespace

hollow needle
wind swan
#

Ehh, I thought it would convert my bad

#

Edited

hollow needle
#

okay

#

what have i done wrong here

wind swan
#

void MyMethod(Rect rect, ReordeableList list) is the signature of the method

hollow needle
#

thats soo cool

#

and that'll be used to add the statistics?

wind swan
#

Yeah!

hollow needle
#

thats so cool

#

so how do we add multiple buttons?

#

i mean not buttons

#

like the X

#

because there is 1 at the moment

wind swan
#

How do you think?

hollow needle
#

like this?

#

it works

wind swan
#

😄

hollow needle
#

so should i make buttons for each of the item statistics now?

#

durability, damage etc

wind swan
#

No need! That is were class number 2 comes in!

hollow needle
#

alright

wind swan
#

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

hollow needle
#

im not sure how it works

#

is it

#

nvm

wind swan
#

Did you read the doc page?

hollow needle
#

yeah

wind swan
#

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

hollow needle
#

so all these

wind swan
#

var itemStatTypes = TypeCahche.GetTypesDerivedFrom<ItemStat>();

wind swan
#

Then you loop over itemStatTypes and add an item to the generic menu for each one

hollow needle
#

okay

#

so what would i do with the bool

wind swan
#

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

hollow needle
#

alright

#

thanks so much for everything

wind swan
#

Replace the contents of the foreach loop you have now with the menu.AddItem that is in that code block

hollow needle
#

you're the only person that actually understood what i wanted to do for like a week

#

lmao

wind swan
#

lol

hollow needle
#

i couldnt get any progress for a week because i couldnt get help

hollow needle
#

is exactly what i needed

wind swan
#

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! 😄

hollow needle
#

thanks

#

i'll message you here tmr if i have any problems

hollow needle
#

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

hollow needle
#

line 67 is this

wind swan
# hollow needle

In AddItem you did (statisticType, statisticType) instead of (index, statisticType)

hollow needle
#

im gettin on my pc

#

@wind swan

hollow needle
#

this is the code now

wind swan
hollow needle
#

im gonna try now

#

just gotta turn my pc on again 😅

hollow needle
#

so that works now

#

it adds elements

#

how would i display the values now?

#

these under the correct stat

wind swan
#

hmmm it should be showing them...

hollow needle
wind swan
#

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

hollow needle
#

its not showing in debug

wind swan
#

That is odd...

hollow needle
#

so what should i do?

#

i debuged

#

here

#

and it shows the right one

wind swan
#

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.

hollow needle
#

could you help me later then?

wind swan
#

Yeah, I will try to 🙂

hollow needle
#

alright thanks

hollow needle
#

I tried to debug everything btw

#

And it shows everything as it should

#

Everything gets set

hollow needle
#

@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?

wind swan
hollow needle
#

yeah sure

#

im at the gym atm

#

when i get back i’ll post it

hollow needle
#

@wind swan

#

i found a way to make it work

#

its fine now

#

thanks for everything