Need help with dashing forward

I am using the first person template and have been trying to get a system to dash forward to work. It sort of works. Basically I want to move 800 units in the forward vector while not losing height.

Current problems are:

  • if dashing off a cube, despite gravity being disabled, the player will still slightly drop for some unknown reason. The speed (100.0f) is very slow for demonstration purposes.
  • If dashing up a slope, the player will rapidly accelerate and the conditional checking when to stop moving is never reached (where the comment “if we can move at least 100 units” is). I can sort of fix this by keeping track of total distance traveled, and if it’s more than the maximum dash distance abort. I think the rapid acceleration happens as soon as they are off the slope. So, friction is taking effect I guess and slowing it down until they are off the slope in which case it travels at the “true” speed. Still it is rather confusing to me how friction is still in effect despite my setting an absolute position…
  • It currently dashes down slopes. This is undesired behavior. I think dashing up slopes is also technically “undesirable”. Anyway instead of dashing down the slopes angle they should dash outward, perpendicular, according to the forward vector. So I’m rather confused why the dash actually matches the slopes angle. This might be a fundamental misunderstanding I have of the forward vector…


void ACleanerCharacter::Tick(float DeltaSeconds)
{
	if (bDashing)
	{
		// If we can move at least 100 units
		if (FVector::Dist(GetActorLocation(), targetDashLocation) >= 100.0f * DeltaSeconds)
		{
			// Move 100 units
			if (SetActorLocation(GetActorLocation() + (dashDirection*100.0f*DeltaSeconds), true) == false)
			{
				// If we failed sweep (hit wall), stop dashing
				bDashing = false;
				this->GetCharacterMovement()->GravityScale = 1.0f;
			}
		}
		else
		{
			// Set location to target location, stop dashing
			SetActorLocation(targetDashLocation, true);
			bDashing = false;
			this->GetCharacterMovement()->GravityScale = 1.0f;
		}
	}
	else
	{
		// Reset if we land
		if (this->GetCharacterMovement()->IsWalking() && !this->GetCharacterMovement()->IsFalling())
		{
			bCanDashForward = true;
		}
	}
	Super::Tick(DeltaSeconds);
}

void ACleanerCharacter::OnDashForward()
{
	if (bCanDashForward)
	{
		GetCharacterMovement()->GravityScale = 0.0f;
		GetCharacterMovement()->StopMovementImmediately();
		dashDirection = GetActorForwardVector();
		targetDashLocation = GetActorLocation() + (GetActorForwardVector()*800.0f);
		bCanDashForward = false;
		bDashing = true;
	}
}

One easier way to control the movement, would be to add a force, not to use teleportation. Although you might have a hard time controling the speed should the character go down or up a slope.

I would offer an architectural advice:

  • Use events instead of setting up the code all at once in tick. E.g., have a OnWallHit triggered event, where you check if the player is dashing, if so, stop him. And so on. Makes the code a bit cleaner and easier to handle. Additionally, makes it easier to accomodate new ‘skills’. Same for OnLanded() etc.

Do try using force adding and not teleportation and let me know if it makes a difference. The OnWallHit event would suffice to prevent going upward slopes - you merely check the event and stop the dash. As for going down… well, since you want to cap height then this shouldn’t be a problema, down will never occur.

Quickly looking at the code, and this might be a dumb question(idea, but shouldn’t you set gravity scale to 0.0f ? Thus effectively disabling grav.

PS- Boolean variables should ask questions to make it clear what the variable’s value refers to. Consider changing “bDashing” to “bIsDashing”.

I would still be calling that from Tick, unless you are thinking of a built-in event and got the name wrong. Landed happens to already be built out in ACharacter which I override/overload whatever the right terminology is. It was not triggering in all cases (I forget the odd circumstances). But yes I’m not opposed to making more functions but this is prototyping the movement system so there’s not much

SetActorLocation provides a parameter to check for collisions which I do. It doesn’t appear to work with the upward slope for some reason. Perhaps it does very limited raycasting or just simulates physics of the frame without setting the location. However it does work with traditional walls.

Well technically this system is not teleportation either. It works similar to Genji’s dash (from Overwatch) except you can only move forward, not an arbitrary direction. And yes I did try using the physics system but it did not provide the results I wanted. Mainly, the extreme speed (Instead of 100.0f I use 2500.0f normally) and there being acceleration.

Right, but I cannot figure out why it doesn’t work correctly. The forward vector should not have rotation (or so I thought) so why it doesn’t work the way I expect is a mystery.

That is done in void ACleanerCharacter::OnDashForward() (scroll the code box)

Been trying to get better at that :wink:

Be aware that what you’ve done there won’t work with Multiplayer, if that’s your intention.

Adding movement code to the character is best done in the movement component, in your case probably by overriding Phys_Walking() and adding your extra functionality. If you want to do multiplayer, you’ll also probably want to look at adding control flags to the prediction data as well.

In all honesty this isn’t particularly easy to do, but you could look at Unreal Tournament source code and see how they have handled adding Dashing. Character Movement has a LOT of edge-cases you need to think about usually.