Struct but with a function

Hello,

is it possible to somehow have a struct that I can call a function on, or potentially hide a getter function in a way that it looks like a UPROPERTY in blueprint?

I want to build a parameter struct / object that I can use in my blueprint like so: It has a min and max value defined in the editor. At runtime, the actual value for the parameter will be interpolated by taking the level of the user in relation to the possible max level. For example: When my parameter has a min value of 5 and a max value of 15, and the current user level is 10 with a max level in my game of 20, then the parameter value is 10 = (5 + 10 * (10 / 20)).

Now I can have the struct, but I am not allowed to add a function to it to calculate the interpolated value at runtime. I also tried rewriting the struct to a class derived from uobject. But then I can not add this class as a member variable in my parent blueprint where I want it as a parameter. I mean I can add it, but I can’t define the min and max value in the blueprint editor, since it will only accept a reference to an instance of that parameter class, which I don’t have. When It’s a struct I can access and change the variable values of min and max easily.

I would be fine if I could decorate the function so that it looks like a UPROPERTY to the struct and therefore does not break the editor.

Thanks in advance

I would say you have two potential solutions here:

The first is using a blueprint function library as the place for all the blueprint functions for working with that structure. These could even be as simple as calling non-UFUNCTION methods of the structure. The main downside is that the blueprint nodes will look like function calls and not variable accesses (like they would with the getter/setter markup).

The second option would be going the route you already tried with turning it into a UObject. The piece that you’re missing to make it work the way you want is to flag the type and property so that it is an Instanced type. In the UCLASS macro you would specify EditInlineNew and in the UPROPERTY macro you add Instanced. This will provide a dropdown to select a type, and once you’ve selected a type you can edit the properties similarly to if it were a structure instance. It can be a little bit of a bother if you never have more than one type, but it’s provides an interesting place to be able to swap out similar pieces of functionality (like maybe a version that interpolates along a curve instead of linearly).

1 Like

Hi and thanks for your suggestion! I want to try out the second option, creating a UObject that I can edit inline in the editor, since it sounds exactly what I had in mind. I added EditInlineNew (next to Blueprintable) in my C++ class. Since the amount of parameters depends on each use case, I want to add the variable itself in blueprint. So I can’t really add the Instanced option on the variable (or can I?). So far the result is still the same, the field only allows me to add an Instance manually instead of editing the parameters inline.

Is there a way to still achieve this, despite me adding the variable itself in blueprint?

Screenshot for reference:

And this is what I hope I can get it to, being able to edit the properties of my UObject inline (on this screenshot it’s a struct):

Thanks in advance

Adding the object in blueprint would prevent you from being able to use the Instanced option (or at least I’ve never seen a way to do it).

I guess I don’t quite understand what you’re trying to accomplish with this particular combination of data. With the Instanced option you’d always have 1 and then you’d have to have ways to parameterize that instance appropriately to generate the result you want for the particular blueprint that you’re in.

I suppose your base class could have an array of instanced objects. Then instead of adding a new variable you would add an element to the array. I’ve definitely done that, though for different reasons.

1 Like

Okay then maybe I misunderstood you and it’s not possible to get what I want (basically I wanted to edit the params in the editor like on the last screenshot bottom right, but then also be able to call a function on the object). So then I will just go with your first suggestion and use a struct with a blueprint library.

One question though: Since I read about EditInlineNew, it should allow me to create an instance from the editor: On my first screenshot bottom right there is no button to create a new instance of the object. Am I doing it wrong or is the button elsewhere? The EditInlineNew was added on that class in C++.

Yes and no. It is possible to get what you want, but you’d have to add your property with the Instanced markup to your C++ class. You should try adding a property to your Ability Base with the Instanced markup just to see what it looks like.

You won’t be able to add Instanced instances in Blueprint. If that is an additional requirement then your options are either to stick to the structure, or you can make your C++ class have an instanced property that is a TArray. Then you’d get the benefits of instancing and be able to add the number of them appropriate to the specific blueprint. At a slight cost of some readability.

1 Like

Good point, I played around with it and I might even use an array (and just add a “comment” field for usability that replaces a variable name), however when I add some values to the array, save the project and restart unreal engine, the values are lost. The array size is the same but all members are back to None.

I also found the class decorator DefaultToInstanced that I understand can be used in conjunction with EditInlineNew and I thought I might use this on my class to make a blueprint variable of its type instanced, but it does not work.

At this point I might as well use structs, but trying it out made me curious, so if you have a solution for one of these please let me know.

Did you only rely on DefaultToInstanced? or have you tried it with the Instanced markup on the UPROPERTY? I haven’t had the issue you’re describing and I’ve done this exact thing of arrays of instanced objects. But I also don’t bother with the DefaultToInstanced flag. I’m not why, I think I tried it and it didn’t work for me in some situation or another.

1 Like

I can’t help but think that, in the time you’ve spent trying to solve this one problem, you could have added the Gameplay Ability System boilerplate code, and be off and running with a quite powerful system that has “level scaling properties” as a built in feature.

If you’re building a game with level-scaled properties, the GAS is pretty good. There are a few blog posts and youtube videos on how to set it up, and there’s the “Action RPG” sample project to investigate for usage patterns; the main thing missing is the bridge between “here’s how you get it going at all” to “here’s how you should actually think about using it in your own project.” But you can figure it out by playing around a bit and searching on the various interfaces and type names.

1 Like

Hi thanks,

@MagForceSeven you are right it was related to DefaultToInstanced, potentially a bug or I don’t use it correctly. When I use Instanced the values don’t get lost after saving and loading. I will continue the route with the C++ Instanced Array.

@jwatte I was actually thoroughly studying the GAS system before I decided not to use it. I don’t remember all of my concerns but one was that I was not able to determine the networking impact of the feature, which is important because I would like to release my game for mobile. I had the impression that GAS was quite heavy on that regard.

Also the whole GAS was by default assuming 3D and an 3D animations, while I work on a 2D game. So with that knowledge from researching the GAS I started implementing my own system, and honestly it’s just a lot of fun right now for me to build it :slight_smile: Thanks anyway, I appreciate the input and I agree it’s always good to use engine stuff when it solves the issue at hand. I just didn’t feel too confident in this specific scenario.

GAS is entirely networked! That’s one of the nice parts about it; it’s thoroughly worked-through how to distribute it.

I don’t quite see that – the attributes are just plain values. There are some helper actions that “play a 3D animation” and such, but given that you’d have to write your own “play 2D animation” code anyway, writing it inside the GAS versus writing it inside some other system seems about equivalent to me.

That being said, I understand the “it’s a lot of fun to work on systems” – that’s the main reason I still do these things! :slight_smile: