0
\$\begingroup\$

I have a data structure that represents a simple terrain system and a number of filter algorithms that can be run on it. I want to be able to apply them in in any arbitrary order and have multiple instances with their own settings, basically how the Modfiers panel works in blender.

Currently, the filters are SO's that implement an interface. Then via Odin, I can expose a list of type <IFilter> to the inspector, and populate with SO instances in any order.

The script then iterates through the list, feeding the output from one to the input of the next.

List<Vertex2> generatedVerts = generateVerts(Settings settings)
foreach (var filter in filterList)
{
    generatedVerts = filter.Process(generatedVerts);
}

return generatedVerts;

It works, but the problem is each entry in the list is associated with an instance of the SO. So if I want to tweak the settings, I have to keep track of which SO instance corresponds to which entry in the list and it gets confusing.

What I really want is an interface where I can visually reorder modules in the inspector, but they also have their own controls exposed rather than being driven by a separate SO, as I say like how it works with blender modifiers.

Can anyone suggest an approach for this? I do have access to Odin if that will help.

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

I can think of two solutions.

The first one is to keep things as they currently are, and use a custom inspector to show the Scriptable Object fields as part of the inspector view of the object that contains the reference. You don't even need to know how to implement this, there are a bunch of plugins out there that have that feature. I personally like Naughty Attributes, but I've seen several others that do it as well.

The downside is that you still need to create an Scriptable Object instance in your project for each set of parameters that you want, which is kind of awful.

So, my preferred solution would be to make the filters not be Scriptable Objects at all, just plain C# objects. That way, when you serialize an instance it is serialized by value, and it is tied to the script that contains it, rather than sitting in your project forever.

So you would just do:

[System.Serializable]
public class Filter : IFilter{
   //...
}

And then:

[SerializeReference] List<IFilter> filters;

Except there's a problem. By default, Unity would not actually let you change the filters correctly through the inspector when using polymorphism. This is not because the serializer doesn't allow it, but simply because the objects won't be correctly drawn to the inspector. You can solve that with custom Property Drawers, but they are quite tedious to implement. In the past, I have used Animancer's Polymorphic Drawer for this, but that's only convenient because I happen to already be using Animancer as a whole in my project. I'm sure there are other projects that have similar attributes for this, I just don't know of them (maybe Odin has something like it? I wouldn't know).

\$\endgroup\$
2
  • \$\begingroup\$ thanks this gives me somewhere to start \$\endgroup\$ Nov 2, 2022 at 0:36
  • \$\begingroup\$ Turns out Odin, which I already have, can handle the drawing part. It now works just as I hoped, thanks. \$\endgroup\$ Nov 2, 2022 at 1:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .