As a Unity developer working with Unity version 2020.2.6f1 and Visual Studio 2017, I am preparing to share several scripts with you.  The goal is to modify the grinding mechanism to allow the player, who is on a HoverBoard, to engage with the rail from any point along it and initiate grinding. Furthermore, I want to enable the player, or HoverBoard, to grind in both directions along the rail, similar to the grinding mechanics found in the game Tony Hawk’s Pro Skater. Please provide guidance once all script details are provided.

Script 1:
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Rigidbody))]
public class HoverBoardControl : MonoBehaviour
{
    [Header("Hover Settings")]
    public float hoverForce = 9.0f;
    public float hoverHeight = 2.0f;
    public GameObject[] hoverPoints;

    [Header("Movement Settings")]
    public float forwardAcceleration = 100.0f;
    public float backwardAcceleration = 25.0f;
    public float turnStrength = 10f;

    [Header("UI & Scoring")]
    public Text scoreText;
    public int currentScore;
    public HUD hud;
    public TrickManager trickManager;

    [Header("Boost Settings")]
    public float boostMultiplier = 2.0f;

    [Header("Rotation Settings")]
    public float minRotation = -20.0f;
    public float maxRotation = 0.0f;

    [Header("Timer Settings")]
    public float timer = 5.0f;

    [Header("Miscellaneous")]
    public bool moving;
    public GameObject board;

    [Header("Input Settings")]
    public KeyCode moveForwardKey = KeyCode.W;
    public KeyCode moveBackwardKey = KeyCode.S;
    public KeyCode turnLeftKey = KeyCode.A;
    public KeyCode turnRightKey = KeyCode.D;

    [Header("Customizable Keys")]
    [SerializeField] private KeyCode ollieKey = KeyCode.Space;
    [SerializeField] private KeyCode boostKey = KeyCode.LeftControl;
    [SerializeField] private KeyCode grindKey = KeyCode.G; // Add the grindKey from Script 1

    int layerMask;
    float currentThrust;
    float currentTurn;

    Rigidbody rb;
    HoverboardGrindController hoverboardGrindController; // Add reference to HoverboardGrindController

    void Awake()
    {
        rb = GetComponent<Rigidbody>();
        hud = FindObjectOfType<HUD>();
        trickManager = GetComponent<TrickManager>();
        hoverboardGrindController = GetComponent<HoverboardGrindController>(); // Add this line
    }

    void Start()
    {
        layerMask = 1 << LayerMask.NameToLayer("Characters");
        layerMask = ~layerMask;

        hoverForce = 1500f;
        hoverHeight = 6f;

        if (scoreText == null)
        {
            GameObject canvas = GameObject.Find("Canvas");
            if (canvas != null)
            {
                scoreText = Instantiate(Resources.Load("ScoreText", typeof(Text))) as Text;
                scoreText.transform.SetParent(canvas.transform, false);
            }
            else
            {
                Debug.LogError("Canvas not found. Make sure there is a Canvas GameObject in the scene.");
            }
        }
    }

    void OnEnable()
    {
        // Reset physics properties if needed when hoverboard control is enabled
        rb.isKinematic = false;
        rb.useGravity = true;
    }

    void OnDisable()
    {
        // Stop the hoverboard movement by making it kinematic or directly setting velocity to zero as needed
        rb.velocity = Vector3.zero;
        rb.angularVelocity = Vector3.zero;
        rb.isKinematic = true;
    }

    void Update()
    {
        currentThrust = 0.0f;
        currentTurn = 0.0f;

        scoreText.text = currentScore + " Points";

        if (Input.GetKeyDown(ollieKey))
        {
            trickManager.ExecuteOllieOrTrick(1500f);
        }

        if (hud != null)
        {
            if (Input.GetKeyDown(boostKey) && (hud.BoostInt > 0))
            {
                forwardAcceleration = forwardAcceleration * boostMultiplier;
                backwardAcceleration = backwardAcceleration * boostMultiplier;

                if (hud.BoostInt <= 0)
                {
                    forwardAcceleration = forwardAcceleration / boostMultiplier;
                    backwardAcceleration = backwardAcceleration / boostMultiplier;
                }
            }

            if (Input.GetKey(boostKey))
            {
                hud.BoostInt -= 0.2f;
            }
        }

        Vector3 currentRotation = transform.rotation.eulerAngles;
        currentRotation.x = Mathf.Clamp(currentRotation.x, minRotation, maxRotation);
        currentRotation.z = Mathf.Clamp(currentRotation.z, minRotation, maxRotation);
        transform.rotation = Quaternion.Euler(currentRotation);

        float aclAxis = Input.GetAxis("Vertical");
        if (aclAxis > 0.1f)
            currentThrust = aclAxis * forwardAcceleration;
        else if (aclAxis < -0.1f)
            currentThrust = aclAxis * backwardAcceleration;

        float turnAxis = Input.GetAxis("Horizontal");
        if (Mathf.Abs(turnAxis) > 0.1f)
            currentTurn = turnAxis;

        if (Input.GetKeyDown(trickManager.kickflipKey))
        {
            trickManager.ExecuteKickflip();
        }
        else if (Input.GetKeyDown(trickManager.heelflipKey))
        {
            trickManager.ExecuteHeelflip();
        }
        else if (Input.GetKeyDown(trickManager.shoveItKey))
        {
            trickManager.ExecuteShoveIt();
        }

        // Insert Script 1 code here
        if (Input.GetKeyDown(grindKey))
        {
            GrindableSurface nearestSurface = hoverboardGrindController.FindClosestGrindableSurface();
            if (nearestSurface != null)
            {
                hoverboardGrindController.StartGrinding(nearestSurface);
            }
        }
        else if (Input.GetKeyUp(grindKey))
        {
            hoverboardGrindController.EndGrinding();
        }
       
    }

    void FixedUpdate()
    {
        ApplyHover();
        ApplyMovement();
        ApplyTurning();
    }

    void ApplyHover()
    {
        for (int i = 0; i < hoverPoints.Length; i++)
        {
            var hoverPoint = hoverPoints[i];
            RaycastHit hoverHit;
            if (Physics.Raycast(hoverPoint.transform.position, -Vector3.up, out hoverHit, hoverHeight, layerMask))
            {
                rb.AddForceAtPosition(Vector3.up * hoverForce * (1.0f - (hoverHit.distance / hoverHeight)), hoverPoint.transform.position);
            }
            else
            {
                if (transform.position.y > hoverPoint.transform.position.y)
                {
                    rb.AddForceAtPosition(hoverPoint.transform.up * hoverForce, hoverPoint.transform.position);
                }
                else
                {
                    rb.AddForceAtPosition(hoverPoint.transform.up * -hoverForce, hoverPoint.transform.position);
                }
            }
        }
    }

    void ApplyMovement()
    {
        if (Mathf.Abs(currentThrust) > 0)
        {
            rb.AddForce(transform.forward * currentThrust);
        }
    }

    void ApplyTurning()
    {
        if (currentTurn > 0)
        {
            rb.AddRelativeTorque(Vector3.up * currentTurn * turnStrength);
        }
        else if (currentTurn < 0)
        {
            rb.AddRelativeTorque(Vector3.up * currentTurn * turnStrength);
        }
    }
}

Script 2: 
using UnityEngine;
using UnityEngine.UI;

public class HoverboardGrindController : MonoBehaviour
{
    [Header("Grind UI")]
    public Slider grindBalanceSlider; // Assign the slider in the inspector

    [Header("Grind Detection")]
    public float detectionRadius = 5f;
    public LayerMask grindableLayer;
    public KeyCode grindKey = KeyCode.G; // Key to start grinding

    public GrindableSurface currentGrindSurface { get; private set; } // Change type to GrindableSurface
    public bool isGrinding { get; private set; }

    // Update method (includes key press logic)
    private void Update()
    {
        // Check for grind key press and toggle grinding
        if (Input.GetKeyDown(grindKey))
        {
            Transform closestSurfaceTransform = FindClosestGrindableSurface();
            if (closestSurfaceTransform != null)
            {
                // Attempt to get GrindableSurface component
                GrindableSurface grindableSurface = closestSurfaceTransform.GetComponent<GrindableSurface>();

                // If the component is found, start grinding
                if (grindableSurface != null)
                {
                    StartGrinding(grindableSurface);
                }
            }
        }
        else if (Input.GetKeyUp(grindKey))
        {
            EndGrinding();
        }

        if (isGrinding)
        {
            GrindAlongSurface();
        }
    }

    // Method to find the nearest grindable surface
    public Transform FindClosestGrindableSurface()
    {
        Collider[] hits = Physics.OverlapSphere(transform.position, detectionRadius, grindableLayer);
        Transform closestSurface = null;
        float closestDistanceSqr = Mathf.Infinity;
        Vector3 currentPosition = transform.position;

        foreach (Collider hit in hits)
        {
            Vector3 directionToSurface = hit.transform.position - currentPosition;
            float dSqrToSurface = directionToSurface.sqrMagnitude;
            if (dSqrToSurface < closestDistanceSqr)
            {
                closestDistanceSqr = dSqrToSurface;
                closestSurface = hit.transform;
            }
        }

        return closestSurface;
    }

    // Method to start grinding
    public void StartGrinding(GrindableSurface grindSurface)
    {
        isGrinding = true;
        currentGrindSurface = grindSurface;
        grindBalanceSlider.gameObject.SetActive(true);
        // You can run additional logic here (like animations, scoring system, etc.)
    }

    // Method to end grinding
    public void EndGrinding()
    {
        isGrinding = false;
        currentGrindSurface = null;
        grindBalanceSlider.gameObject.SetActive(false);
        // You can run additional logic here (like animations, scoring system, etc.)
    }

    // Method to handle movement along the surface while grinding
    private void GrindAlongSurface()
    {
        if (currentGrindSurface != null)
        {
            transform.position += currentGrindSurface.transform.forward * Time.deltaTime;
            // Here you could add checks to see if the grind has reached the end of the surface
            // And additional logic such as effects, scoring, and so on
        }
    }
}

Script 3: using UnityEngine;

public class GrindableSurface : MonoBehaviour
{
    [Header("Surface Properties")]
    public float grindingSpeed = 5f; // The speed at which the player will move along the grind

    // Calculate direction from start to end normalized
    public Vector3 GetDirection(Transform playerTransform)
    {
        // Calculate the direction based on the player's position and the grind surface position
        return (transform.position - playerTransform.position).normalized;
    }

    public float GetSpeed()
    {
        return grindingSpeed;
    }
}

Script4: using UnityEngine;

public class PlayerHoverboardInteraction : MonoBehaviour
{
    [Header("Interaction Settings")]
    public KeyCode getOnKey = KeyCode.E;
    public KeyCode getOffKey = KeyCode.E;
    public GameObject playerModel;
    public GameObject hoverboard;
    public Transform hoverboardStandPosition; // Assign a transform position to stand on the hoverboard

    private bool isOnHoverboard = false;

    // Reference to player and hoverboard control scripts
    public playerController playerControllerManager; // Assuming your playerController script name is ‘PlayerController’
    public HoverBoardControl hoverBoardControl; // Assuming your hoverboard control script name is ‘HoverBoardControl’

    // Camera references for player and hoverboard
    [Header("Camera Settings")]
    public Camera playerMainCamera; // Player’s main camera
    public Camera hoverboardCamera; // Hoverboard’s camera

    private Rigidbody playerRigidbody;
    private Collider playerCollider;

    void Start()
    {
        // Cache references to the player’s Rigidbody and Collider
        playerRigidbody = playerModel.GetComponent<Rigidbody>();
        playerCollider = playerModel.GetComponent<Collider>();

        // Disable hoverboard control at the start.
        hoverBoardControl.enabled = false;

        // Ensure the hoverboard camera is also disabled at the start
        if (hoverboardCamera != null)
            hoverboardCamera.enabled = false;

        // Additional start initialization, if needed
    }

    void Update()
    {
        if (!isOnHoverboard && Input.GetKeyDown(getOnKey) && CanGetOnHoverboard())
        {
            GetOnHoverboard();
        }
        else if (isOnHoverboard && Input.GetKeyDown(getOffKey))
        {
            GetOffHoverboard();
        }
    }

    private bool CanGetOnHoverboard()
    {
        return hoverboard != null;
    }

    private void GetOnHoverboard()
    {
        if (!CanGetOnHoverboard())
            return;

        isOnHoverboard = true;

        // Positioning the player on the hoverboard
        playerModel.transform.position = hoverboardStandPosition.position;
        playerModel.transform.rotation = hoverboardStandPosition.rotation;
        playerModel.transform.SetParent(hoverboardStandPosition);

        // Disabling player controls and collider
        playerControllerManager.enabled = false;
        playerRigidbody.isKinematic = true;
        playerCollider.enabled = false;

        // Enabling hoverboard control
        hoverBoardControl.enabled = true;

        // Switch cameras
        if (playerMainCamera != null)
            playerMainCamera.enabled = false;

        if (hoverboardCamera != null)
            hoverboardCamera.enabled = true;
    }

    private void GetOffHoverboard()
    {
        isOnHoverboard = false;

        // Detach player from hoverboard and apply a small upward and forward offset
        playerModel.transform.SetParent(null);
        playerModel.transform.Translate(0, 1f, 1f);

        // Re-enabling player controls and collider
        playerControllerManager.enabled = true;
        playerRigidbody.isKinematic = false;
        playerCollider.enabled = true;

        // Disabling hoverboard control
        hoverBoardControl.enabled = false;

        // Switch cameras back to the player’s main camera
        if (hoverboardCamera != null)
            hoverboardCamera.enabled = false;

        if (playerMainCamera != null)
            playerMainCamera.enabled = true;
    }
}