How do I add ground tolerance and ledge grabbing to Sebastian Lague's Unity 5 2D Controller?
Sebastian Lague's 2D controller uses raycasting for all movements instead of rigidbody movement. I have used other controllers but his one makes the game very fluid and responsive. He does not continue the series anymore. Link to Video Playlist Link to Source Code
How do I add the following two features to the controller?
1) Ledge grabbing so that when the Player collides just below a tall obstacle, he can stick to that position. then when a certain button is pressed, the player can move onto the top of the obstacle.
2) Ground tolerance for jumping. if the player calls for a jump a few frames just before the character touches the ground or if the player wants to jump when the character reaches the end of a platform, he reacts just a few frames too late while the character just start to fall. In both cases i want the game to be a bit forgiving when checking if the player is grounded when jumping
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (Controller2D))]
public class Player : MonoBehaviour {
public float maxJumpHeight=4;
public float minJumpHeight=1;
public float timeToJumpApex=.4f;
float accelerationTimeAirborne=.2f;
float accelerationTimeGrounded=.1f;
float moveSpeed=6;
float runSpeed=0;
public Vector2 wallJumpClimb;
public Vector2 wallJumpOff;
public Vector2 wallLeap;
public float wallSlideSpeedMax=3;
public float wallStickTime = .25f;
float timeToWallUnstick;
float gravity;
float maxJumpVelocity;
float minJumpVelocity;
Vector3 velocity;
float velocityXSmoothing;
Controller2D controller;
void Start() {
controller = GetComponent<Controller2D> ();
gravity = -(2 * maxJumpHeight) / Mathf.Pow (timeToJumpApex, 2);
maxJumpVelocity = Mathf.Abs (gravity) * timeToJumpApex;
minJumpVelocity = Mathf.Sqrt (2 * Mathf.Abs (gravity) * minJumpHeight);
print ("Gravity" + gravity + "Jump Velocity" + maxJumpVelocity);
}
void Update() {
Vector2 input = new Vector2 (Input.GetAxisRaw ("Horizontal"), Input.GetAxisRaw ("Vertical"));
int wallDirX=(controller.collisions.left)?-1:1;
if (Input.GetButton ("Sprint"))
runSpeed = 6;
else
runSpeed = 0;
float targetVelocityX = input.x * (moveSpeed+runSpeed);
velocity.x = Mathf.SmoothDamp (velocity.x, targetVelocityX, ref velocityXSmoothing, (controller.collisions.below)?accelerationTimeGrounded:accelerationTimeAirborne);
bool wallSliding = false;
if ((controller.collisions.left || controller.collisions.right) && !controller.collisions.below && velocity.y < 0)
{
wallSliding = true;
if (velocity.y < -wallSlideSpeedMax) {
velocity.y = -wallSlideSpeedMax;
}
if (timeToWallUnstick > 0) {
velocityXSmoothing = 0;
velocity.x = 0;
if (input.x != wallDirX && input.x != 0) {
timeToWallUnstick -= Time.deltaTime;
} else {
timeToWallUnstick = wallStickTime;
}
}
else {
timeToWallUnstick = wallStickTime;
}
}
if (Input.GetButtonDown("Jump")) //&& controller.collisions.below
{
if (wallSliding) {
if (wallDirX == input.x) {
velocity.x = -wallDirX * wallJumpClimb.x;
velocity.y = wallJumpClimb.y;
}
else if (input.x == 0) {
velocity.x = -wallDirX * wallJumpOff.x;
velocity.y = wallJumpOff.y;
}
else {
velocity.x = -wallDirX * wallLeap.x;
velocity.y = wallLeap.y;
}
}
if (controller.collisions.below) {
velocity.y = maxJumpVelocity;
}
}
if (Input.GetButtonUp ("Jump")) {
if (velocity.y > minJumpVelocity) {
velocity.y = minJumpVelocity;
}
}
velocity.y += gravity * Time.deltaTime;
controller.Move (velocity * Time.deltaTime,input);
if (controller.collisions.above || controller.collisions.below) {
velocity.y = 0;
}
}
}