Let’s say I’m playing a mage and I cast a meteor ability. After a short delay, the meteor crashes into the ground and damages all enemies in an area. Simple, right? But I can’t find anywhere a way to handle this. Something like an AnimMontage, where I can place the meteor Niagara system and add events to deal damage, play SFX and such.
I think I’ve looked at every single tutorial ever made, and they all either only show basic abilities with timings set in the AnimMontage itself, use collision based projectiles, hardcode timing values, or even worse. There must be an alternative, right? Any suggestions? Thanks.
So I would say the way to go about this is to use a Sphere Cast by Object
I’m not sure how your game is set up, so I can’t suggest how to get the location for the meteor fall. But I’d say do your sphere trace looking for (enemy class) in the array of objects to seek, then a foreach loop for all hit actors to do damage. You can also Spawn System At Location for your Niagara effect! Of course you can put all of this on timelines/delays to get your desired timing correct.
I hope that helps! If you need more I’ll need more info, and remember, a picture is worth a thousand words, so bring screenshots
I know how to set a hitbox and find the enemies that should be hit, but I don’t know when to do that. After the skill is cast, there’s a little delay where the skill animation is warming up for impact. So I’d need some sort of timeline to fire the event exactly when the lightning bolt strikes, as well as setting up proper timing for SFX. This is easy to do in an AnimMontage, but in this case the spell effect has nothing to do with the caster’s animation, so I couldn’t do it that way.
Another maybe better example would be stepping on a trap that explodes after a short delay. Sure I can hardcode the delay, but that’s what I’m trying to avoid! It might explode multiple times, having multiple micro hits, and then there’s SFX on top. Manually setting these timings would be a pain.
Is there no better alternative, though? It seems like a horrible workflow to use Timelines like that. In Unity I could use their implementation of a Timeline, for example:
You can preview and properly time SFX and events with the VFX animations. Look at the amount of SFX he’s using in this simple example - doing that in UE’s timeline sounds like pure pain. And then there are skills with even more complex timings, like this for example:
Niagara itself has a pretty nice “Timeline” with good previews, but it can’t be used for any of this afaik.
Anim montages are kindof meant to help with timing though. You can place a branch point so it’s way more precise than a normal notification.
The branch point can determine when in your animation you want the action to occur which you probably want most of the time or else your game actions aren’t in sync with the animation.
I also actually have some extra functions on top of montages to set their play rate based on the time I want the montage to play. This way I can tweak timings of actions in the game and make the animations play correctly on the fly. It’s like the best of both worlds, all things are animation driven and actions line up with what the animation is doing, but I’m also driving the timings directly with outside data.
This function should help figure out montage play rates:
float FRDBaseUtil::GetAnimMontageRateForDuration(UAnimMontage* AnimMontage, float Duration, FName Section, bool bAccountForBlendoutTime)
{
if (Duration > 0.f && AnimMontage)
{
if (Section != NAME_None)
{
const int32 SectionIndex = AnimMontage->GetSectionIndex(Section);
if (SectionIndex != INDEX_NONE)
{
return GetAnimationRateForDuration(AnimMontage->GetSectionLength(SectionIndex), Duration,
bAccountForBlendoutTime
? AnimMontage->BlendOutTriggerTime
: 0.f,
bAccountForBlendoutTime
? AnimMontage->BlendOut.GetBlendTime()
: 0.f);
}
}
return GetAnimationRateForDuration(AnimMontage->GetPlayLength(), Duration, bAccountForBlendoutTime
? AnimMontage->BlendOutTriggerTime
: 0.f,
bAccountForBlendoutTime
? AnimMontage->BlendOut.GetBlendTime()
: 0.f);
}
else
{
return 0.1f;
}
}
/**
* Helper to get the animation rate for an animation if you want it to take a specific duration
*/
static FORCEINLINE_DEBUGGABLE float GetAnimationRateForDuration(float OriginalDuration, float Duration, float BlendoutTriggerTime, float BlendoutTime)
{
if (BlendoutTriggerTime >= 0.f)
{
OriginalDuration -= BlendoutTriggerTime;
BlendoutTime = 0.f;
}
if (Duration > 0.f && OriginalDuration > 0.f)
{
return OriginalDuration / (Duration + BlendoutTime);
}
return 0.1f;
}
The biggest difference here is you’re looking at it as if it were the character doing the animation for the spell effect, not the cast, and I was looking at it as the spell being a spawned actor all by itself.
Looking at it this way, what unity calls a timeline here is an animation montage. Notice that the video says nothing about when the damage goes out or how to damage the enemies, purely looks only, because it’s a bit more complicated.
So on your character BP you’ll use the PlayMontage node, and select your spell.
You’ll also need to send whatever targeting data you need to your Anim BP and set it as a vector variable on the Character BP and the Anim BP right before the PlayMontage.
On the montage itself you’ll pass in your vector, and then on that location put your Niagara effects, and use an animnotify for the functionality of the target damage.
Then use TryGetOwner on the ABP event graph to send that notification to play an Event on the character which would be your Sphere cast by Object> Do damage event on your vector you saved before your montage :).
None of this would use my above-mentioned timeline.