Having a non teleport dash
Hello!
I'm new with unity and i would really appreciate a little help if possible! :)
It's about a dash mechanic that i want to introduce to my game. I found a code on that forum and it works perfectly but in this case it's a teleport from point A to point B and it doesn't represent what i want. What i really want is to have a dash where you see the player moving like really fast from point A to point B without having the gravity influence it (couldn't implement that function even in that code : if you're on air the second point B will be either higher or lower than point A depending of when you pressed the dash button ) and not teleport from point A to point B. And i would like to have some particles popping all the way from A to B and not only on A and B ( On the code i use and since it's a teleport i get two particles popping : One in point A and one in point B).
Thanks, and have a good day! :D
Here is the part of the code i use to get a dash :
Answer by Evilhonor · Oct 15, 2019 at 09:10 PM
Here is the code ( i hope it will be clean (sorry i don't know how to post the code on the forum the way i see it )) :
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityStandardAssets._2D;
public class PlatformerCharacter2D : MonoBehaviour
{
private DashState dashState;
private float dashTimer;
public float maxDash;
public float dashLength;
private Vector2 savedVelocity;
public void Move(float move, bool crouch, bool jump)
{
//Movement control part of script
switch (dashState)
{
case DashState.Ready:
var isDashKeyDown = (Input.GetKeyDown (KeyCode.LeftShift) && m_Grounded == true); {
if(isDashKeyDown)
{
DashAnim.SetTrigger("dash");
GameObject clone = (GameObject)Instantiate (dashEffect, transform.position, Quaternion.identity);
Destroy (clone, 3f);
savedVelocity = m_Rigidbody2D.velocity;
if(m_FacingRight){m_Rigidbody2D.velocity = new Vector2(m_Rigidbody2D.velocity.x + dashLength, m_Rigidbody2D.velocity.y);}
else {m_Rigidbody2D.velocity = new Vector2(m_Rigidbody2D.velocity.x - dashLength, m_Rigidbody2D.velocity.y);}
dashState = DashState.Dashing;
}
}
break;
case DashState.Dashing:
dashTimer += Time.deltaTime * 3;
if(dashTimer >= maxDash)
{
dashTimer = maxDash;
m_Rigidbody2D.velocity = savedVelocity;
dashState = DashState.Cooldown;
DashAnim.SetTrigger("dash");
GameObject clone = (GameObject)Instantiate (dashEffect, transform.position, Quaternion.identity);
Destroy (clone, 3f);
}
break;
case DashState.Cooldown:
dashTimer -= Time.deltaTime;
if(dashTimer <= 0)
{
dashTimer = 0;
dashState = DashState.Ready;
}
break;
}
}
Answer by lgarczyn · Oct 16, 2019 at 08:14 PM
In most games, a dash is a teleport, but with a raycast so that you don't move through walls. A simple effect is added from the origin to the end.
You can use the ParticleSystem.Emit to spawn particles along the path of the dash, using a single particle system for the whole scene. You can also spawn particle systems from a prefab along the path as you are doing now.
Simply use a loop to Lerp from your original position to your end position, and spawn an effect each iteration.
Many games also use a kinematic rigidbody for the player, using a CapsuleCast for most of the collision logic. Won't help you here though.
But starting with your code, I can see a few problems:
You are not applying the gravity yourself, which means your rigidbody has useGravity set to true. Simply set it to false in the editor, and run this line if the state is different from Dashing.
m_RigidBody2D.AddForce(Physics2D.gravity, ForceMode.force);
This code
if (m_FacingRight) { m_Rigidbody2D.velocity = new Vector2(m_Rigidbody2D.velocity.x + dashLength, m_Rigidbody2D.velocity.y); } else { m_Rigidbody2D.velocity = new Vector2(m_Rigidbody2D.velocity.x - dashLength, m_Rigidbody2D.velocity.y); }
is bad for three reasons. First if you want the dash to be horizontal, keeping the y velocity won't do. If the character is jumping, he'll go diagonally upwards. Second, if the character is already moving, the dash will be faster than if he were standing still. Third, the dash won't actually reach a distance of dashLength, unless maxDash is 1f, which is quite long for a dash.
Lastly, very small problem, if the framerate is low, dashes might go further, because if the frame happens too late the timer will overshoot a bit. Hard to fix, except by moving the code into FixedUpdate, but you'll still need to handle the input in Update.
What you want is simply this instead:
float dashSpeed = dashDistance / maxDash;
if (m_FacingRight == false)
dashSpeed = -dashSpeed;
m_RigidBody2D.velocity = new Vector2(dashSpeed, 0f)
To have particles every frame of dashing, simply move the particle spawn line outside of the if(dashTimer >= maxDash)
block.
Hello! Thanks for your answer! :)
Starting from bottom : $$anonymous$$oving the spawn line outside of the if statement works! It generate multiple times the particles!
I tried to implement the code you gave me but it didn't work for me and then i took the y value off on $$anonymous$$e by only putting a 0 in it's place and it works, the dash is pure horizontal. The only issue i got is the "after dash " : what i got is that when the horizontal dash is finished; the previous mouvement i dit still counts ( like if i press shift just after pressing space to jump : the dash is horizontal but when it ends the player goes up. Is there a thing to cancel the previous movement and always make the player fall when the dash is finished?
And with the code i have the problem is still there : When i put big numbers for the dashLength the dash is through a longer distance but still instant, what i want is a dash that doesn't happen in two frames, for an example, i can give you Hollow $$anonymous$$night where you can see your character dashing and when they use the long upgraded dash ( even in the normal dash ), you see that it takes time to travel from point A to B and that's what i want in my game. An example in this youtube video : ( in the first seconds of the video )
That is what i want to implement :)
If you know a way to get that i would really appreciate ^^
To prevent a jump from continuing, simply do not restore the velocity after the dash, and set it to Vector2(0,0).
The reason my code didn't work for you and that your dash is still instant is probably because your maxDash var is set to 0, or a very low number.
Hello! Thanks for the answer again! I really appreciate :)
I did what you told me about the saved velocity and put it to new Vector 2 (0,0) and the after dash is just perfect as the way i wanted, thanks! :D
But about the instant dash, the variable maxDash in my case is set at 0.5 and it works as the delay between two possible dashes. Puting it to a greater value ( let's say 5 ) will only let you use the dash each 5 seconds. So the dash is still instant if i change this value.
$$anonymous$$axDash serves two purpose in your code, as the dash timer and as the dash reset timer.
You can fix that by replacing the maxDash in dashTimer = maxDash
by another car representing the cooldown timer.
Hello! Thanks for the answer! :)
I did what you told me : I made another float dashCooldown and set
`dashTimer = dashCooldown`
I made the value of dashCooldown to 0.5 and i'm able with that to dash every 0.5 seconds. For the maxDash, tried other combinaisons and found out that the line
`dashTimer = dashCooldown`
is just useless, took it off with two // and the dash still works as before, nothing changed.
So now the maxDash apprears only in if(dashTimer >= maxDash)
, changing that value lets me choose the cooldown for the dash. I think that the issue is in the line
`if(m_FacingRight){m_Rigidbody2D.velocity = new Vector2(m_Rigidbody2D.velocity.x + dashLength, 0 );}`
and the others like this one where it sets the
m_Rigidbody2D.velocity.x + dashLength
to make the RigidBody2D teleport. I found out that there are other commands like AddForce but i don't have a clue about how to implement them in my code :/
Do you think that the issue is here?
Thanks! :)
AddForce is basically just incrementing your current velocity by some amount, which is what you are doing now.
I really recommend changing
m_Rigidbody2D.velocity = new Vector2(m_Rigidbody2D.velocity.x + dashLength, 0 );
To
m_Rigidbody2D.velocity = new Vector2(dashLength, 0 );
This will prevent some dash from being longer than others.
The reason that the line was "useless" is because when that if statement is true, dashTimer will always be a bit more than maxDash. Having a dashCooldown allows you to set any value to the cooldown, ins$$anonymous$$d of the default maxDash (0.5).
Hello! Thanks for the answer! :)
I did what you told me and i changed the line, but i still have the issue of the instant teleport :/
Is there a way to get it the way i want in your opinion please?
Have a great day! :)
Hello! Thanks for the replies :)
So there is my full updated dash code :
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityStandardAssets._2D;
public class PlatformerCharacter2D : $$anonymous$$onoBehaviour
{
private DashState dashState;
private float dashTimer;
public float maxDash;
public float dashLength;
private Vector2 savedVelocity;
public void $$anonymous$$ove(float move, bool crouch, bool jump)
{
//$$anonymous$$ovement control part of script
switch (dashState)
{
case DashState.Ready:
var isDash$$anonymous$$eyDown = (Input.Get$$anonymous$$eyDown ($$anonymous$$eyCode.LeftShift) ); { // && m_Grounded == true); {
if(isDash$$anonymous$$eyDown)
{
savedVelocity = m_Rigidbody2D.velocity;
if(m_FacingRight){m_Rigidbody2D.velocity = new Vector2(dashLength, 0 );}
else {m_Rigidbody2D.velocity = new Vector2(-dashLength, 0 );}
dashState = DashState.Dashing;
}
}
break;
case DashState.Dashing:
dashTimer += Time.deltaTime * 3;
if(dashTimer >= maxDash)
{
m_Rigidbody2D.velocity = new Vector2(0,0);
dashState = DashState.Cooldown;
}
break;
case DashState.Cooldown:
dashTimer -= Time.deltaTime;
if(dashTimer <= 0)
{
dashTimer = 0;
dashState = DashState.Ready;
}
break;
}
Your dash is likely not instant, just very fast.
You need to increase maxDash to increase the dash time, while reducing dashLength, and changes these lines to:
float dashVelocity = dashLength / (maxDash / 3f);
if(m_FacingRight){m_Rigidbody2D.velocity = new Vector2(dashVelocity, 0 );}
else {m_Rigidbody2D.velocity = new Vector2(-dashVelocity, 0 );}
The reason we need to divide maxDash by three here is that you are incrementing dashTimer by 3 * deltaTime, which makes the timer run out faster.
Your answer
Follow this Question
Related Questions
Broken Jump Physics 0 Answers
OnTriggerEnter getting called more than once 0 Answers
Error: An object reference is required to access non-static member, help? 2 Answers
One Song plays but the other does not? 0 Answers
How to play animations from script. 0 Answers