Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question How to make a player use bezier spline for code I show you?

Discussion in 'Scripting' started by Somi_, Oct 28, 2022.

  1. Somi_

    Somi_

    Joined:
    Oct 25, 2017
    Posts:
    2
    Hello, how do I make player use this script and follow bezier curve with constant speed?

    Using DeCasteljausAlgorithm(float t) will just make it follow the curve set T no matter how long curve is.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. //Interpolation between 2 points with a Bezier Curve (cubic spline)
    5. public class BezCurve : MonoBehaviour
    6. {
    7.     //Has to be at least 4 so-called control points
    8.     public Transform startPoint;
    9.     public Transform endPoint;
    10.     public Transform controlPointStart;
    11.     public Transform controlPointEnd;
    12.  
    13.     Vector3 A, B, C, D;
    14.  
    15.     Color[] colorsArray = { Color.white, Color.red, Color.blue, Color.magenta, Color.black };
    16.  
    17.     private void Start()
    18.     {
    19.     }
    20.  
    21.     //Display without having to press play
    22.     void OnDrawGizmos()
    23.     {
    24.         DivideCurveIntoSteps();
    25.         A = startPoint.position;
    26.         B = controlPointStart.position;
    27.         C = controlPointEnd.position;
    28.         D = endPoint.position;
    29.  
    30.         //The Bezier curve's color
    31.         Gizmos.color = Color.white;
    32.  
    33.         //The start position of the line
    34.         Vector3 lastPos = A;
    35.  
    36.         //The resolution of the line
    37.         //Make sure the resolution is adding up to 1, so 0.3 will give a gap at the end, but 0.2 will work
    38.         float resolution = 0.02f;
    39.  
    40.  
    41.         //How many loops?
    42.         int loops = Mathf.FloorToInt(1f / resolution);
    43.  
    44.         for (int i = 1; i <= loops; i++)
    45.         {
    46.             //Which t position are we at?
    47.             float t = i * resolution;
    48.  
    49.            
    50.             Vector3 newPos = DeCasteljausAlgorithm(t);
    51.  
    52.             //Draw this line segment
    53.             Gizmos.DrawLine(lastPos, newPos);
    54.  
    55.             //Save this pos so we can draw the next line segment
    56.             lastPos = newPos;
    57.  
    58.         }
    59.  
    60.         //Also draw lines between the control points and endpoints
    61.         Gizmos.color = Color.green;
    62.  
    63.         Gizmos.DrawLine(A, B);
    64.         Gizmos.DrawLine(C, D);
    65.  
    66.     }
    67.  
    68.     //The De Casteljau's Algorithm
    69.     public Vector3 DeCasteljausAlgorithm(float t)
    70.     {
    71.         //Linear interpolation = lerp = (1 - t) * A + t * B
    72.         //Could use Vector3.Lerp(A, B, t)
    73.  
    74.         //To make it faster
    75.         float oneMinusT = 1f - t;
    76.  
    77.         //Layer 1
    78.         Vector3 Q = oneMinusT * A + t * B;
    79.         Vector3 R = oneMinusT * B + t * C;
    80.         Vector3 S = oneMinusT * C + t * D;
    81.  
    82.         //Layer 2
    83.         Vector3 P = oneMinusT * Q + t * R;
    84.         Vector3 T = oneMinusT * R + t * S;
    85.  
    86.         //Final interpolated position
    87.         Vector3 U = oneMinusT * P + t * T;
    88.  
    89.         return U;
    90.     }
    91.  
    92.     //The derivative of cubic De Casteljau's Algorithm
    93.     public Vector3 DeCasteljausAlgorithmDerivative(float t)
    94.     {
    95.         Vector3 dU = t * t * (-3f * (A - 3f * (B - C) - D));
    96.  
    97.         dU += t * (6f * (A - 2f * B + C));
    98.  
    99.         dU += -3f * (A - B);
    100.  
    101.         return dU;
    102.     }
    103.  
    104.     //Get and infinite small length from the derivative of the curve at position t
    105.     public float GetArcLengthIntegrand(float t)
    106.     {
    107.         //The derivative at this point (the velocity vector)
    108.         Vector3 dPos = DeCasteljausAlgorithmDerivative(t);
    109.  
    110.         float integrand = dPos.magnitude;
    111.  
    112.         return integrand;
    113.     }
    114.  
    115.     //Get the length of the curve between two t values with Simpson's rule
    116.     public float GetLengthSimpsons(float tStart, float tEnd)
    117.     {
    118.         //This is the resolution and has to be even
    119.         int n = 20;
    120.  
    121.         //Now we need to divide the curve into sections
    122.         float delta = (tEnd - tStart) / (float)n;
    123.  
    124.         //The main loop to calculate the length
    125.  
    126.         //Everything multiplied by 1
    127.         float endPoints = GetArcLengthIntegrand(tStart) + GetArcLengthIntegrand(tEnd);
    128.  
    129.         //Everything multiplied by 4
    130.         float x4 = 0f;
    131.         for (int i = 1; i < n; i += 2)
    132.         {
    133.             float t = tStart + delta * i;
    134.  
    135.             x4 += GetArcLengthIntegrand(t);
    136.         }
    137.  
    138.         //Everything multiplied by 2
    139.         float x2 = 0f;
    140.         for (int i = 2; i < n; i += 2)
    141.         {
    142.             float t = tStart + delta * i;
    143.  
    144.             x2 += GetArcLengthIntegrand(t);
    145.         }
    146.  
    147.         //The final length
    148.         float length = (delta / 3f) * (endPoints + 4f * x4 + 2f * x2);
    149.  
    150.         return length;
    151.     }
    152.  
    153.     //Use Newton–Raphsons method to find the t value at the end of this distance d
    154.     public float FindTValue(float d, float totalLength)
    155.     {
    156.         //Need a start value to make the method start
    157.         //Should obviously be between 0 and 1
    158.         //We can say that a good starting point is the percentage of distance traveled
    159.         float t = d / totalLength;
    160.  
    161.         //Need an error so we know when to stop the iteration
    162.         float error = 0.001f;
    163.  
    164.         //We also need to avoid infinite loops
    165.         int iterations = 0;
    166.  
    167.         while (true)
    168.         {
    169.             //Newton's method
    170.             float tNext = t - ((GetLengthSimpsons(0f, t) - d) / GetArcLengthIntegrand(t));
    171.  
    172.             //Have we reached the desired accuracy?
    173.             if (Mathf.Abs(tNext - t) < error)
    174.             {
    175.                 break;
    176.             }
    177.  
    178.             t = tNext;
    179.  
    180.             iterations += 1;
    181.  
    182.             if (iterations > 1000)
    183.             {
    184.                 break;
    185.             }
    186.         }
    187.  
    188.         return t;
    189.     }
    190.  
    191.     //Divide the curve into equal steps
    192.     public void DivideCurveIntoSteps()
    193.     {
    194.         //Find the total length of the curve
    195.         float totalLength = GetLengthSimpsons(0f, 1f);
    196.  
    197.         //How many sections do we want to divide the curve into
    198.         int parts = 30;
    199.  
    200.         //What's the length of one section?
    201.         float sectionLength = totalLength / (float)parts;
    202.  
    203.         //Init the variables we need in the loop
    204.         float currentDistance = 0f + sectionLength;
    205.  
    206.         //The curve's start position
    207.         Vector3 lastPos = A;
    208.  
    209.         //The Bezier curve's color
    210.         //Need a seed or the line will constantly change color
    211.         Random.InitState(12345);
    212.  
    213.         int lastRandom = Random.Range(0, colorsArray.Length);
    214.  
    215.         for (int i = 1; i <= parts; i++)
    216.         {
    217.             //Use Newton–Raphsons method to find the t value from the start of the curve
    218.             //to the end of the distance we have
    219.             float t = FindTValue(currentDistance, totalLength);
    220.  
    221.             //Get the coordinate on the Bezier curve at this t value
    222.             Vector3 pos = DeCasteljausAlgorithm(t);
    223.  
    224.  
    225.             //Draw the line with a random color
    226.             int newRandom = Random.Range(0, colorsArray.Length);
    227.  
    228.             //Get a different random number each time
    229.             while (newRandom == lastRandom)
    230.             {
    231.                 newRandom = Random.Range(0, colorsArray.Length);
    232.             }
    233.  
    234.             lastRandom = newRandom;
    235.  
    236.             Gizmos.color = colorsArray[newRandom];
    237.  
    238.             Gizmos.DrawLine(lastPos, pos);
    239.  
    240.  
    241.             //Save the last position
    242.             lastPos = pos;
    243.  
    244.             //Add to the distance traveled on the line so far
    245.             currentDistance += sectionLength;
    246.         }
    247.     }
    248. }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,960
    I just use the Bezier Solutions pack from the Unity asset store (from Sleyman Yasir Kula) and it all works: constant speed, constant time, etc.

    If you want to debug your own bezier follower solution, here's how to get started.

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    When in doubt, print it out!(tm)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
    Somi_ likes this.
  3. Somi_

    Somi_

    Joined:
    Oct 25, 2017
    Posts:
    2
    Im gonna just make it short and just say THANK YOU VERY MUCH !!!!! :)
     
    Kurt-Dekker likes this.