x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Abstraction and Interfaces

So I'm having trouble with abstraction in UE4 and c++. In c# I would use an interface and pass around objects as (e.g.) IAbility which would allow functions to take IAbility as a parameter and call any implemented members of the object on whatever derived class happened to be passed in.

So if a character had a list of IAbility, any class that implemented IAbility would be able to be placed in the container.

//Can hold Fireball or Slash etc.

List list = new List();

Then I could access a member of the list and call any function implemented from IAbility and it would call that function from the object's concrete type.

So far the closest I've gotten in UE4 is TSubclassOf and having to get and cast the default object that comes back from that. I'm looking into c++ interfaces but UE4 seems to really not like using interfaces for whatever reason.

//Needed to be able to setup a blueprint reference and allow any subclass to be given

TSubclassOf

Which also needs to be cast back to (or have the cast stored) the original type in order to use it. This causes a loss of abstraction as I won't/shouldn't know the concrete type when I'm trying to generically handle abilities.

In short, I'm looking for a way to take an abstract class or interface and use the derived class members without casting it back to the original type. I don't know if this is something that requires a workaround from c++ or UE4 but I haven't been able to figure it out yet. Any guidance would be appreciated and I'd be happy to clarify anything that might have been confusing as I know this was a wall of text. I feel like I'm missing something obvious, so sorry if it is.

tl;dr Is there a way to use abstract classes or interfaces generically or do you have to explicitly cast everything.

Product Version: UE 4.13
Tags:
more ▼

asked Oct 19 '16 at 01:19 AM in C++ Programming

avatar image

TX549
33 2 3 3

avatar image TX549 Oct 19 '16 at 04:52 AM

Thanks for the response, I was trying to keep the wall of text to a minimum so it wouldn't be a pain to read.

Right now I'm trying to set up a real time ability use system, like SMITE or Dragon Nest where a user will input a button causing a move to be readied which then upon confirmation would be activated. Each class (Ranger, Mage, Paladin etc.) would have a list of abilities to train and use, but the manner of storage issue should be fixed with solving the problem of trying to remove casts.

In my mind, my problem is essentially that c++/UE4 seems to want the explicit derived class (Fireball instead of Ability) to be able to use any behavior defined in that class (specifically calling functions as opposed to just returning values).

As opposed to calling Fire() on an Ability object, which is the base class, and have it execute the code on the objects actual derived class; UE4 seems to want the explicit conversion to the derived class to be able to run any functionality on there. This effectively ruins the attempt at abstraction.

avatar image TX549 Oct 19 '16 at 04:52 AM

All abilities inherit the IAbility interface and implement the members

Prep(); Fire(); Cleanup;

I'm also trying a base abstract class that implements IAbility but that doens't seem to be working quite right either.

I'm trying to get it to a point where I can have a generic ability object, let's say a fireball, and call each of the steps on it without having to explicitly cast it to a AFireball. I'm trying to model the fact that all abilities have, in my mind, those three steps and I shouldn't/ don't want to know exactly what ability I have to be able to handle it. In terms of abilities a sword swing functions no differently in my mind to a fire ball, they just spawn different hitboxes and FX.

So a sword swing's prep might spawn a slash effect and a close arc hit box, while a fireball would spawn a fire effect with a projectile. Both would be activated and handled in the same manner from a character/game point of view though, with the specific class overriding and specific behavior.

avatar image TX549 Oct 19 '16 at 04:52 AM

In c# I would be able to just call Prep() on any IAbility object because the object would just be an address reference to the concrete fireball. It seems to me (so far) that c++ and/or UE4 doesn't/can't have an object of a concrete type whose type was declared as a base type.

tl;dr I have a derived class that overrides base behavior, but I don't seem to have a good way to keep a generic (base class) reference to the derived class so I can work with it without explicitly casting it to it's derived class. This could totally be just something that c++ doesn't handle well, while c# does and that's why I'm coming in with this expectation. I dunno...

I'm going to look into trying to do this as a templated generic, but I don't know a ton about generics and templates in c++ so we'll see how that goes. Again, thanks for the help!

avatar image ScottSpadea Oct 19 '16 at 06:12 AM

in c++, you need to use pointers to objects to prevent object slicing when storing subclasses inside baseclass containers.

c# mostly avoids object slicing by using references instead of pointers, in C++ you have to be more careful not to loose data by copying from a subclass into a base class container.

if you put a weapon into an array of actors, you will loose all of the weaponness of the actor, and no amount of casting will get that data back. but if you put a weapon pointer into an array of actor pointers, you don't loose data, because you don't copy the object, you only copy the address, so you don't slice the object's data.


if you have an array of pointers to objects that implement an interface, the hierarchy of the objects shouldn't matter, you should be able to call the interface function Fire() on the anonymous object pointer, and the most relevant implementation of the Fire() function should be called.

so if a shotgun class inherits from a gun class, and overrides the fire() interface function, and you put a pointer to that shotgun in an array of weapon pointers, you should be able to call Fire on an element of that array, and it should just work, running the Shotgun's version of that Fire function.

avatar image ScottSpadea Oct 19 '16 at 06:29 AM

also, you could make each attack a DataAsset, so a designer can edit its values and keep track of it in the Asset Browser of the level editor.

these might help:

https://www.youtube.com/watch?v=hr9ybCCPw9Y&ab_channel=UnrealEngine

https://www.youtube.com/watch?v=0MhL9O09ZsM&ab_channel=UnrealEngine

https://www.youtube.com/watch?v=R2V_D5Krdy4&ab_channel=UnrealEngine

avatar image TX549 Oct 19 '16 at 06:30 AM

That's what I figured, but part of my confusion is stemming from the fact that the editor won't pick up blueprints of a given class unless the variable in the header is declared as a TSubclass of instead of just a pointer.

What I am/was doing was building out functionality in c++ and using a blueprint as a container for any actual things I needed to point to. So the behavior was contained in the c++ class, while the actual pointers to needed objects (The projectile required for a fireball lets say) were set up in the blueprint. This might have just been bad design, or maybe I'm missing a UPROPERTY bit that would let it find my blueprints?

object slicing being the fact that any data not present in the base class is trimmed off an object if it's cast down (or up? not sure what the proper terminology there is)?

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

1 answer: sort voted first

the container can hold Actors or Objects, then when you try to place an item in the container, you can check if it implements the interface by casting to the interface. this will give you a huge list of all actors in the editor to choose from, and i don't know of any way to narrow it down to subclasses that implement the interface.

any class members that you want to know about generically, you should have an interface function that returns those values, and you need to set up the interface function on each class that implements it, so that they return the proper values when asked through the interface function. an interface does not give you access to all members of a class, only values relevant to the interface is accessible through the return values of the interface functions.

so iAttack has a GetAttackStats function, and it returns a struct filled with Damage,Speed,Accuracy,etc... and a weapon can implement iAttack, and in its version of GetAttackStats, it can return its relevant values. but once you have a character and a weapon each implement the iAttack interface, and you want to put both in the same list, you will have to use a list of Actor, because that is the closest common ancestor between weapons and characters... but why would you ever need to be so generic that characters and weapons show up in the same list? is this list displayed to the player on the same menu page or is there some internal use for this list?


if you were more specific in explaining what you are trying to do from a gameplay/players perspective, rather than explaining the tool you want to use to achieve generic communication, maybe we can find a better way to organize your data so its generic enough and easy for designers/players to use. so if you describe how an ability is used in gameplay, it would be easier to help you design the flow of information. it may turn out that you can separate abilities as components of the things that own the abilities, or keep them completely separate, and you may never actually need to list all things that can have abilities in the same list, depending on the design of the game. your design may not require things to be as generic as you are trying to make them, and there could exist a more user friendly approach that works for your specific needs.

so what are you actually trying to make? is this a turn based attack menu? or some kind of RPG team roster? does this array represent options a player would select in a menu?

more ▼

answered Oct 19 '16 at 03:03 AM

avatar image

ScottSpadea
9.6k 320 205 449

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question