Ricocheting impacts that speed up over time

I went down a rabbit hole of Googling to get this to work, and ended up making my own sounds in Ableton to fit it haha. For example to start working towards a ricochet effect, I eventually found there’s an FMath::GetReflectionVector, after testing out a lot of other approaches. I never went to college and everything I know about Vectors I’m learning right now as we speak so even figuring out that I needed to search for “reflection” or mirror took me a bit.

This is all a line trace, timer delegate and timer handle in a Bounce function recursively calling itself with that handle/delegate combo until we hit our max bounces setting. The delegate and timer is so all the bounces aren’t instantaneous, and also allows for cool things like building up speed over time with each bounce. We just remake the delegate each time inside Bounce(), with updated parameters/values for the Bounce function we’re calling.

If you notice, the rotation of the particle emitter is always matching which way the ricochet is going too.

1 Like

Awesome job for figuring this out. What was the process from having the problem to getting the solution?

1 Like

Ah, asking the right question lol. Now I gotta elaborate because it was a lot of steps of improvising and Googling.

First we learn how to do a line trace to hit an object/point, and also spawn a particle effect. I picked and altered an impact effect that had a sort of liquid explode from one angle. But since the particle spawns at random rotations, sometimes the liquid effect would gush out, and other times it would go sideways or completely disappear behind the wall.

So then I realized you can specify the rotation when you spawn the emitter. So I wondered if I could get a rotation based on the surface we hit. I vaguely remembered normals had something to do with surfaces, and in our “FHitResult Hit” variable, after using Rider to scroll through the list of suggested members, there just happens to be a member variable for it named ImpactNormal. I figured that might be where I want to start.

So I repeated that step and used Rider to suggest to me more members on ImpactNormal, because I could see it was some type of Vector but I don’t know what “FVector_NetQuantizeNormal” actually means. But I noticed that ImpactNormal had a Rotation() method, so that’s exactly what I could use to set the rotation of the particle emitter.

So at that point after some testing and adjustments, I had a particle spawning where it always shot outwards from the surface it hit. But then I though well, if I’m hitting a surface at an angle, shouldn’t the particle really be bouncing at a mirrored angle anyway like a ricochet?

So I had to figure out, how do I get the mirror of the impact direction of our shot, and use the ImpactNormal as a surface? What does that even mean for vectors? How do you mirror vectors? I don’t know any of this. I barely understand what vectors are!

So I ran through a short math article online about vectors, and another youtube video explaining how to mirror vectors and get a mirror of a point based on a reflection plane. Well there’s the word I needed, reflection.

So after more Googling, I found FMath::GetReflectionVector, and it allowed me to pass in our direction vector, and use the impact normal as the plane to reflect from.
image

Then I could just grab its rotation, then convert that to a vector with .Vector() to get it’s direction (things we learned in this course already so far). Okay, so now we’ve got a mirrored direction of our impact. Let’s go!

So to make something bounce, I figured you’d have to do an identical line trace, but now your end point from your initial shot is your new starting point from that same point you just hit, and your new direction is the mirror of the previous direction.

So this is all in a “BounceImpact()” method. So how do I pass in subsequent bounces into itself?

Well, really you can just call it recursively, starting with the direction and point of your initial player shot, then pass in the new start point and new direction in subsequent calls and calculate the next new point and direction and pass it in again and again until you reach your desired bounces.
image

So I did that, but it was all instantaneous and I couldn’t tell how well it was bouncing around. So I wanted to add some sort of delay before the next recursive call to this function, so that it would look like it’s actually traveling. I figured you can’t just add a delay in the code since it’ll pause the entire program, but we did learn about Timers and Delegates earlier, so I did some more Googling.

What I needed was a way to bind our Bounce function to a delegate so we could call it on a timer after a delay that is run on its own thread so it doesn’t stop our program (whole point of Timers and Delegates for them, I think), that also lets us pass in parameters, because we update the parameters for every bounce. We haven’t learned how to delegate functions with parameters yet, but I found this asked about on UE Answers, so I implemented that.

// Setup timer delegate so we can make a sort of delayed ricochet bounce by calling this again.
// Recursive calls means updating the parameters/values with the new bind.
RicochetDelegate.BindUFunction(this, FName("BounceImpact"), StartLocation, RicochetDirection);

// Our recursive loop and base case.
if (RicochetBounces < RicochetMaxBounces) {
	RicochetBounces += 1;
	// Slowly speed up the bounces as we go on.
	RicochetBounceDelay *= RicochetBounceSpeedGrowthFactor;
	// Call this function again after a short delay, with updated parameters.
	GetWorld()->GetTimerManager().SetTimer(RicochetTimerHandle, RicochetDelegate, RicochetBounceDelay, false);
}

And we did it!

Privacy & Terms