Bezier Solution [Open Source]

Hello there,

I’d like to share my open source bezier spline framework for Unity. Enjoy!

Asset Store: Bezier Solution | Level Design | Unity Asset Store
Also available at: GitHub - yasirkula/UnityBezierSolution: A bezier spline solution for Unity 3D with some utility functions (like travelling the spline with constant speed/time)
Discord: yasirkula Unity Assets
GitHub Sponsors :coffee:

14 Likes

Thanks for sharing! :slight_smile:

Now available on Asset Store!

2 Likes

I’m finding this tool very useful for my current project!

I found one bug in the AutoConstructSpline method (BezierSpline.cs, line 488):

endPoints[0].precedingControlPointPosition = endPoints[0].position + direction * controlPointDistance * 0.5f;

The 0.5f multiplier inappropriately shrinks the control handles of the first point of a loop spline, which warps the curve at that point. Removing the * 0.5f fixes this issue.

1 Like

Sounds great! Thank you for your help.

I’m using your bezier solution for my on-rails game. Thanks for making it, it’s fantastic! Was wondering if you could add (or point me in the direction to add myself) a way to start a follower moving from a point other than the beginning point. So if I wanted to start 50% of the way on the curve to test that part of my game, I could quickly do so?

If you are using “Once” travel mode, the fastest way would be to change “private float progress = 0f;” to “public float progress = 0f;”. Then, you can give Progress a value in range [0,1] via Inspector. Otherwise, we’d have to make a few more tweaks. Let me know in that case.

Worked like a charm, exactly what I needed. Thank you!

1 Like

Really awesome thanks!
One question re 2D usage, It seems the Look Forward turns it in Z space, any fix I can implement to make it stay in 2D ?

2 Likes

Awesome asset!!
I have assigned a sprite and box collider so that at runtime on device (not only in editor mode) the user can see and move the “Bezier Control Points”. Works well. At runtime on device the handles do not appear.

How can I assign a box collider and sprite to the handles?

Or is there another way to allow the user to adjust the handles at runtime on device (not only in editor mode)?

Try this:

if( lookForward )
{
    // Credit: http://answers.unity.com/answers/651344/view.html
    Vector2 direction = spline.GetTangent( progress ) * ( isGoingForward ? 1 : -1 );
    float angle = Mathf.Atan2( direction.y, direction.x ) * Mathf.Rad2Deg;
    Quaternion targetRotation = Quaternion.AngleAxis( angle, Vector3.forward );

    cachedTransform.rotation = Quaternion.Lerp( cachedTransform.rotation, targetRotation, rotationLerpModifier * Time.deltaTime );
}
2 Likes

@jococo Thank you! You can add two empty child objects to each point of the spline with the following component attached, as well as a sprite and a box collider:

using BezierSolution;
using UnityEngine;

public class BezierCPRuntimeEditor : MonoBehaviour
{
    private BezierPoint point;
    private bool precedingCP;
    private BezierCPRuntimeEditor otherCP;
   
    private void Start()
    {
        point = transform.parent.GetComponent<BezierPoint>();
        precedingCP = transform.GetSiblingIndex() == 0;
        otherCP = transform.parent.GetChild( precedingCP ? 1 : 0 ).GetComponent<BezierCPRuntimeEditor>();

        UpdatePosition();
    }

    public void UpdatePosition()
    {
        transform.localPosition = precedingCP ? point.precedingControlPointLocalPosition : point.followingControlPointLocalPosition;
    }

    // Should be called when dragged via BoxCollider
    public void OnDrag()
    {
        if( precedingCP )
            point.precedingControlPointLocalPosition = transform.localPosition;
        else
            point.followingControlPointLocalPosition = transform.localPosition;

        otherCP.UpdatePosition();
    }
}

EDIT: fixed a bug in the code.

Thanks for the fast reply!

It may not work while dragging the object in Scene view but it should work when you call OnDrag on the dragged control point (if you call both control points’ OnDrag simultaneously, one control point may always override the other; similar to what you are experiencing). Are you sure that OnDrag is only getting called for the dragged control point? Also, are you possibly calling the UpdatePosition function manually somewhere in your code?

1 Like

Thanks so much for the quick reaction.
It works!

1 Like

Cool! Thanks for the tips. It seems to be working well.

I need to have the control point handles to be oriented 90degrees from created position. I’m creating a mobile app and having them oriented 90 degree offset helps with UI. Attached is a pic if that helps. Is this fairly easy code mod?

3508067--279947--bezier-change.jpg

This one works if your points are scattered across the XY plane and all have the same position-z value:

using BezierSolution;
using UnityEngine;

public class BezierCPRuntimeEditor : MonoBehaviour
{
    private BezierPoint point;
    private bool precedingCP;
    private BezierCPRuntimeEditor otherCP;

    private Vector3 INWARDS = new Vector3( 0f, 0f, 1f );
    private Vector3 OUTWARDS = new Vector3( 0f, 0f, -1f );

    private void Start()
    {
        point = transform.parent.GetComponent<BezierPoint>();
        precedingCP = transform.GetSiblingIndex() == 0;
        otherCP = transform.parent.GetChild( precedingCP ? 1 : 0 ).GetComponent<BezierCPRuntimeEditor>();

        UpdatePosition();
    }

    public void UpdatePosition()
    {
        Vector3 position = precedingCP ? point.precedingControlPointLocalPosition : point.followingControlPointLocalPosition;
        transform.localPosition = Vector3.Cross( position, INWARDS );
    }

    // Should be called when dragged via BoxCollider
    public void OnDrag()
    {
        Vector3 position = Vector3.Cross( transform.localPosition, OUTWARDS );
        if( precedingCP )
            point.precedingControlPointLocalPosition = position;
        else
            point.followingControlPointLocalPosition = position;

        otherCP.UpdatePosition();
    }

    // Does the same thing without requiring you to call OnDrag manually
    // and works in editor as well, but uses Update and is therefore slower
    // If uncommented, comment OnDrag
    //public void Update()
    //{
    //    if( transform.hasChanged )
    //    {
    //        Vector3 position = Vector3.Cross( transform.localPosition, OUTWARDS );
    //        if( precedingCP )
    //            point.precedingControlPointLocalPosition = position;
    //        else
    //            point.followingControlPointLocalPosition = position;

    //        otherCP.UpdatePosition();

    //        transform.hasChanged = false;
    //        otherCP.transform.hasChanged = false;
    //    }
    //}
}

If you use a different plane, try changing the values of INWARDS and OUTWARDS.

Protip: for a smoother spline in Game view, call spline.DrawGizmos(color,smoothness) function at Start function.

1 Like

Awesme! Thank you for yet another fast and effective reply!

Yeah I have no z depth.

Now all I need to do is figure out how to constrain bez points to only the X axis. I assume that constraint can be done in my drag and drop routine?

I agree.

yasirkula, first of all, congratulations for the amazing job you did with this asset. Incredible!

I’m already using your asset on my project for moving sprites with curves, but I was wondering if there is a way to draw a line renderer into it. I want to draw some circles on the object’s path, so the player can know which way the object will follow, just like some baskets on Dunk Shot =)

Sorry if you’ve already explained this somewhere and I didn’t noticed!

Thanks and congratulations again!