Search Unity

Bezier Solution [Open Source]

Discussion in 'Assets and Asset Store' started by yasirkula, Nov 12, 2016.

  1. Zihaben

    Zihaben

    Joined:
    Apr 6, 2015
    Posts:
    6
    Beautiful solution, very detailed documented! For my case, had some minor glitches, but somehow fixed em after reading this thread ( picture "I have no idea what Im doing" here). Excellent job, big thanks!
     
    yasirkula likes this.
  2. peterahou

    peterahou

    Joined:
    May 19, 2015
    Posts:
    53
    Hi,

    I have an array of objects that I would like to distribute evenly on a closed spline (Loop is checked). As has already been established, I can't just use NormalizedT to offset them like this:
    Code (CSharp):
    1.         float offset = 1f / walkers.Length;
    2.         for (int i=0; i<walkers.Length; i++)
    3.         {
    4.             walkers[i].NormalizedT = offset * i;
    5.         }
    So, instead I tried the MoveAlongSpline method like this:
    Code (CSharp):
    1.         float offset = 1f / walkers.Length;
    2.         for (int i=0; i<walkers.Length; i++)
    3.         {
    4.             float t = 0f;
    5.             walkers[i].Spline.MoveAlongSpline(ref t, walkers[i].Spline.GetLengthApproximately(0f, 1f, 50) * (offset * i), 3);
    6.             walkers[i].NormalizedT = t;
    7.         }
    But then I get this error:
    Code (CSharp):
    1. ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
    2. Parameter name: index
    3. System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource) (at <fb001e01371b4adca20013e0ac763896>:0)
    4. System.ThrowHelper.ThrowArgumentOutOfRangeException () (at <fb001e01371b4adca20013e0ac763896>:0)
    5. System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <fb001e01371b4adca20013e0ac763896>:0)
    6. BezierSolution.BezierSpline.GetPoint (System.Single normalizedT) (at Packages/com.yasirkula.beziersolution@1.27.1/Plugins/BezierSolution/BezierSpline.cs:338)
    7. BezierSolution.BezierSpline.MoveAlongSpline (System.Single& normalizedT, System.Single deltaMovement, System.Int32 accuracy) (at Packages/com.yasirkula.beziersolution@1.27.1/Plugins/BezierSolution/BezierSpline.cs:651)
    I have 8 BezierWalkersWithSpeed in the array and it appears to break after the 5th. Also, I noticed that t is outside the 0-1 range when that happens. Is it supposed to do that?
    Code (CSharp):
    1. 0
    2. 0.3845523
    3. 0.5379122
    4. 0.8607984
    5. 1.032565
     
  3. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    MoveAlongSpline calculates an approximate value and I think in this case, when a large deltaMovement is passed to it, the error margin increases substantially. Increasing MoveAlongSpline's accuracy may resolve this issue. Can you give it a try?
     
  4. peterahou

    peterahou

    Joined:
    May 19, 2015
    Posts:
    53
    Sure, it looks like setting the accuracy to around 6 fixes the error, but I have to increase it to around 100 to get an even distribution of the objects. It's still a little off, but pretty close to what I want.
    Is it a bad idea to use such high numbers for accuracy? I may need to do this simultaneously on 50 splines with 4-8 objects on each of them.
     
  5. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I'd expect a performance drop while positioning too many objects with high accuracy. But unless you're going to position these objects every frame, a 1-frame performance drop can be acceptable in many scenarios.
     
  6. peterahou

    peterahou

    Joined:
    May 19, 2015
    Posts:
    53
    Yeah, that makes sense. It actually doesn't seem that bad on my old Macbook Pro. Thank you very much for the replies. :)
     
    yasirkula likes this.
  7. marcmantra

    marcmantra

    Joined:
    Nov 4, 2013
    Posts:
    2
    Hi @yasirkula ,

    First of all I want to thank you so much for your amazing tool and open it to the community. I'm playing with it to add some crowds around the scenario like train, people walking and drones flying.
    The train it's clear, but on people and drones I want to use the particle component to add some variations like size, speed... random. But on this component we don't have a Follow Forward to move the particle mesh in Local to look at forward. Is there anyway to add this option on particles?

    Thanks in advance!
     
  8. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can call
    particles[i].rotation3D = Quaternion.LookRotation( spline.GetTangent( 1f - ( particles[i].remainingLifetime / particles[i].startLifetime ) ) ).eulerAngles;
    after settings the same particle's position inside ParticlesFollowBezier.cs but the Particle System must have its Simulation Space set to World.
     
  9. EndlessMc

    EndlessMc

    Joined:
    Apr 25, 2017
    Posts:
    2
    Hi
    Im using the spline to draw a line between a static object and my player. 1 point is object, 3th point is player. Inbetween is a 2nd point which is calculated at the center distance between point 1 and 3.
    I have been trying to change the Control points of my 2nd point. (So the spline has an bend) But i think im doing something wrong, here is the spline part of my code. the last 2 lines should work according to the documentation, but my spline is still just strait.
    What could i be missing?


    Code (CSharp):
    1.     void Start()
    2.     {
    3.         spline = this.gameObject.GetComponent<BezierSpline>();
    4.         spline.Initialize(3);
    5.         ParticalTrail.SetActive(false);
    6.     }
    7.  
    8.     // Update is called once per frame
    9.     void Update()
    10.     {
    11.         if (inTrigger && ObjectToInteract.GetComponent<Pickup>().HasChosen == false)
    12.         {
    13.  
    14.         // Set second end point's local
    15.         spline[0].position = SmellStartPoint.transform.position;
    16.         spline[0].handleMode = BezierPoint.HandleMode.Free;
    17.         // Set first end point's (world)
    18.         spline[2].position = Player.transform.position;
    19.  
    20.         //Inbetween
    21.         x = Player.transform.position.x + (SmellStartPoint.transform.position.x - Player.transform.position.x) / 2;
    22.         y = Player.transform.position.y + (SmellStartPoint.transform.position.y - Player.transform.position.y) / 2;
    23.         z = Player.transform.position.z + (SmellStartPoint.transform.position.z - Player.transform.position.z) / 2;
    24.  
    25.         spline[1].position = new Vector3(x, y , z );
    26.         spline[1].precedingControlPointLocalPosition = new Vector3(50, 50, 50);
    27.         spline[1].precedingControlPointPosition = spline[2].position;
     
  10. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    spline[1].precedingControlPointPosition
    overrides the previous line (
    spline[1].precedingControlPointLocalPosition
    ). Removing precedingControlPointPosition could help.
     
  11. EndlessMc

    EndlessMc

    Joined:
    Apr 25, 2017
    Posts:
    2
    Ah, thanks now it does work!
     
    yasirkula likes this.
  12. Nakel

    Nakel

    Joined:
    Sep 28, 2017
    Posts:
    106
    Still no mesh repeat along the splines support? :)
     
  13. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Yeah, I'm currently not planning to add this feature :oops: I think other free assets like this and this are already doing a great job, I don't think it is necessary to duplicate their work.
     
  14. Nakel

    Nakel

    Joined:
    Sep 28, 2017
    Posts:
    106
    Yes you are right, but one only generates mesh and the other one is just not friendly at all xD
    Believe me I have tried many... even on GitHub, YouTube... and this one is really user friendly... easy to manipulate during runtime and simple as yours! with that only I think it is a genuine asset and not just a duplicate, even though that is just my opinion.

    Keep Up!
     
    Last edited: Jan 13, 2021
    yasirkula likes this.
  15. Nakel

    Nakel

    Joined:
    Sep 28, 2017
    Posts:
    106
    By the way.... and just in case, Could you point me into the right direction to adapt this asset onto mesh along the spline?
     
  16. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I'd also need to make some research before being able to answer this question. I'd recommend you to check out this video:


    Bezier points in my plugin have only a position and a tangent value, so they don't have a normal value. Thus, your road mesh will always have a normal value of Vector3.up, you can't tilt it. We'd need a normal value to be able to tilt the road.
     
  17. Nakel

    Nakel

    Joined:
    Sep 28, 2017
    Posts:
    106
    THANK YOU VERY MUCH!
    I will try to do it with a normal value using your bezier solution :D
     
    yasirkula likes this.
  18. Hi_ImTemmy

    Hi_ImTemmy

    Joined:
    Jul 8, 2015
    Posts:
    174
    Hello,

    I'm really digging this asset. Great stuff. The only thing I can't seem to do is get an object travelling along the spline to roll / tilt. Is this possible? I'd like to do something like just rotate the points and have that affect the object travelling along the spline.
     
    yasirkula likes this.
  19. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Currently, there isn't a built-in way for this. But I hear you because I also needed this feature recently. I'll investigate this but can't promise any ETA.
     
  20. Lord_Slimeball

    Lord_Slimeball

    Joined:
    Dec 1, 2019
    Posts:
    10
    Hi yasirkula,

    I downloaded your asset and it looks great, but I am not sure if I am using it correctly. I have an object which I would like to move at a consistent speed along a bezier curve. The object in my game will need to move along multiple bezier paths, which do not need to be connected, so I have to able to create curves programmatically. This is my code, I added a BezierSpline and a BezierWalkerWithTime onto the object I want to move:

    BezierSolution.BezierSpline bezierSpline = GetComponent<BezierSolution.BezierSpline>();
    bezierSpline.InsertNewPointAt(0);
    bezierSpline.InsertNewPointAt(1);
    bezierSpline.InsertNewPointAt(2);
    bezierSpline.InsertNewPointAt(3);

    bezierSpline[0].position = new Vector3(0, 1f, 0);
    bezierSpline[1].position = new Vector3(-0.2f, 0.9f, 0f);
    bezierSpline[2].position = new Vector3(0.7f, 1.8f, 0f);
    bezierSpline[3].position = new Vector3(0.6f, 1.7f, 0);
    bezierSpline.AutoConstructSpline();

    BezierSolution.BezierWalkerWithTime bezierWalkerWithTime = GetComponent<BezierSolution.BezierWalkerWithTime>();
    bezierWalkerWithTime.spline = bezierSpline;
    bezierWalkerWithTime.enabled = true;

    I can see that the object does not constantly move at exactly the same speed, and it does not stop once it reaches the last point. On the BezierWalkerWithTime I have reduced the Movement Lerp Modifier to 1 and Rotation Lerp Modifier to 0. Am I doing something wrong or missing a step?
     
  21. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    - For constant speed, try using BezierWalkerWithSpeed
    - You are inserting 4 points to the spline but it had at least 2 points beforehand, so you end up with at least 6 points. I'd recommend you to check BezierSpline's Count property and create only the missing points
     
  22. Lord_Slimeball

    Lord_Slimeball

    Joined:
    Dec 1, 2019
    Posts:
    10
    Hi,

    thanks for the quick reply. How exactly should I set the speed? If I want to move from (0, 0, 0) to (1, 0, 0) in two seconds the speed should be 0.5?
     
  23. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    spline.Length / 2f
    would be more accurate.
     
  24. Lord_Slimeball

    Lord_Slimeball

    Joined:
    Dec 1, 2019
    Posts:
    10
    Ok, thanks. This is my code now:

    BezierSolution.BezierSpline bezierSpline = GetComponent<BezierSolution.BezierSpline>();
    bezierSpline.InsertNewPointAt(2);
    bezierSpline.InsertNewPointAt(3);

    bezierSpline[0].position = new Vector3(0, 1f, 0);
    bezierSpline[1].position = new Vector3(-0.2f, 0.9f, 0f);
    bezierSpline[2].position = new Vector3(0.7f, 1.8f, 0f);
    bezierSpline[3].position = new Vector3(0.6f, 1.7f, 0);
    bezierSpline.AutoConstructSpline();

    BezierSolution.BezierWalkerWithSpeed bezierWalkerWithSpeed = GetComponent<BezierSolution.BezierWalkerWithSpeed>();
    bezierWalkerWithSpeed.spline = bezierSpline;
    bezierWalkerWithSpeed.enabled = true;

    The object unfortunately flies of too one side and does reach the final position. What am I doing wrong?
     
  25. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Do you mean that the object moves too fast?
     
  26. Lord_Slimeball

    Lord_Slimeball

    Joined:
    Dec 1, 2019
    Posts:
    10
    Also that, but the object does not reach the final position (0.6f, 1.7f, 0) at all. Do you see any problems with my code?
     
  27. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I don't see any issues. Most probably you've set BezierWalker's Speed to a very high value but it shouldn't prevent the object from reaching the final point, at least I can't reproduce it with the same code. Can you call bezierSpline.Initialize(4) instead of calling InsertNewPointAt functions?
     
  28. Lord_Slimeball

    Lord_Slimeball

    Joined:
    Dec 1, 2019
    Posts:
    10
    So the problem was I was putting the spline on the same object as where the BezierWalker was, it works now, thanks Yasirkula!
     
    yasirkula likes this.
  29. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    @Hi_ImTemmy I've updated the asset to
    v2.0.1
    . It is already available on GitHub and is currently pending review on Asset Store. Quoting the changelog:
     
  30. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    Two question:

    1) it's possible merge two or more splines at runtime?
    2) How to move along spline with speed using rigidbody instead transform?

    Thanks :)
     
  31. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    1) The easiest solution would be to set the bezier 2's points' transform parent to bezier 1 and then call bezier 1's Refresh function.
    2) You can modify BezierWalkerWithSpeed script so that it changes the Rigidbody's position and rotation values rather than Transform's position and rotation values. Then, change the Update function to FixedUpdate.
     
  32. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    1) mmmm ... I don't think it works. I'll explain, I'm building a procedural path at runtime where each chunk has a spline designed at design time with an entry point and an exit point. When the player moves and finds himself on a new chunk he starts from point 1, the problem is that he makes a small jump despite the splines are perfectly aligned, due to the new position of the rigidbody. I wanted to understand if there was the possibility of obtaining the normalizedT given the player's position, thanks to which I can reposition it in the spline without starting it from 0. However, I have not found any method that allows me to obtain this information. Also as regards the merge I do not think it can be done, as I would have to merge 2 or more splines at once including the current one where the player is and I risk invalidating all the anchors placed by hand at design time
    2) solved, thanks :)

    Actually my peace of code for bind to spline is:


    Code (CSharp):
    1.         private void HandleMovement()
    2.         {
    3.             if (!currentChunk || !currentChunk.BezierSplineComponent)
    4.                 return;
    5.  
    6.             rb.position = currentChunk.BezierSplineComponent.MoveAlongSpline(ref splineNormalizeT, forwardSpeed * movementSpeed * Time.fixedDeltaTime);
    7.  
    8.             BezierSpline.PointIndexTuple tuple = currentChunk.BezierSplineComponent.GetNearestPointIndicesTo(splineNormalizeT);
    9.             var targetRotation = Quaternion.LookRotation(tuple.GetTangent(), tuple.GetNormal());
    10.             transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, rotationSpeed * Time.fixedDeltaTime);
    11.         }
    12.  
    13.         private void OnChunkTriggered(GameObject go, bool isTrigger, Vector3 collisionPoint)
    14.         {
    15.             if (!go.CompareTag(chunkTag) || !isTrigger)
    16.                 return;
    17.  
    18.             var oldChunk = currentChunk;
    19.             currentChunk = go.GetComponent<InfinityChunk>();
    20.  
    21.             splineNormalizeT = oldChunk ? 0f : startSplinePosition;
    22.         }
    When player enter a new chunk "OnChunkTriggered" is called and i reset normalizedT to new spline but it make a wrong small jump back to position...maybe the solution is replace "oldChunk ? 0f : startSplinePosition" with "oldChunk ? <normalizeTaACurrentRigidbodyPosition> : startSplinePosition" for fix delta movement margin error when player go over point 1 on new spline
     
    Last edited: Apr 9, 2021
  33. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Perhaps BezierSpline's FindNearestPointTo function would be helpful. If the jump still occurs, try increasing accuracy parameter. If that doesn't help, see if calling HandleMovement at the end of OnChunkTriggered helps.
     
  34. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    i partially resolve with this code:


    Code (CSharp):
    1. private void HandleMovement()
    2.         {
    3.             if (!currentChunk || !currentChunk.BezierSplineComponent)
    4.                 return;
    5.  
    6.             rb.position = currentChunk.BezierSplineComponent.MoveAlongSpline(ref splineNormalizeT, forwardSpeed * movementSpeed * Time.fixedDeltaTime);
    7.  
    8.             BezierSpline.PointIndexTuple tuple = currentChunk.BezierSplineComponent.GetNearestPointIndicesTo(splineNormalizeT);
    9.             var targetRotation = Quaternion.LookRotation(tuple.GetTangent(), tuple.GetNormal());
    10.             transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, rotationSpeed * Time.fixedDeltaTime);
    11.      
    12.             if (splineNormalizeT >= 1f)
    13.             {
    14.                 currentChunk = nextChunk;
    15.                 nextChunk = null;
    16.  
    17.                 splineNormalizeT = Mathf.Clamp(splineNormalizeT - 1f, 0f, 1f);
    18.                 rb.position = currentChunk.BezierSplineComponent.GetPoint(splineNormalizeT);
    19.             }
    20.         }
    21.  
    22.         private void OnChunkTriggerEnter(GameObject go, bool isTrigger, Vector3 collisionPoint)
    23.         {
    24.             if (!go.CompareTag(chunkTag) || !isTrigger)
    25.                 return;
    26.  
    27.             nextChunk = go.GetComponent<InfinityChunk>();
    28.  
    29.             if (!currentChunk)
    30.             {
    31.                 currentChunk = nextChunk;
    32.                 splineNormalizeT = startSplinePosition;
    33.             }        
    34.         }
    i found that normalizewdT can be over 1f (and yes, this is the delta that i need) but anyway, little jump occur when pass from linear spline to curved spline, because player in this case going out of the new spline if it not continue smoothly with previous...then injstead brutal repositioning maybe is good a Lerp movement to realigned on new spline?
     
  35. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Were the results of using FindNearestPointTo (followed by a HandleMovement call, if needed) inside OnChunkTriggerEnter not good?
     
  36. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    however, it does not solve the problem. I actually solved it by adding a linear margin in the chunks with a curved spline so that we have a portion of linear continuity at the beginning and end of the chunk. In reality I don't think there is a solution at runtime because when it exits the previous chunk its position is always beyond that of point 1 of the new chunk, and if at that moment it is not linear it always goes out. Reposition it by any method does not solve the problem because there would be an immediate repositioning that should be avoided. But still I solved by graphically adjusting the chunks
     
    yasirkula likes this.
  37. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    @yasirkula however it might be a good thing to set up a function that allows you to merge two or more splines giving you a new spline as a result (without invalidating the anchors), it would be really useful in case it is feasible to do so. It would also be useful to have a method that given your position in the spline (not the spline point, real position) returns the time T :)
     
    Last edited: Apr 9, 2021
  38. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    @yasirkula i try to do this for get better normalizeT when going to next spline with position margin error:

    Code (CSharp):
    1. if (splineNormalizedT >= 1f && nextChunk)
    2.             {
    3.                 float deltaPerc = Mathf.Clamp(splineNormalizedT - 1f, 0f, 1f);
    4.                 if (deltaPerc > 0f)
    5.                 {
    6.                     float currentBezierLenght = currentChunk.BezierSplineComponent.Length;
    7.                     float estimateNextPosition = currentBezierLenght * deltaPerc;
    8.                  
    9.                     splineNormalizedT = estimateNextPosition / nextChunk.BezierSplineComponent.Length;
    10.                     rb.position = nextChunk.BezierSplineComponent.GetPoint(splineNormalizedT);
    11.                 }
    12.                 else
    13.                     splineNormalizedT = 0f;
    14.  
    15.                 currentChunk = nextChunk;
    16.                 nextChunk = null;
    17.             }
    it's work well also with two spline with different lenghts, but obviously if you have any suggestions for obtaining the normalized time considering the margin of error in passing from one spline to another I am open to suggestions (obviously it happens that the connection points between the two splines have a linear continuity for a certain length)

    PS: A very light and almost imperceptible snap between one spline and another continues to be there but honestly i have no idea how to improve it
     
    Last edited: Apr 9, 2021
  39. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    How about this approach:
    • store the previous splineNormalizeT in a variable
    • when splineNormalizeT >= 1, call
      float remainingDistance = forwardSpeed * movementSpeed * Time.fixedDeltaTime - spline.GetLengthApproximately(prevSplineNormalizeT, 1f);
    • set splineNormalizeT to 0 and if remainingDistance > 0, call MoveAlongSpline with that distance
     
  40. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    i can't understand "prevSplineNormalizeT" and "splien" is current or next?. I tried as you said but it doesn't work. I am attaching the complete script:

    [EDIT] it's worked now but little jump in some juncture splines still happens....
    [EDIT-EDIT] increasing accuracy to 100f on GetLenghtApproximately and 10 on MoveAlognSpline, the jumps are almost reduced, however i do not know why between one spline and the other there is a small deceleration of the rigidbody ... however it is becoming almost impossible to have a smooth and continuous movement between two separate splines

    Code (CSharp):
    1.  
    2.     [DisallowMultipleComponent]
    3.     public class InfinityBezierPlayer : MonoBehaviourPlus
    4.     {
    5.         #region vars
    6.         [Header("Dependencies")]
    7.         [SerializeField] protected Rigidbody rb;
    8.         [SerializeField] private TriggerCollisionDetector triggerDetector;
    9.         [SerializeField] [Tag] private string chunkTag;
    10.         [Header("Settings")]
    11.         [SerializeField] [Range(0f, 1f)] private float startSplinePosition = 0f;
    12.         [SerializeField] protected float movementSpeed;
    13.         [SerializeField] protected float rotationSpeed;
    14.         private float forwardSpeed;
    15.         private float splineNormalizedT;
    16.         private float prevSplineNormalizedT;
    17.         private InfinityChunk currentChunk;
    18.         private InfinityChunk nextChunk;
    19.         #endregion
    20.         #region behaviours
    21.         protected override void Awake()
    22.         {
    23.             base.Awake();
    24.             triggerDetector.TriggerCollisionEnter += OnChunkTriggerEnter;
    25.         }
    26.         protected override void OnDestroy()
    27.         {
    28.             base.OnDestroy();
    29.             triggerDetector.TriggerCollisionEnter -= OnChunkTriggerEnter;
    30.         }
    31.         protected override void OnPausableFixedUpdate()
    32.         {
    33.             HandleMovement();
    34.         }
    35.         private void OnChunkTriggerEnter(GameObject go, bool isTrigger, Vector3 collisionPoint)
    36.         {
    37.             if (!go.CompareTag(chunkTag) || !isTrigger)
    38.                 return;
    39.             nextChunk = go.GetComponent<InfinityChunk>();
    40.             if (!currentChunk)
    41.             {
    42.                 currentChunk = nextChunk;
    43.                 splineNormalizedT = startSplinePosition;
    44.                 prevSplineNormalizedT = startSplinePosition;
    45.             }
    46.         }
    47.         #endregion
    48.         #region spline movement
    49.         public void UpdateForwardSpeed(float normalizedSpeed)
    50.         {
    51.             forwardSpeed = Mathf.Clamp(normalizedSpeed, 0f, 1f);
    52.         }
    53.         private void HandleMovement()
    54.         {
    55.             if (!currentChunk || !currentChunk.BezierSplineComponent)
    56.                 return;
    57.             prevSplineNormalizedT = splineNormalizedT;
    58.             rb.position = currentChunk.BezierSplineComponent.MoveAlongSpline(ref splineNormalizedT, forwardSpeed * movementSpeed * Time.fixedDeltaTime);
    59.             BezierSpline.PointIndexTuple tuple = currentChunk.BezierSplineComponent.GetNearestPointIndicesTo(splineNormalizedT);
    60.             var targetRotation = Quaternion.LookRotation(tuple.GetTangent(), tuple.GetNormal());
    61.             transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, rotationSpeed * Time.fixedDeltaTime);
    62.      
    63.             if (splineNormalizedT >= 1f && nextChunk)
    64.             {
    65.                 float remainingDistance = forwardSpeed
    66.                     * movementSpeed
    67.                     * Time.fixedDeltaTime
    68.                     - nextChunk.BezierSplineComponent.GetLengthApproximately(prevSplineNormalizedT, 1f);
    69.                 splineNormalizedT = 0;
    70.                 if (remainingDistance > 0f)
    71.                     rb.position = nextChunk.BezierSplineComponent.MoveAlongSpline(ref splineNormalizedT, remainingDistance);
    72.                 /*float deltaPerc = Mathf.Clamp(splineNormalizedT - 1f, 0f, 1f);
    73.                 if (deltaPerc > 0f)
    74.                 {
    75.                     float currentBezierLenght = currentChunk.BezierSplineComponent.Length;
    76.                     float estimateNextPosition = currentBezierLenght * deltaPerc;
    77.                  
    78.                     splineNormalizedT = estimateNextPosition / nextChunk.BezierSplineComponent.Length;
    79.                     rb.position = nextChunk.BezierSplineComponent.GetPoint(splineNormalizedT);
    80.                 }
    81.                 else
    82.                     splineNormalizedT = 0f;*/
    83.                 currentChunk = nextChunk;
    84.                 nextChunk = null;
    85.             }
    86.         }
    87.         #endregion
    88.     }
    89.  
     
    Last edited: Apr 10, 2021
  41. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    @yasirkula another question: how to apply a movement offset on spline by code?
    Code (CSharp):
    1. MoveAlongSpline(ref splineNormalizedT, forwardSpeed * movementSpeed * Time.fixedDeltaTime) + splineOffsetMovement
    but this code not work also if i transformpoint from local to world....you know a method for calculate offset position?
     
  42. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I've tested your code and it worked flawlessly for me. I just needed to change transform.rotation to rb.rotation in my case. I've tried with very slow, slow, moderate and fast speeds. There were literally no jumps. I didn't even need to increase accuracy. But I made sure that the 2 splines' connected end points are at exactly the same position. Perhaps there is some distance between these 2 end points in your splines?

    You can calculate offset as follows:
    Vector3 offset = targetRotation * splineOffsetMovement;
     
    gabry90 likes this.
  43. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    yes they are all in exactly the same position, it will be a bug in the editor I don't know ... thanks for the movement with the offset and thanks for the help you gave me, you saved me days of cursing ahahaha
     
    yasirkula likes this.
  44. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    FYI, I've assigned currentChunk and nextChunk's values in Start instead of OnTriggerEnter. If OnChunkTriggerEnter is called when splineNormalizedT >= 1, then this might be the cause of the issue you're having.
     
  45. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    OnChunkTriggerEnter is always called before the player finishes the current path, however, debugging more deeply i discovered that the problem is not due to the movement of the player in the splines but to the camera .... I don't know why but if I follow in the late update with a non-physical movement of the player there are no jump
     
  46. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    In my test scene, I used a static camera so it makes sense that I didn't notice the same issue. But I wouldn't expect this issue to occur as long as OnPausableFixedUpdate was called in FixedUpdate, weird indeed.
     
  47. gabry90

    gabry90

    Joined:
    Dec 16, 2015
    Posts:
    29
    of curse OnPausableFIxedUpdate it's called at FixedUpdate time. I'll try with cinemachine instead a custom follow camera with smoothdamp. Anyway, this is my final code, and works well with both system (physical and non-physical).


    Code (CSharp):
    1.     /// <summary>
    2.     /// Class for manage player movement on spline with Infinity system integration
    3.     /// </summary>
    4.     [DisallowMultipleComponent]
    5.     [RequireComponent(typeof(InfinityRigidbody))]
    6.     public class InfinityBezierPlayer : InfinityPlayer
    7.     {
    8.         #region vars
    9.  
    10.         [Header("Dependencies")]
    11.         [SerializeField] protected Rigidbody rb;
    12.  
    13.         [Header("Settings")]
    14.         [SerializeField] private bool physicalMovement;
    15.         [SerializeField] [Range(0f, 1f)] private float startSplinePosition = 0f;
    16.         [SerializeField] protected float movementSpeed;
    17.         [SerializeField] protected float rotationSpeed;
    18.         [SerializeField] private Vector3 splineMovementOffset;
    19.  
    20.         private float forwardSpeed;
    21.         private float splineNormalizedT;
    22.         private float prevSplineNormalizedT;
    23.  
    24.         private InfinityChunk currentChunk;
    25.         private InfinityChunk nextChunk;
    26.  
    27.         /// <summary>
    28.         /// True if can move with physic
    29.         /// </summary>
    30.         protected bool enabledPhysicsMovement { get { return physicalMovement && rb; } }
    31.  
    32.         #endregion
    33.  
    34.         #region behaviours
    35.  
    36.         protected override void OnPausableUpdate()
    37.         {
    38.             if (rb)
    39.                 rb.isKinematic = !physicalMovement;
    40.  
    41.             if (!enabledPhysicsMovement)
    42.                 HandleMovement(Time.deltaTime);
    43.         }
    44.  
    45.         protected override void OnPausableFixedUpdate()
    46.         {
    47.             if (enabledPhysicsMovement)
    48.                 HandleMovement(Time.fixedDeltaTime);
    49.         }
    50.  
    51.         protected override void OnChunkEnter(InfinityChunk chunk)
    52.         {
    53.             nextChunk = chunk;
    54.             if (!currentChunk)
    55.             {
    56.                 currentChunk = nextChunk;
    57.                 splineNormalizedT = startSplinePosition;
    58.                 prevSplineNormalizedT = startSplinePosition;
    59.             }
    60.         }
    61.  
    62.         protected override void OnChunkExit(InfinityChunk chunk)
    63.         {
    64.            
    65.         }
    66.  
    67.         protected override void OnInfinityCameraWorldNeedReset(Vector3 resetPosition)
    68.         {
    69.             if (!enabledPhysicsMovement)
    70.                 base.OnInfinityCameraWorldNeedReset(resetPosition);
    71.         }
    72.  
    73.         #endregion
    74.  
    75.         #region spline movement
    76.  
    77.         /// <summary>
    78.         /// Update speed used for move player on current spline
    79.         /// </summary>
    80.         /// <param name="normalizedSpeed">Normalized time (0f - 1f)</param>
    81.         public void UpdateForwardSpeed(float normalizedSpeed)
    82.         {
    83.             forwardSpeed = Mathf.Clamp(normalizedSpeed, 0f, 1f);
    84.         }
    85.  
    86.         private void HandleMovement(float deltaTime)
    87.         {
    88.             if (!currentChunk || !currentChunk.BezierSplineComponent)
    89.                 return;
    90.  
    91.             prevSplineNormalizedT = splineNormalizedT;
    92.  
    93.             Vector3 position = currentChunk.BezierSplineComponent.MoveAlongSpline(ref splineNormalizedT, forwardSpeed * movementSpeed * deltaTime);
    94.  
    95.             BezierSpline.PointIndexTuple tuple = currentChunk.BezierSplineComponent.GetNearestPointIndicesTo(splineNormalizedT);
    96.             var targetRotation = Quaternion.LookRotation(tuple.GetTangent(), tuple.GetNormal());
    97.             Quaternion rotation = Quaternion.Lerp(enabledPhysicsMovement ? rb.rotation : transform.rotation, targetRotation, rotationSpeed * deltaTime);
    98.  
    99.             if (enabledPhysicsMovement)
    100.             {
    101.                 rb.position = position + targetRotation * splineMovementOffset;
    102.                 rb.rotation = rotation;              
    103.             }
    104.             else
    105.             {
    106.                 transform.position = position + targetRotation * splineMovementOffset;
    107.                 transform.rotation = rotation;
    108.             }  
    109.  
    110.             if (splineNormalizedT >= 1f && nextChunk)
    111.             {
    112.                 float remainingDistance = forwardSpeed
    113.                     * movementSpeed
    114.                     * deltaTime
    115.                     - nextChunk.BezierSplineComponent.GetLengthApproximately(prevSplineNormalizedT, 1f, 100f);
    116.  
    117.                 splineNormalizedT = 0;
    118.                 if (remainingDistance > 0f)
    119.                 {
    120.                     Vector3 mergedPosition = nextChunk.BezierSplineComponent.MoveAlongSpline(ref splineNormalizedT, remainingDistance, 10)
    121.                         + targetRotation * splineMovementOffset;
    122.  
    123.                     if (enabledPhysicsMovement)
    124.                         rb.position = mergedPosition;
    125.                     else
    126.                         transform.position = mergedPosition;
    127.                 }
    128.  
    129.                 currentChunk = nextChunk;
    130.                 nextChunk = null;
    131.             }
    132.         }
    133.  
    134.         #endregion
    135.     }
     
    yasirkula likes this.
  48. JohnHer

    JohnHer

    Joined:
    Jun 11, 2019
    Posts:
    6
    Is there a way to change the color of the line in the viewport?
     
  49. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
  50. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Released a major update:
     
    Last edited: May 12, 2021
    gabry90 likes this.