Roll/Dodge/Evade System

I am trying to make my character be able to evade attacks. My movement script is quite long but this is the portion of code I am using.

if(evading)
		{
			moveDirection = playerRotation.transform.forward / 5 * evadeSpeed;
			moveSpeed = evadeSpeed;
		}

The problem here is that I don’t have control over the two things I need:

The distance of the roll and the speed in which the character covers the distance. I am uncertain how to control these.

@HappyMoo’s comment : The evasion occurs in the forward direction because the forward direction is the direction the character is facing, that’s the style I want for my game.

	void ProcessEvasionTime()
	{
		//evasion timer for action performed
		if(evading)
		{
			evadeTimer -= Time.deltaTime;
			if(evadeTimer <= 0)
			{
				anim.SetBool("Evading", false);
				evading = false;
				cooldownInEffect = true;

			}
		}else
		{
			evadeTimer = evadeTime;
		}

		if(!evading && InputManager.ActiveDevice.GetControl(InputControlType.Action1))
		{
			ProcessEvasion();
		}

		if(cooldownInEffect)
		{
			cooldownTimer -= Time.deltaTime;
			if(cooldownTimer <= 0)
			{
				cooldownInEffect = false;
				cooldownTimer = cooldown;
			}
		}
	}

	void ProcessEvasion()
	{
		if(!cooldownInEffect)
		{
			//timers
			evading = true;
			evadeTimer = evadeTime;

			//move character to evade and set animator to play evasion animation
			anim.SetBool("Evading", true);
		}
	}

Character Movement:
Note - The input system is a custom script to allow cross controller support, just think of it as input.getaxis or relevant alternative.

	void Update()
	{
		InputManager.Update();

		//cache the inputs
		//h = Input.GetAxis ("Horizontal");
		h = InputManager.ActiveDevice.GetControl(InputControlType.LeftStickX);
		//v = Input.GetAxis ("Vertical");
		v = InputManager.ActiveDevice.GetControl(InputControlType.LeftStickY);
		//s = Input.GetAxis ("Strafe");
		//mh = Input.GetAxis ("Mouse X");

		//zero the move direction so previous data is removed
		moveDirection = Vector3.zero;

		//check if it's grounded, otherwise player cannot move, also check for the deadzone
		if(characterController.isGrounded)
		{
			if (v > deadZone || v < -deadZone)
			{
				moveDirection = new Vector3 (0f, 0f, v);
			}
			//add horizontal movement to the (currently)vertical movement vector
			moveDirection.x = h;
			//process turning
			//ProcessTurning(s, mh);

			//normalize the diagonal inputs to prevent values above 1
			if (moveDirection.magnitude > 1)
			{
				moveDirection.Normalize ();
			}

			//move character in the direction of the camera's facing angle
			moveDirection = cam.transform.TransformDirection(moveDirection);
		}

		//change movement speed if weapon unsheathed
		if(anim.GetBool("Unsheathed") == true && !evading)
			moveSpeed = walkSpeed;
		else
			moveSpeed = runSpeed;

		//process evasion timers
		if(combo!= null && combo.attackTimer <= 0)
			ProcessEvasionTime();

		//all events for when the player loses control of character eg. talking, cutscene, death, evading
		RevokeControl();

		//set the animator's Speed float to the magnitude of the moveDirection to allow for the run animation to play
		anim.SetFloat ("Speed", moveDirection.magnitude);

		//calculate gravity
		moveDirection.y = -gravity * Time.deltaTime;

		//move the character
		characterController.Move (moveDirection * moveSpeed * Time.deltaTime);
		transform.Rotate(turnDirection * Time.deltaTime);

		//control player facing direction when strafing, moving backward, etc
		if(moveDirection.x > deadZone || moveDirection.x < -deadZone || moveDirection.z > deadZone || moveDirection.z < -deadZone)
		{
			desiredRotation = Quaternion.LookRotation(new Vector3(moveDirection.x, 0f, moveDirection.z));
			playerRotation.transform.rotation = Quaternion.RotateTowards(playerRotation.transform.rotation, desiredRotation, rotateSpeed * 10 * Time.deltaTime);
		}
	}

Things I noticed:

  • You calculate gravity in a wrong way. The way you do it, falling speed will not build up, but you always fall with the same constant velocity. And you also apply it if the player is grounded which probably means your players scrapes along the ground and you lose speed.

  • Strange constant 10 where rotateSpeed is used. If you don’t use rotateSpeed for two different rotations and one should be 10 times faster than the other, you should include the 10 in the constant rotateSpeed.

  • Is it by design or by accident, that you treat deadzone differently for the different axes? In forward direction the character doesn’t even react if below deadzone, but sideways you can slowly strafe, but you only turn when >deadzone

Now to ProcessEvasionTime: The cooldown timer logic is smeared over so many lines, I would pull it together. Also, do you really need cooldownTimer and cooldownInEffect? Just keep cooldownTimer at 0 and if you set it to anything elsem you’re in cooldown and it counts down.

Rename ProcessEvasionTime to ProcessEvasion as it now not only processes the Timer and do this:

public float evadeTime; // this tells us how long the evade takes
public float evadeDistance; // this tells us how far player will evade

void ProcessEvasion()
{
	cooldownTimer = Mathf.Max(0f, cooldownTimer - Time.deltaTime);
	
	if(!evading && cooldownTimer==0 && InputManager.ActiveDevice.GetControl(InputControlType.Action1))
	{
		evading = true;
		evadeTimer = evadeTime;
		anim.SetTrigger("Evading");
	}

	if(evading)
	{
		evadeTimer = Mathf.Max(0f, evadeTimer - Time.deltaTime);

		// Evasion overrides speed and direction
		moveDirection = playerRotation.transform.forward; // evasion = full speed forward
		moveSpeed = evadeDistance/evadeTime; 
		 
		if(evadeTimer == 0)
		{
			//anim.SetBool("Evading", false);
			evading = false;
		}
	}
}