How to properly create a Dash ability?

Hello,

I've been using the code below as a dash ability, but the problem is when the speed multiplier is bigger than 15 and I walk up on a ramp the collision messes up and my character stutters for a second (like it's going underground) and then resumes the dash. Another problem with the code below is that it requires movement to use the ability as its just modifying the input vectors.

Is there a better solution to create a dash ability?

Here's a link to the code: https://pastebin.com/cPaLyAA0

If I increase the speed multiplier even more to like 50, I fall through the ground. The same thing could be replicated if you increase the Speed Change's ability Speed Change Multiplier and min/max value to 15.
 
Last edited:

Justin

Administrator
Staff member
Do you have the Agility Pack? You could use the dodge ability as an example. The dodge ability movement is driven by the animation and uses the built in collision detection.
 
Do you have the Agility Pack? You could use the dodge ability as an example. The dodge ability movement is driven by the animation and uses the built in collision detection.
I don't have the agility pack, but what do you mean driven by the animation? I'm not planning to drive the movement by the animation since I don't have a dash animation. What are other ways to make a dash and solve this problem?
 

Andrew

Moderator
Staff member
Instead of directly modifying the InputVector, there are a couple of different approaches you could try, as suggested in a couple of other threads on the same topic:

Using the state system to temporarily increase the character's speed by a much higher factor: https://opsive.com/forum/index.php?threads/swift-dash-ability.3851/ (and maybe also temporarily disabling the character's rotational input so they can't turn during the dash, etc.)

For a more manual, controlled approach - setting the character's MoveDirection every frame to move them towards a set target: https://opsive.com/forum/index.php?threads/dash-ability.2409/
 
Instead of directly modifying the InputVector, there are a couple of different approaches you could try, as suggested in a couple of other threads on the same topic:

Using the state system to temporarily increase the character's speed by a much higher factor: https://opsive.com/forum/index.php?threads/swift-dash-ability.3851/ (and maybe also temporarily disabling the character's rotational input so they can't turn during the dash, etc.)

For a more manual, controlled approach - setting the character's MoveDirection every frame to move them towards a set target: https://opsive.com/forum/index.php?threads/dash-ability.2409/


The problem is that when I increase the character's speed (Motor Acceleration Vector3), the collision breaks and the character goes underground. I've tried using AddForce as well and same result - the collision breaks and my character goes through objects.

Please check out this video to see the problem: Link

I increase the motor z acceleration to 2 or 1.6 as that would be a good value to make a dash, but the collision uphill breaks.
 
Last edited:

Andrew

Moderator
Staff member
Hm ok the collision breaking looks like a separate issue - are you able to reproduce it in the demo scene at all? I trried increasing the motor acceleration on Nolan in the demo and couldn't see any issues with collisions.
 
The collision breaking is the only issue I have and yes I'm able to reproduce it in the demo scene, please take a look: : Link
 
Last edited:

Justin

Administrator
Staff member
The collider shouldn't be stopping like that. I can take a look at that for the next update. I'll let you know what I find out.
 
The collider shouldn't be stopping like that. I can take a look at that for the next update. I'll let you know what I find out.

Please take a look and update me as soon as you find anything. I'm in a big rush.. Currently the only way to get around the issue is to decrease the fixed timestep (from the project settings/time) from 0.02 to something like 0.005 (the lower the better the collision detection is), but even a slight decrease to say 0.01 makes the whole movement feel very bad and unpredictable, so I'd rather not mess with that settings and keep it at 0.02.

Honestly, I will be happy even for a solution that gets activated during my Dash ability, if it's gonna take a bit more performance to calculate the collision better, because obviously my character isn't running with such a high speed all the time, only when dashing or equipping certain items (speed boosters).
 

Justin

Administrator
Staff member
I've been debugging this and think that I found a fix. Within MathUtility change line 360 from:

Code:
if (segment >= 0 && segment <= 1) { // On cylinder.
to:
Code:
if (segment >= 0 && segment <= 1 && (!lowerPoint || capsuleCollider.transform.InverseTransformPoint(point).y < 0)) { // On cylinder.

This will allow the grounded check to get the closest collider position on the ground rather than the edge. Let me know if that works for you and if so I'll include it in the next update.
 
I've been debugging this and think that I found a fix. Within MathUtility change line 360 from:

Code:
if (segment >= 0 && segment <= 1) { // On cylinder.
to:
Code:
if (segment >= 0 && segment <= 1 && (!lowerPoint || capsuleCollider.transform.InverseTransformPoint(point).y < 0)) { // On cylinder.

This will allow the grounded check to get the closest collider position on the ground rather than the edge. Let me know if that works for you and if so I'll include it in the next update.

This works way better than before with the previous speed I was using, I've only noticed a couple of times the character going through colliders. I increased the speed to 2x as much just to test and you can see on this video how the character goes through colliders. I'm not sure what can be done about that, but I've seen in assets for car controllers where they move with high speed that they don't clip through any colliders.

Video link.
 

Justin

Administrator
Staff member
Can you tell me how to reproduce it within the demo scene? What speed and what is the slope of the plane?
 
Sure, as I said it works with much lower values but happens rarely, so just go to the Speed Change ability in the demo scene and increase these 3 values to 100, it's going to clip through terrain and other colliders you have in the demo scene.

I personally increase these 3 to 50 for my dash, but as I said it happens rarely, but with 100 (which can also work for a dash) you will see it right away.


values.png
 

Justin

Administrator
Staff member
Thanks. The problem is that the character is ignoring that collider because the slope is less than the slope limit and the character then passes right through the object. The solution is be to run multiple collision checks within a single frame, but that will take a lot more thought to get right. I am planning on switching over the the Unity job system for collision detection later this year and it makes sense to group this in with that. In the meantime the best option is to slightly reduce the fixed timestep and adjust your parameters to work better with that new rate. I wish that I had a better immediate answer.
 
I won't bother with these physics settings, because I will have to get them back to normal when you switch the collision to work with the job system and fix that issue. I can wait a few months and work on other stuff, hope you manage to solve it or at least have a feature that when turned on does multiple collision checks.
 
Hello,

I will post a temporary solution for anyone who is looking to make a dash, it still clips through objects, but rarely and when @Justin fixes the collision system we are going to have a full solution.

But first I want to ask about something else which I've struggled with and it's dashing when you are on edge. It seems to shoot the character with a huge force and make that dash so much more powerful. I've been trying to find out what's causing it during the weekend, but no luck. Can we somehow stop this acceleration when the dash ends?

Take a look at this video.
 

Justin

Administrator
Staff member
You can call m_CharacterController.ResetRotationPosition to stop all movement immediately.
 
You can call m_CharacterController.ResetRotationPosition to stop all movement immediately.

I've tried this suggestion and there are two problems

1) I think when we are in the air the character falls way faster straight down than normal, maybe it has to do with stopping Airborne acceleration, but definitely feels off
2) You can see right after I jump and dash, there's an undesired effect thats produced as if the character is rendered twice, maybe its caused by camera stuttering. Calling "_cameraController.PositionImmediately();" makes that effect go away, but then the camera is reset to the default state and moves right behind the character in the middle even if I'm looking up or to the side.

I think just halting the forward momentum would be nice or doing it slowly instead of right away.

Here's a video where I compare a normal fall and a fall after dashing: Link.

Do you have any other suggestions?

Edit:
What I've tried instead of ResetRotationPosition is using SetPosition in AbilityStopped like this

protected override void AbilityStopped(bool force) { base.AbilityStopped(force); // Other Code.... m_CharacterLocomotion.SetPosition(m_CharacterLocomotion.transform.position, false); }

The problem this caused is if you keep spamming the dash button and have 0 cooldown on the dash ability the character will stay in air. I checked what SetPosition does and more importantly it's call to base.SetPositon and found out that it does this

m_GravityAmount = 0;

If I remove this line, then I can't see the same problem happening, but of course I don't want to edit your code, so I want to ask:

1) Why the gravity has to be set to 0 when we call SetPosition? Is it safe to ignore this line?
2) Can you provide an option to not set the gravity to 0 (maybe in the method arguments), if it's safe to even do that?
 
Last edited:

Justin

Administrator
Staff member
Before setting the position I would save off the GravityAmount and then reapply it after you set the position. The gravity is reset because when you instantaneously move the character the previous gravity values are no longer relevant.
 
This code below works very well so far executed in the AbilityStopped method.

var gravityAmount = m_CharacterLocomotion.GravityAmount; m_CharacterLocomotion.SetPosition(m_CharacterLocomotion.transform.position, false); m_CharacterLocomotion.GravityAmount = gravityAmount;

Right now what I do to make the collision detection a bit better is when the ability starts I change the Time.fixedDeltaTime to 0.01333f and then back to 0.02 when the ability stops, you can't feel the difference while playing. It works in about 95% of the cases, but every once in a while I will get stuck in a collider or fall through the terrain. I will be keeping an eye on the controller updates and look forward for the collision detection rework!
 
Top