Ledge Climb (Sort of working) Need help
So I have my ledge climbing sort of working except it also kind of doesn't work at times, sometimes it will double grab (will reposition back down the ledge and play the animation again before finishing), I have checked and the canClimbLedge bool gets reset too fast ssometimes and it runs again but I can't work out how or why? There is also a bug where the further I travel on an axis the more out of sync the ledge grabs & offsets become. I've been racking my brain and I think I'm now at a point where I need someones help on this.
How it works
I using a layerMasks to detect a "ledge" collider and a ray cast near the top of the character pointing out in all 4 directions with a set distance (3D Forward, backwards, left and right). Once it catches that you have hit a ledge based on player input (pressing w,a,s,d) it sets that direction true which in turn sets a ledgeDetected to true.
It then sets canClimbLedge to true and removes control from the player, then it checks the direction the player has climbed and calculates the begining position on the animation and the last position of the animation (on top of the ledge). It then sets the players location to loc1 and plays animation, the animation has a event on the last frame that calls the finishLedgeClimb function which resets everything.
Code can be seen below:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ledgeClimb : MonoBehaviour
{
public Transform Player;
public Transform ledgeCheck;
public Vector3 ledgeCheck2;
public float vertical;
public float horizontal;
private bool isTouchingLedgeR;
private bool isTouchingLedgeL;
private bool isTouchingLedgeF;
private bool isTouchingLedgeB;
private bool ledgeRight = false;
private bool ledgeLeft = false;
private bool ledgeForward = false;
private bool ledgeBack = false;
private bool canClimbLedge = false;
private bool ledgeDetected = false;
public float wallCheckDistance;
public Animator anim;
public LayerMask ledgeLayer;
public float ledgeClimbXOffset1 = 0f;
public float ledgeClimbYOffset1 = 0f;
public float ledgeClimbZOffset1 = 0f;
public float ledgeClimbXOffset2 = 0f;
public float ledgeClimbYOffset2 = 0f;
public float ledgeClimbZOffset2 = 0f;
public Vector3 ledgePosBot;
private Vector3 ledgePos1;
private Vector3 ledgePos2;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
checkSurroundings();
CheckLedgeClimb();
}
private void checkSurroundings() {
//Get player horizontal value
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
vertical = v;
horizontal = h;
//If player is moving leftssssssssss
if (!ledgeDetected) {
if (h > 0) {
isTouchingLedgeR = Physics.Raycast(ledgeCheck.position, Vector3.right, wallCheckDistance, ledgeLayer);
ledgeRight = true;
ledgeLeft = false;
ledgeBack = false;
ledgeForward = false;
} else if (h < 0) {
isTouchingLedgeL = Physics.Raycast(ledgeCheck.position, Vector3.left, wallCheckDistance, ledgeLayer);
ledgeLeft = true;
ledgeRight = false;
ledgeBack = false;
ledgeForward = false;
} else if (v > 0) {
isTouchingLedgeF = Physics.Raycast(ledgeCheck.position, Vector3.forward, wallCheckDistance, ledgeLayer);
ledgeForward = true;
ledgeBack = false;
ledgeLeft = false;
ledgeRight = false;
} else if (v < 0) {
isTouchingLedgeB = Physics.Raycast(ledgeCheck.position, Vector3.back, wallCheckDistance, ledgeLayer);
ledgeBack = true;
ledgeForward = false;
ledgeLeft = false;
ledgeRight = false;
}
} else { }
if (isTouchingLedgeR && ledgeRight && !ledgeDetected) {
ledgeDetected = true;
ledgePosBot = ledgeCheck.position;
} else if (isTouchingLedgeL && ledgeLeft && !ledgeDetected) {
ledgeDetected = true;
ledgePosBot = ledgeCheck.position;
} else if (isTouchingLedgeF && ledgeForward && !ledgeDetected) {
ledgeDetected = true;
ledgePosBot = ledgeCheck.position;
} else if (isTouchingLedgeB && ledgeBack && !ledgeDetected) {
ledgeDetected = true;
ledgePosBot = ledgeCheck.position;
}
ledgeCheck2 = ledgeCheck.position;
}
private void CheckLedgeClimb() {
if (ledgeDetected && !canClimbLedge) {
canClimbLedge = true;
GameObject.Find("Player").GetComponent<PlayerMovement>().canMove = false;
//If player is moving left
if (ledgeLeft) {
ledgePos1 = new Vector3(Mathf.Ceil(ledgePosBot.x - wallCheckDistance) + ledgeClimbXOffset1, Mathf.Floor(ledgePosBot.y) + ledgeClimbYOffset1, ledgePosBot.z);
ledgePos2 = new Vector3(Mathf.Ceil(ledgePosBot.x - wallCheckDistance) - ledgeClimbXOffset2, Mathf.Floor(ledgePosBot.y) + ledgeClimbYOffset2, ledgePosBot.z);
}
if (ledgeRight) {
ledgePos1 = new Vector3(Mathf.Floor(ledgePosBot.x + wallCheckDistance) - ledgeClimbXOffset1, Mathf.Floor(ledgePosBot.y) + ledgeClimbYOffset1, ledgePosBot.z);
ledgePos2 = new Vector3(Mathf.Floor(ledgePosBot.x + wallCheckDistance) + ledgeClimbXOffset2, Mathf.Floor(ledgePosBot.y) + ledgeClimbYOffset2, ledgePosBot.z);
//else keep it the same as the previous values
}
//If player is moving left
if (ledgeBack) {
ledgePos1 = new Vector3(ledgePosBot.x, Mathf.Floor(ledgePosBot.y) + ledgeClimbYOffset1, Mathf.Ceil(ledgePosBot.z - wallCheckDistance) + ledgeClimbZOffset1);
ledgePos2 = new Vector3(ledgePosBot.x, Mathf.Floor(ledgePosBot.y) + ledgeClimbYOffset2, Mathf.Ceil(ledgePosBot.z - wallCheckDistance) - ledgeClimbZOffset2);
}
if (ledgeForward) {
ledgePos1 = new Vector3(ledgePosBot.x, Mathf.Floor(ledgePosBot.y) + ledgeClimbYOffset1, Mathf.Floor(ledgePosBot.z + wallCheckDistance) - ledgeClimbZOffset1);
ledgePos2 = new Vector3(ledgePosBot.x, Mathf.Floor(ledgePosBot.y) + ledgeClimbYOffset2, Mathf.Floor(ledgePosBot.z + wallCheckDistance) + ledgeClimbZOffset2);
}
anim.SetBool("canClimbLedge", canClimbLedge);
}
//THIS IS THE ISSUE NEEDS TO BE UPDATED AND NOT MOVED THEN REALSED
//ON ledgePos2
if (canClimbLedge && ledgeDetected) {
Player.position = ledgePos1;
}
}
//Is setting the ledge to detected to false on the same line the position is moved
public void finishLedgeClimb() {
Player.position = ledgePos2;
canClimbLedge = false;
anim.SetBool("canClimbLedge", canClimbLedge);
ledgeRight = false;
ledgeLeft = false;
ledgeForward = false;
ledgeBack = false;
ledgeDetected = false;
GameObject.Find("Player").GetComponent<PlayerMovement>().canMove = true;
}
private void OnDrawGizmos() {
Gizmos.DrawLine(ledgeCheck.position, new Vector3(ledgeCheck.position.x + wallCheckDistance, ledgeCheck.position.y, ledgeCheck.position.z));
}
}