User Tag List

Page 3 of 3 FirstFirst 123
Results 81 to 96 of 96

Thread: GameplayAbilities and you.

  1. #81
    0
    I found a solution to my problem, I had to pass the AbilityActorInfo to the function.
    Code:
    FGameplayAbilitySpec* AbilitySpec = AbilitySystem->FindAbilitySpecFromClass(Ability);
    
    if (AbilitySpec && AbilitySpec->Ability)
    {
    	float TimeRemaining = AbilitySpec->Ability->GetCooldownTimeRemaining(AbilitySystem->AbilityActorInfo.Get());
    	UE_LOG(LogTemp, Warning, TEXT("Time Remaining %f"), TimeRemaining);
    }

  2. #82
    0
    Sorry for commenting on this so late, but I don't see why anything here could not have been accomplished with Blueprints. Lets not confuse preference for requirement. I'm sure you've lost 90% of the crowd here though, at least as of 2017 hahah. Thanks!

  3. #83
    0
    Samaritan
    Join Date
    Mar 2014
    Posts
    84
    Quote Originally Posted by malosal View Post
    Sorry for commenting on this so late, but I don't see why anything here could not have been accomplished with Blueprints. Lets not confuse preference for requirement. I'm sure you've lost 90% of the crowd here though, at least as of 2017 hahah. Thanks!
    I'm not sure I understand what you're trying to say with this comment. Are you saying the GamePlayAbilities as a whole aren't all that useful because you could "do something similar in blueprints"?

    Creating a game with abilities such as a typical modern day single player RPG has a lot of complex interactions between abilities and effects. It gets vastly more complicated to maintain if you're doing multiplayer. It's also completely optional.

  4. #84
    0
    Quote Originally Posted by malosal View Post
    Sorry for commenting on this so late, but I don't see why anything here could not have been accomplished with Blueprints. Lets not confuse preference for requirement. I'm sure you've lost 90% of the crowd here though, at least as of 2017 hahah. Thanks!
    Oh you could probably make a quite powerful multiplayer skill/buff-system in blueprints if you got the patience, skills and time for it, but this is a code plugin that's included in the engine by default and contains code that has been tried and tested quite well due to Epic themselves using it for their games. It is fast, replicates efficiently, it's powerful and flexible, and it's free, so what's not to like?

    This guide's topic concerns the basic comprehension of the system, and that's what you will find here. The main objective of my post is to get people acquainted with C++ to tinker with the system, partially because I think it's dumb that previously there were no useful ressources regarding how to make use of this system(an annoying trend that actually affects a lot of built-in C++ functionalities and systems, GameplayAbilities just has the added bonus of being quite obtuse in its initial setup, as well), partially because I am actually quite lazy, and I like having people do the work analyzing this behemoth for me so when I have issues myself, I can ask them. It's a good plan, in theory, if I do say so myself.

    You could actually expose most functions and useful tidbits of the system to Blueprints quite easily if you know the C++ basics and know which functions to look out for, but this is a guide, not a blueprint function library plugin, and making a function library for the system is, to put it blunt, not my job, and would probably get obsoleted anyway the moment Epic decides that they want to make the plugin a full-fledged, officially supported plugin for aspiring devs, with some proper blueprint exposure, some polish work to make the system as a whole less mindnumbingly confusing, and some other stuff. Maybe someone else can be arsed to do it.



    On a different, slightly less snarky note, I've decided to tinker around with AbilityTasks over the course of the last week a little bit, because I thought it'd be kinda neat to have a specialized montage ability task that spawns a special component that plays an attack animation with hitbox and combo data(basically, I can define which attacks can cancel into each other and which can't, and when, using tags). I even added a little input buffer-kinda thing where I can queue a new attack a little before the current attack becomes cancelable, actually quite proud of how well I managed to make the thing turn out in such a short time.
    But, uh, back to topic. AbilityTasks, they don't make a lick of sense, they somehow have exec output pins for each multicast delegate variable you add to them and tag as BlueprintAssignable in the UPROPERTY(even providing variable outputs to use alongside these exec paths if your multicast delegate has parameters) when you spawn them with their dedicated static spawn function and I eventually concluded that the way they do it is pretty much just magic, because I couldn't tell you how that works(I kept looking for a variable or something to define which delegates it should use, but it turns out it just picks any variable that's marked as BlueprintAssignable, so good grief, I guess).
    Now that I had a first taste of them I kinda want to update me old wall of text in the first post to include a little paragraph about them because I do feel like making your personal AbilityTask might be useful for functions specific to your game, but I'm not sure if my understanding of them is sufficient for such a thing.

  5. #85
    0
    AbilityTasks, are more or less standard async K2Nodes. This is the file which define them:
    K2Node_LatentAbilityCall.cpp
    You can have specialized K2Nodes for any tasks if you wish (limiting them to specific graphs, generating outputs, having graphs inside K2Node, pretty much anything goes).

    Though creating custom K2Nodes is bit obscure, since that part of engine have zero documentation, all you can do is to looks for how it is done and reverse engineer it.
    https://github.com/iniside/ActionRPGGame - Action RPG Starter kit. Work in Progress. You can use it in whatever way you wish.

  6. #86
    0
    Quote Originally Posted by iniside View Post
    AbilityTasks, are more or less standard async K2Nodes. This is the file which define them:
    K2Node_LatentAbilityCall.cpp
    You can have specialized K2Nodes for any tasks if you wish (limiting them to specific graphs, generating outputs, having graphs inside K2Node, pretty much anything goes).

    Though creating custom K2Nodes is bit obscure, since that part of engine have zero documentation, all you can do is to looks for how it is done and reverse engineer it.
    Ah thanks. This will be useful to know when I want to pull some more details out about how exactly they for example work and convert their delegate into output pins. The actual logic in the AbilityTasks themselves seems thankfully rather straightforward, most of them just bind some delegates in the Activate function and wait for them to get called by the component/objects responsible for them.

  7. #87
    0
    This is Amazing thank you.

  8. #88
    0
    Supporter
    Join Date
    Jun 2015
    Posts
    4
    I'm a bit late to this party, but I've just started diving into this system and implementing it into my project. I have a quick question about best practices and my understanding of the flow of abilities.

    So if I understand this correctly, when an ability is "activated" it cannot be reactivated, and an ability which is activated is still considered activating until end ability is called. In the example on the wiki (and probably the OP as well), an example for a hitscan weapon is posted (under "gameplaytasks example"). Basically, that blueprint draws a line from the character to a target point, then calls end ability. The wiki then mentions that you can "use the struct provided from the output of GameplayAbilityTargetActor_SingleLineTrace to determine which Pawn you hit (if any) and apply a GameplayEffect to it, reducing its health or applying buffs of some kind." Would you do the "damage" effect during the "activate ability" portion of the the blueprint? Or would it be better to save that result, and deal the damage after the ability resolves inside of the "ability end" event?

    The reason I'm asking this is I'm thinking about a typical "fireball spell" type ability. I was thinking about building the blueprint something like this, activate ability -> play the pawns animation, then once the animation was done, call end ability. Then within the end ability code, I would spawn the projectile, give it velocity, play sound, etc etc.

    Further down it talks about a simple 5 second cooldown gameplay effect. Why is this cooldown effect added during "activate ability" as opposed to "end ability?" Wouldn't it make sense to put the ability on cooldown AFTER it's finished using/casting? Especially if some abilities get animations coded into them, or some kind of interaction where an ability can be activated (start casting), but then a stun/knockback/silence would end the cast early, and prevent the user from completing and "casting" the spell itself. But now that I think about it, I have played some games where the ability goes on cooldown RIGHT when you start casting it, regardless of if it's interrupted or completed, however the spell resolving (and spawning a projectile or damage or whatever) only occurs when the ability ends and doesn't care if it's on cooldown or not...

    Should all of the game logic be applied in Activate Ability event as opposed to End Ability? If so, what is the purpose of the end ability event anyway? If not, what would be a set of "best practices" when determining what logic should go in either activate or end?

    I'd really love to see some other examples of common types of abilities, like a fireball, or hold and release (charge) attack, an interruptible attack, etc.

  9. #89
    0
    Infiltrator
    Join Date
    Jun 2015
    Posts
    23
    Quote Originally Posted by Zerve View Post
    I'd really love to see some other examples of common types of abilities, like a fireball, or hold and release (charge) attack, an interruptible attack, etc.
    I do charged attacks and had a couple of issues. Maybe there's a better way, but all of my abilities are charged, and are split between vector cast and non-vector cast (ie. some spells are directional, others just use the caster's direction or ignore direction altogether). I initially implemented charge as an attribute, but in order to have it increase along with the gametime I have to have a short period on an effect that increases it. I found 0.1s was bearable but still not exactly smooth for the purposes of updating UI elements. The problem is that attributes are replicated, and with 40 characters all replicating an attribute every 0.1s to each other the replication load was insane. I had to remove that and instead increase a float in tick when the charging tag is added, and reset back to 0 when it's not there. This means I only have to replicate the charging tag (plus a paused tag in my case). The charge ability is added completely separate to the rest of the ability system, and all abilities that require charge require that tag to be added in order for the ability to be activateable. So actually the only ability the player can use is the one to start charging, and then the other abilities are available after that. The final note is that the player is generally very sensitive to charge times, particularly if you have different charging tiers that do different things, so I actually ended up using the client's Charge and sending it to to the ability cast via the targeting actor, then on the server it checks that it's within 200ms to prevent cheating. This prevents the user from putting in whatever time they like, but also means that (very) high ping users won't be able to use charge abilities.

    If you're charging things that also may mean you don't want static values in your gameplay effects. You have two options for setting values at runtime here: SetByCallerMagnitude and Level. I originally did the former, and it works perfectly well, but similar to the charging issues it creates extra replication load, as each effect you use SetByCallerMagnitude on will now have an extra entry in its array, and that gets replicated to all clients. So if you're setting damage or something that way it can really add up. I originally did it this way because I wanted to use Level for the ability level, but I realised I can just incorporate that calculation in the ability itself and it's easier. I made a simple MagnitudeCalculation class that returns the magnitude as the level, and using that I can also set the duration via the level of the effect. This is good for something like 'Chill' where the character is slowed a static amount, but I want to have different abilities apply different durations of chill. If you need both runtime-set duration and magnitude then you'll have to use SetByCallerMagnitude.

  10. #90
    0
    So if I understand this correctly, when an ability is "activated" it cannot be reactivated, and an ability which is activated is still considered activating until end ability is called.
    Almost, you can set a setting in the ability classes' defaults to allow reactivation while the ability is still running, but generally speaking you cannot reactivate an ability that hasn't been ended since it's last activation, and is considered active until then.

    In the example on the wiki (and probably the OP as well), an example for a hitscan weapon is posted (under "gameplaytasks example"). Basically, that blueprint draws a line from the character to a target point, then calls end ability. The wiki then mentions that you can "use the struct provided from the output of GameplayAbilityTargetActor_SingleLineTrace to determine which Pawn you hit (if any) and apply a GameplayEffect to it, reducing its health or applying buffs of some kind."
    I didn't make that actually, but yeah, the target data ability task essentially takes a target actor class as template so to speak, and this template class usually has some kind of target finding method implemented that's used to determine what is ultimately being targetted(I believe it even uses the client result of the targetting over the server if there is one, but I haven't done enough with targetting actors to say that for sure). It's a little more flexible than a regular trace but slightly more cumbersome too because you need to create an extra class for each behaviour and it's imo a little obtuse and not that clear how and where exactly to implement the target getter.

    Would you do the "damage" effect during the "activate ability" portion of the the blueprint? Or would it be better to save that result, and deal the damage after the ability resolves inside of the "ability end" event?
    In the ActivateAbility portion generally, but I suppose it does depend on what you try to do. It frankly doesn't matter where you put your ability logic, as long as you don't use any ability tasks or anything else particularly advanced. As soon as you use an ability task for waiting/responding to outside signal-purposes, ActivateAbility should be used. EndAbility is called when the ability wishes to shut down and, as such, no more AbilityTasks should be created during that period. It's also cleaner to actually place the effects of an ability's activation within, well, its activation function in my opinion, but hey, whatever suits you.

    The way I see it, EndAbility is for things you HAVE to resolve, no matter when or how your ability ends. Imagine a toggleable buff ability, for instance. The ability activation may just consist of you placing a gameplay effect on your character that boosts its stats and waiting for an additional button press so you may end the ability. Of course, you could just prompt the ability to simply remove the gameplay effect it applied after pressing the button and before ending the ability, but what if your ability got cancelled or interrupted by an outside source, such as a different gameplay effect with a tag that your ability has described as something it gets cancelled by in its defaults. Now you're in deep feces, because ending the ability before the key got pressed never prompts the removal of the buff, and the character may now either reactivate the buff for multiple instances of that buff, or may reap the benefits of having the buff on without going through the trouble of activating the ability again! That's no good!

    Hence, adding this "remove my buff when I wish to end the ability" clause in the EndAbility function makes sense, because no matter how the ability got ended and when, that function will always get called and you may add finishing touches and cleanups as you wish.

    The reason I'm asking this is I'm thinking about a typical "fireball spell" type ability. I was thinking about building the blueprint something like this, activate ability -> play the pawns animation, then once the animation was done, call end ability. Then within the end ability code, I would spawn the projectile, give it velocity, play sound, etc etc.
    Bad idea, because not only should you not start ability tasks(assuming you use the SpawnActor ability task for the trick, anyway) when the ability has explicitly expressed its wish to end itself to you(as the ability tasks will go down with the ability instance), your ability needs to end regardless of how the montage ultimately ended up playing. If you'd do it like this, you'll head into trouble when your montage can get interrupted or even forced not to play at all, because you still need to end the ability in these cases, and the EndAbility function does not discriminate how your ability ended.

    In fact, you could break your game pretty badly already, without adding any new abilities or effects that could cancel your ability into the mix: Simply bind 2 separate fireball abilities with this setup to 2 different keys. Activate the first fireball ability, it will play the animation. Activate the second immediately after, and your first ability will either become unable to resolve itself due to not calling EndAbility in this unexpected path, or simply fire the fireball immediately before the animation could finish properly, while this second ability prompts the montage to play once again. Then you can activate your first ability again, cancel the second one, make the second one fire its fireball, and, well, what was intended to be a singular fireball has now become dual-wielding rapid-fire fireballs of utter annihilation.

    Cool as it may be, that's very difficult to balance, so I'd argue you'd be better off just not letting this happen. Attach your fireball spawning node to the OnBlendOut on your Montage task or something.

    And then make the annihilator dual-wield fireballs their own ability.

    Further down it talks about a simple 5 second cooldown gameplay effect. Why is this cooldown effect added during "activate ability" as opposed to "end ability?" Wouldn't it make sense to put the ability on cooldown AFTER it's finished using/casting? Especially if some abilities get animations coded into them, or some kind of interaction where an ability can be activated (start casting), but then a stun/knockback/silence would end the cast early, and prevent the user from completing and "casting" the spell itself. But now that I think about it, I have played some games where the ability goes on cooldown RIGHT when you start casting it, regardless of if it's interrupted or completed, however the spell resolving (and spawning a projectile or damage or whatever) only occurs when the ability ends and doesn't care if it's on cooldown or not...
    When exactly you commit the cooldown/cost is completely up to you, and there's a good reason why that is its own function rather than being integrated into either ActivateAbility or EndAbility by default. No size fits all, and it's all very dependent on the type of game and the type of ability within that game you want to make.

    One thing to consider is that the point of ressource commitment should usually be the very last thing that can prompt an ability to fail, and while you can check that individually without applying the ressource commitment, it's built into the commiting itself as well. Maybe the ability was off cooldown and maybe you could pay its mana cost when you first activated it, but perhaps this has changed now that the actual effect of the ability takes place because you got manadrained, or a unique spell triggered your spell to go on cooldown(like, maybe you can only use your mobility skill after a small charge time and only after having received no damage for 2 seconds). If you commit the ability's costs only after you have given the player the ability's benefits, then you run into the risk of letting them essentially walk out without paying, so to speak. Perhaps you want to split cost and cooldown too, apply the cost before the effect can activate, and applying the cooldown when it has resolved, deciding in detail what exactly can prompt an ability to fail at the last moment and what can't.

    Another thing to think about is that other abilities actually can use tasks to wait for an ability to commit or an attribute to change. Perhaps you have a malicious debuff on your character that prompts you to take damage for each point of mana you spend, potentially killing them for mana consumption before they even get the chance to get to the effect part of their spell(I know that a Dota 2 hero utilizes such a mechanic pretty much word for word, and another one just deals a flat amount of damage and silences you shortly before you get to the effect part of the skill instead), or maybe you have a buff that alters the cost of your next ability slightly, if you can afford it, in favour of a power boost for a short period of time? Placing the ability commiting function in smart ways can make it a useful asset.

    Finally, I repeat the point from the previous example with the fireballs: Just because an ability ends doesn't mean it ends the way you want it to. Commiting the ressources in the EndAbility is kinda dangerous and makes things needlessly complicated, because you're calling a function quite specifically meant for a select few scenarios(in which the ability supposedly progresses as intended) in a function that is more or less built not to discriminate and always get called. These issues can be solved by using bools and such, but why would you go through this issue when just calling it in ActivateAbility where it makes sense is way simpler and easy to understand?
    Last edited by KZJ; 06-24-2017 at 03:59 PM.

  11. #91
    0
    Supporter
    Join Date
    Apr 2016
    Posts
    1
    Thank you for the work into putting this together and answering questions about this module.
    Last edited by Syxr; 07-12-2017 at 09:57 AM.

  12. #92
    0
    Supporter
    Join Date
    Jun 2015
    Posts
    4
    Man this is so embarassing but I'm at my limit. I haven't used C++ in ages, and the heavily macro'd nature of UE4 isn't something that I'm used to. I've scoured the net for different tutorials and questions but seem like I'm the only one having this issue. But here it is:

    I'm trying to incorporate Attributes to my project, and made the following "BaseAttributeSet.h" class:

    Code:
    #include "CoreMinimal.h"
    #include "AttributeSet.h"
    #include "UnrealNetwork.h"
    #include "BaseAttributeSet.generated.h"
    
    /**
     * 
     */
    UCLASS(Blueprintable, BlueprintType)
    class DUNGEONRUNNERS_API UBaseAttributeSet : public UAttributeSet
    {
    	GENERATED_UCLASS_BODY()
    	
    public:
    	UPROPERTY(EditAnywhere, BlueprintReadWrite, ReplicatedUsing = OnRep_Health, Category = "Base Attributes")
    	FGameplayAttributeData Health;
    	UFUNCTION()
    	void OnRep_Health()
    	{
    		GAMEPLAYATTRIBUTE_REPNOTIFY(UBaseAttributeSet, Health)
    	}
    	
    };
    And my very minimal .cpp:

    Code:
    #include "BaseAttributeSet.h"
    
    void UBaseAttributeSet::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
    {
    	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    
    	DOREPLIFETIME_CONDITION_NOTIFY(UBaseAttributeSet, Health, COND_None, REPNOTIFY_Always);
    }
    Yet, every time I try to compile I'm getting this error on the GAMEPLAYATTRIBUTE_REPNOTIFY line: error C2027: use of undefined type 'UAbilitySystemComponent'
    and on AttributeSet.h note: see declaration of 'UAbilitySystemComponent'

    So I peeked into macro into AttributeSet.h and found an early declaration of UAbilitySystemComponent in there, assuming that is causing the error since it isn't defined. So do I need to edit this header file to get my project to compile? I don't really want to go and change engine files, rather just change my own.

    I've found that commenting out the REPNOTIFY line allows me to compile without any issue. I have a feeling this is something really simple and stupid but I just can't get it

    Edit: I've also tried moving the On_Rep function to BaseAttributeSet.cpp, but in doing so gives me some linker errors/unresolved externals...

    Edit2: Of course I solve it after posting. Soultion: change generated uclass body to basic "generated body", and move OnRep func to cpp, include abilitysystemcomponent and unrealnetwork in cpp class. Hit compile save.

    ####

    And on a side note, what's the best way to bind that ability system to the actor? Another resource recommended AbilitySystem->InitStats() function inside of the PostInitializeComponents() func of my actor, but I'd rather do it in the constructor as mentioned in the tutorial. Actualy when I tested the InitStats func it broke my editor and was unable to launch until I figured out how to rebuild it out of the engine.. Oh the joys of being a noob.

    Something like this?

    Code:
    void ADungeonRunnersCharacter::PostInitializeComponents()
    {
    	Super::PostInitializeComponents();
    	AbilitySystemComponent->InitStats(UBaseAttributeSet::StaticClass(), NULL);
    }
    Or is the something better?
    Last edited by Zerve; 06-25-2017 at 07:46 AM.

  13. #93
    0
    Quote Originally Posted by Zerve View Post
    Stuff about GAMEPLAYATTRIBUTE_REPNOTIFY
    Include "AbilitySystemComponent.h" in your header file, or wherever you wish to implement your On_Rep function.

    The GAMEPLAYATTRIBUTE_REPNOTIFY macro in your OnRep_Health function is causing the error, because it's set up to update important things within the AbilitySystemComponent this attribute set belongs to.

    If you peek into the macro's definition, it's easy to see that GetOwningAbilitySystemComponent()->SetBaseAttributeValueFromReplication is the culprit, because it gets a reference to an AbilitySystemComponent and then tries to run one of its functions(which are not yet defined, because you didn't include the AbilitySystemComponent header yet). It should work correctly then.

    Quote Originally Posted by Zerve View Post
    And on a side note, what's the best way to bind that ability system to the actor? Another resource recommended AbilitySystem->InitStats() function inside of the PostInitializeComponents() func of my actor, but I'd rather do it in the constructor as mentioned in the tutorial. Actualy when I tested the InitStats func it broke my editor and was unable to launch until I figured out how to rebuild it out of the engine.. Oh the joys of being a noob.
    Not sure if I understand the question. The Ability System itself should just work out of the box, more or less, once you add the component to your actor of choice and describe which actors are your owner/avatar with InitAbilityActorInfo.

    Attribute Sets too should just integrate themselves into the ability system automatically should you create them as default subobjects on the same actor, though granted I personally got issues with that as it seemingly stopped working for no reason. I'm still trying to figure out how that happened and why, but just in case your attribute set won't automatically register either, you may write AbilitySystem->AddDefaultSubobjectSet<UMyAttributeSet>(CreateDefaultSubobject<UMyAttributeSet>(TEXT("Attribute Set"))) instead. This essentially manually adds a freshly created default subobject attribute set into your AbilitySystemComponent, instead of relying on it to do it automatically for you. There are other functions that let you do the same thing for non-default subobject attribute sets too, in case you want to do it a different way. Default subobjects are just the easy way to slap it into your constructor.

  14. #94
    0
    Supporter
    Join Date
    Jun 2015
    Posts
    4
    KZJ, I really appreciate the time you've put into this post and the time spent replying to me and my questions. I've been in "the zone" just working on my project and everything is just a blur with all the new things, mistakes, and systems, that I've experienced. Unfortunately my ability to think well and process information clearly has severely deteriorated .

    I'm at the point now where I have a basic ability system, effects, tasks, attributes, and gameplay cues working together. I've got two abilities which spawn different projectiles and apply a gameplay effect when hitting an enemy. That effect also reduces the enemies health (which is within AttributeSet). The next system I'm tackling is building an aggro/threat table of sorts. Basically, any AI Controller needs to keep a track of all players and how much healing/damage they have done, and that will determine the AI's behavior. I can implement that part easily, but the big problem is finding a way to sync up the ability attributes system into the gameplay logic in a good way. How can I track damage taken, damage healed, and who did it?

    In the last four-ish hours or so I've been trying out some really stupid stuff (partly due to my brain turning to jelly, and also because there are almost no other resources for the GameplayAbilities system). Some of the dumb this I've considered/tried are:

    Have one point of damage be represented by a single stack on the ability system as a gameplay effect. IE, player 1 deals 100 damage, the AI gains 100 stacks of Effect A, player 2 heals 50 damage, the AI gains 50 stacks effect B. There's a nice feature in here where the stacks can be independent by owner/actor. This fails because I couldn't figure out a way to have a single ability place multiple stacks. Obviously, I could've hard coded each ability, so ability A, does 100 damage, loops and applies the "threat/aggro" effect 100 times. But I couldn't find any way to actually grab the "damage amount" from the ability nor the effect. There is access to the "modifiers" field on gameplay effects, but couldn't get the value, so everything would need to be hardcoded. Not only that but, I didn't remember finding a way to actually "get" who owned which stacks. If A has 100 stacks, and B has 50, I couldn't really get that info, only that there are 150 stacks in total.

    Tick every second to check for a changed health attribute. This seemed like a lame hack to find out whenever I took damage. It would be easy to implement and I could move on to other features quickly. Except there wouldn't be a way to know who actually did the damage to the character. I'd easily know I took "X" damage, but from who? Quick and dirty. Obviously can't do this.

    Using the "Display" part of an effect with a Gameplay Cue. This is something which I'd like to learn more about, but from all my research and looking around, it seems like this is only intended for graphical things, not actual game logic. Similar to the stacking effect, I could write some short and sweet blueprints to adjust each of these. Also similar to the stacking effect, this could get unwieldy with a large number of abilities, since the actual amount of damage would again need to be hardcoded for each individual ability. I also just felt unsatisfied with this solution, since all the documentation says "for visual effects."

    Gameplay Events sounds like the perfect solution! But all I can't find any examples of how to use this with my desired system. The tutorial mentions how to trigger other abilities, is this the only use of this system? Can this event be written like a blueprint event node? Like, send this event to my AI controller with the payload, then do some logic based on that? The lifesteal example makes perfect sense to me, and so would a kind of thorns effect (reflect flat or x% damage back to the attacker), or even a "counter" or reflect style of move which just bounced the ability back at the caster (sounds fun right?). My only idea from that information is to give my AI characters an "ability" which when activated does all the aggro/threat table logic I mentioned before. This seems like an OK solution, but I haven't tried this yet because it also seems like this is a bit of a strange workaround. It seems wasteful to have an "ability" which does nothing except modify some numbers on my pawn completely irrelevant to the ability system, like not adding any tags or effects. Or is this actually the right place? Would this be the place to also do things like have a slow/snare type effect and adjust the pawn's movespeed to 0? Should I not think that this is wasteful, and that an "ability" is just another word for "event" or "function" ?

    So currently I'm looking at building my own global event system, and then adjusting the code in my AttributeSet::PostGameplayEffectExecute to publish a global event whenever a health attribute is changed, including the amount changed, the target, and the instigator. This seems solid since it would work for both healing and damage, and I wouldn't need to go around hardcoding all of my damage variables. My AI controllers would then subscribe to these events and they can go about their way. Does this seem like a feasible solution? Or is their something else already built-in which might work well, or would allow me to react to events like changing health? Am I totally misunderstanding Gameplay Events here, with that being the actual ideal solution? What I don't want to do is spend a bunch of time coding something only to find out it's been done/couldlve been done better elsewhere.

    Honestly I just wanna jump back in and start experimenting/coding more. But I've already put in way too many hours and lost enough sleep over it (with angry SO and work tomorrow too), so I'll have to call it for tonight. Again, I can't explain how much I appreciate this thread and everyone's time contributing and helping out here. This system is really something special and has re-ignited my passion with UE4. Hopefully I can pay everyone back by releasing a fun game for us all in the future.

  15. #95
    0
    Don't beat yourself up over not being quite getting into the system's flow. It's difficult to grasp what's the best way to do each thing, and if it were all obvious and easy, I wouldn't have arsed myself to write so much about it.

    Quote Originally Posted by Zerve View Post
    In the last four-ish hours or so I've been trying out some really stupid stuff (partly due to my brain turning to jelly, and also because there are almost no other resources for the GameplayAbilities system). Some of the dumb this I've considered/tried are:

    Have one point of damage be represented by a single stack on the ability system as a gameplay effect. IE, player 1 deals 100 damage, the AI gains 100 stacks of Effect A, player 2 heals 50 damage, the AI gains 50 stacks effect B. There's a nice feature in here where the stacks can be independent by owner/actor. This fails because I couldn't figure out a way to have a single ability place multiple stacks. Obviously, I could've hard coded each ability, so ability A, does 100 damage, loops and applies the "threat/aggro" effect 100 times. But I couldn't find any way to actually grab the "damage amount" from the ability nor the effect. There is access to the "modifiers" field on gameplay effects, but couldn't get the value, so everything would need to be hardcoded. Not only that but, I didn't remember finding a way to actually "get" who owned which stacks. If A has 100 stacks, and B has 50, I couldn't really get that info, only that there are 150 stacks in total.
    Hm, how come you can't figure out how to apply multiple stacks of an effect in a single call within an ability? Just use the ApplyGameplayEffect functions within the Ability blueprints, you can either just apply a regular GameplayEffectTemplate with some details on the level/cooldown of it, or create GameplayEffectSpec first, change up some more specific parameters(such as duration, added tags) and apply that.

    That being said, this solution strikes me as a tad odd anyway. I mean, I guess you could represent aggro via some hidden buff stacks that builds up depending on healing/damage done, but then I'd probably put that logic right into the GameplayEffectExecutionCalculation responsible for damage/healing, because then each time you deal damage/heal it applies these automatically. Could even have the damage execution apply aggro counts to monsters that entice them to target characters that recently healed them. I'm not sure how performant the trick may be depending on how many individual GameplayEffect stacks you'd have to govern, but that's more because I don't try to juggle with active gameplayeffect structs yet so I don't know how well the system deals with excessive amounts of stacks. You'd probably have to do such a thing for UI purposes anyway, so I would think someone had the foresight to make iterating through the buffs somewhat efficient, though. You'd have to try it, actually. FGameplayEffectQuery might help with that, seems to be a struct you can use to filter your active GameplayEffects by. Use it with GetActiveEffects(const FGameplayEffectQuery& Query) and you should receive all active effect handles that pass through the filter.

    Getting who applied the effect is fairly easy, GameplayEffects tend to keep their EffectContext around while they're applied, which pretty much describe where they came from. GetEffectContextFromActiveGEHandle should give you a handle containing the context when you use the active gameplay effect handle in question as parameter.

    Quote Originally Posted by Zerve View Post
    Tick every second to check for a changed health attribute. This seemed like a lame hack to find out whenever I took damage. It would be easy to implement and I could move on to other features quickly. Except there wouldn't be a way to know who actually did the damage to the character. I'd easily know I took "X" damage, but from who? Quick and dirty. Obviously can't do this.
    You can actually use a delegate provided by RegisterGameplayAttributeEvent(YourAttribute) to make it so that you can call a function every time an attribute is changed. This not only cleans up the process and lets you avoid using the Tick function like a scrub, but it also provides you an FGameplayEffectModCallbackData as parameter to use in the function you wish to bind into that delegate. The CallBackData struct contains the spec of the GameplayEffect(and as such all the contextual info you'd need to derive the instigator/causer/whatever of the damage from) and some other useful info such as what kind of modifier is being applied(additive, multiplicative, by how much?) and which Ability System is being targetted(which granted is usually obvious, because you only bind yourself to that one ability system with that function).
    Do be careful though that the FGameplayEffectModCallbackData is a pointer, and not always valid. I know modifiers without a GameplayEffect attached to them will fire the function without a CallBackData, but there may or may not be more instances. You should always check if the Data is valid before you access it, but then again, you should pretty much always check if pointers are valid anyway.

    Quote Originally Posted by Zerve View Post
    Using the "Display" part of an effect with a Gameplay Cue. This is something which I'd like to learn more about, but from all my research and looking around, it seems like this is only intended for graphical things, not actual game logic. Similar to the stacking effect, I could write some short and sweet blueprints to adjust each of these. Also similar to the stacking effect, this could get unwieldy with a large number of abilities, since the actual amount of damage would again need to be hardcoded for each individual ability. I also just felt unsatisfied with this solution, since all the documentation says "for visual effects."
    Binding anything gameplay-related to a GameplayCue is a nice way to screw yourself over, because they don't really replicate in a way that'd be desireable for actual gameplay logic. In fact I'm not even sure if they replicate at all, the game may actually just replicate/multicast the tag you wish to call a GameplayCue from and every client's kinda responsible for their own cue. It's also just kind of a weird detour to take for gameplay logic, you're pretty much calling an unknown function that's assigned to the tag you put in as parameter, and you only have limited options in what to put in as parameter.

    Quote Originally Posted by Zerve View Post
    Gameplay Events sounds like the perfect solution! But all I can't find any examples of how to use this with my desired system. The tutorial mentions how to trigger other abilities, is this the only use of this system? Can this event be written like a blueprint event node? Like, send this event to my AI controller with the payload, then do some logic based on that? The lifesteal example makes perfect sense to me, and so would a kind of thorns effect (reflect flat or x% damage back to the attacker), or even a "counter" or reflect style of move which just bounced the ability back at the caster (sounds fun right?). My only idea from that information is to give my AI characters an "ability" which when activated does all the aggro/threat table logic I mentioned before. This seems like an OK solution, but I haven't tried this yet because it also seems like this is a bit of a strange workaround. It seems wasteful to have an "ability" which does nothing except modify some numbers on my pawn completely irrelevant to the ability system, like not adding any tags or effects. Or is this actually the right place? Would this be the place to also do things like have a slow/snare type effect and adjust the pawn's movespeed to 0? Should I not think that this is wasteful, and that an "ability" is just another word for "event" or "function" ?
    There's an AbilityTask that listens for Gameplay Events, so that usually means that by extension there is a delegate you can use for listening to them, too. This system loves its delegates(not that I'm complaining). Poking about reveals that GenericGameplayEventCallbacks seems to be it, it's a public TMap in AbilitySystemComponent that maps a tag to a FGameplayEventMulticastDelegate, which is a multicast delegate that offers the FGameplayEventData itself as variable. Just remember to use FindOrAdd with the map, because you don't actually know if there's a fitting delegate in the map already, and you don't want to try to bind to an invalid delegate/accidentally reset a delegate other functions may already be bound to.

    I'd argue you'd ideally want your AI to be able to stand on its own feet, so I wouldn't want to add an extra ability concerned with listening to GameplayEvents just to make it work. That being said, if something is stupid but works, it probably isn't that stupid. I don't think there's a big difference between binding a manager ability to your GameplayEvent of choice, making it wait for one using an AbilityTask or just cutting the middleman and binding the delegate to whatever is supposed to control your Ai.

    Quote Originally Posted by Zerve View Post
    So currently I'm looking at building my own global event system, and then adjusting the code in my AttributeSet::PostGameplayEffectExecute to publish a global event whenever a health attribute is changed, including the amount changed, the target, and the instigator. This seems solid since it would work for both healing and damage, and I wouldn't need to go around hardcoding all of my damage variables. My AI controllers would then subscribe to these events and they can go about their way. Does this seem like a feasible solution? Or is their something else already built-in which might work well, or would allow me to react to events like changing health? Am I totally misunderstanding Gameplay Events here, with that being the actual ideal solution? What I don't want to do is spend a bunch of time coding something only to find out it's been done/couldlve been done better elsewhere.
    I gave you some options now. Bottomline is that binding it to GameplayEffectExecution may probably be the easiest and most ideal solution, however you can either combine this with other solutions to spare yourself from writing up an extra system just for that, or you can just use delegates, some of which I've mentioned here, for a more global but perhaps less controllable solution.

    Quote Originally Posted by Zerve View Post
    Honestly I just wanna jump back in and start experimenting/coding more. But I've already put in way too many hours and lost enough sleep over it (with angry SO and work tomorrow too), so I'll have to call it for tonight. Again, I can't explain how much I appreciate this thread and everyone's time contributing and helping out here. This system is really something special and has re-ignited my passion with UE4. Hopefully I can pay everyone back by releasing a fun game for us all in the future.
    Good luck my dude!
    Last edited by KZJ; 06-26-2017 at 09:28 AM.

  16. #96
    0
    Supporter
    Join Date
    Jun 2015
    Posts
    4
    Quote Originally Posted by KZJ View Post
    snip
    Thanks for the feedback. There are a lot of really good points in there and it's still hard to make a final decision on what to do! But I've narrowed it down to a couple different ideas on architecture and can hopefully decide and start implementing it once I get a good block of time (working full time + freelance sucks). Sorry if this reads like a personal dev blog, but I'm possibly someone else might go through a similar issue and might want to see me thought process.

    This is for developing an "aggro/threat" table type of mechanic, similar to many RPG games. MMO's often use this kind of system.

    Bad Ideas:
    Aggro as a 'stack' of an effect - That idea was just dumb.
    Ticking like a scrub to check a changed attribute - This is completely outclassed by using "RegisterGameplayAttributeEvent(YourAttribute)" instead.
    Using display and gameplay cues - Due to wonky replication, it would be bad to put gameplay related code in here (as mentioned in other places too).
    Rolling my own global event system - There seems to be enough things built in to the gameplay abilities module that this isn't a smart thing to do. I'd rather not start spaghettify my systems and locking them all together. But I might have to do a little bit of this for the best contender anyway.

    Not so good:
    RegisterGameplayAttributeEvent - This seems like a pretty simple and straightforward approach, but it also seems like it would be very limited. I'm assuming that in order to set this system up, I would need to have each AI subscribe multiple different attributes attached on different systems. In the case where I have, say, 2 characters attacking a single NPC, the NPC would be listening for his "health changed" event, and use that to increase the threat for the NPC that caused it. Seems find and dandy... Until I throw healing and buffs into the mix. If player 1 heals player 2, the NPC needs to know that player 2's health has changed. So I'd need to then make the NPC subscribe to player 2's "health changed" event, and in the same regard player 1's event as well. This could get pretty ridiculous if I have, say 6 NPC characters against 5 player characters. A lot of unnecessary subscriptions (in that case, (6 npc * 5) 30 just for the healing case, and then 6 more for their own "damage taken" aggro calculations). If my game had some kind of team wide attack speed buff, or a slow debuff, which deals zero damage, I would have to add a bunch more listeners and it just gets kinda crazy at this point. Does this sound about right? If it is, I'm definitely leaning no for this as my system. I'd be better off just listening for other "ability events" or even "effects resolving" kind of thing.

    GameplayEvents - It seems like its OK still, a bit of a workaround and I definitely agree that I wouldn't want to tie a bunch of abilities to my AI just to get them to "listen" to threat. I definitely could see this working, but seems more like a hack, and just not as good as another option. Still leaning no on this.

    The Best Contender:
    GameplayEffectExecution, and publishing those messages - This was suggested by KZJ, and also a user in the Unreal Slackers discord "inside." And the more I look into it it seems to get better and better. Because everything in a GameplyAbility heavy game is done through effects and attributes, this gives me a solid "entry point" to start throwing some messages around the game and reacting to them in various ways. This also lets me create a complex "threat" calculation, similar to a damage one, which would cover all kinds of different abilities including nukes, AoE, heals, and even 0 damage effects like temporary buffs, taunt-style effects, and the like. Each ability can have a bunch of attributes within which when combined can produce a single float for threat. Something like:
    Code:
    threatToAdd = (TotalAbilityDamage * DamageThreatModifier) + (FlatThreat * FlatThreatModifier) * CharacterThreatModifier;
    Or whatever kind of crazy calculation I decide to put on there. So a fireball is flexible, and can deal 300 damage and make 300 threat, and an attack speed buff can deal 0 damage, but still make 500 threat. Heals can be added into the equation super easily. That value can then be broadcast (including source and target data too) to all relevant AI's and they can then react accordingly.

    What makes me pretty happy about this solution is how easy it would be to expand upon it in the future. I could very easily implement a kind of "combat log" by grabbing messages controlled by the player, or even a "what killed you?" kind of popup you often see in MOBA's showing you what happened moments before you died. Overall I think this is the most elegant solution, and provides me with the least amount of duplicating code for whatever edge cases might appear (if any).

    If I do decide to go with GameplayEffectExecution (which I probably will at this point), the next challenge will be incorporating the messaging/events. There doesn't happen to be any built in messaging system in here, hidden somewhere deep in the GameplayAbility module?

    If not, fortunately that's something which is already clearly documented and has other examples available .

Page 3 of 3 FirstFirst 123

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •