A simple way to round path corners?



  • @Baroni Is there an example project for bezier path on runtime just like the runtime project for regular path we have?
    I'm having hard time figuring out how and all the steps I need to go through because in BezierPathEditor, it looks very complicated unlike regular path and I really wish there was some sort of a guideline that illustrates each step. For the regular path no guideline was needed due to its simplicity but this, is something else :/



  • @Baroni Actually.. never mind I think I got it lol Thanks!



  • @Baroni Actually.. I can't. I tried with BezierPathEditor class but I really can't figure out how to create BezierPath on runtime and avoid the use of editor completely. Help please?



  • @Baroni Ok so I actually made it work. It's a lot more work to round corners because curving one waypoint distorts the entire path not just the corners so you have to store indexes of corner points while adding 2 extra points that support/hold the corner points so you can only add curve to the corners as seen below -

    alt text
    alt text

    But it still has a problem I cannot solve.
    In design tools, (my background's graphic design) for the obvious reasons (cus they're DESIGN tools) editing one curve changes the surrounding curves accordingly and nicely however it looks like it's impossible to do that with SWS or is there a way? I tried to do it manually but I can't even do the basic stuff like editing anchor points which is crucial in shaping curves as seen below -

    alt text

    I really need to have full control of shaping curves for each point instead of just giving bPoints 2 control point values.

    Thanks..!



  • Ok so I finally figured it out and I couldn't find any info on this on the forum so I'm sharing my experience in case someone else needs this.

    If you want rounded corners you need a completely different approach. You'll need to first store all the waypoint positions and then add 2 waypoints one on the left and the other on the right then remove the waypoint in between.

    alt text

    And you also need to keep track of which side of "tile" each waypoint is at. For example, in my case it's isometric therefore top-left, top-right, bottom-left, bottom-right etc because different curves needs different anchor values.

    Then when you're about to actually create waypoints, you give each anchor different values accordingly... this is indeed the most tedious task I've done in 2020 so far lol
    I bet there's a way to automate this... somehow let a function to calculate each value depending on the positions of the waypoints and desired corner radius value... I had to try each value hundreds of times to make it right. The result I got is still not perfect it still looks a little awkward but at least now I know how to get this done...

    alt text

    private void TileSideSetter(WorldTile backWT, WorldTile targetWT, WorldTile cornerBackWT, WorldTile cornerFrontWT)
        {
            WaypointDirection backDir = backWT.Direction;
            WaypointDirection targetDir = targetWT.Direction;
    
            TileType targetType = targetWT.TileType;
    
    
            if (backDir == WaypointDirection.Vertical && targetDir == WaypointDirection.Horizontal && targetType == TileType.Left)
            {   // ^
    
                cornerBackWT.TileSide = TileSide.Top_Left;
                cornerFrontWT.TileSide = TileSide.Top_Right;
            }
            else if (backDir == WaypointDirection.Horizontal && targetDir == WaypointDirection.Vertical && targetType == TileType.Right)
            {   // v
    
                cornerBackWT.TileSide = TileSide.Bottom_Left;
                cornerFrontWT.TileSide = TileSide.Bottom_Right;
            }
            else if (backDir == WaypointDirection.Horizontal && targetDir == WaypointDirection.Vertical && targetType == TileType.Left)
            {   // <
    
                cornerBackWT.TileSide = TileSide.Left_Bottom;
                cornerFrontWT.TileSide = TileSide.Left_Top;
            }
            else if (backDir == WaypointDirection.Vertical && targetDir == WaypointDirection.Horizontal && targetType == TileType.Right)
            {   // >
    
                cornerBackWT.TileSide = TileSide.Right_Bottom;
                cornerFrontWT.TileSide = TileSide.Right_Top;
            }
        }
    
    left.position = bp.wp.position;
            if (i != 0)
            {
                switch (wt.TileSide)
                {
                    case TileSide.Top_Left:
    
                        left.position += new Vector3(0.04f, 0.04f, 0);
                        break;
                    case TileSide.Top_Right:
    
                        left.position += new Vector3(0.00f, 0.00f, 0);
                        break;
                    case TileSide.Bottom_Left:
    
                        left.position += new Vector3(0.04f, -0.04f, 0);
                        break;
                    case TileSide.Bottom_Right:
    
                        left.position += new Vector3(0.00f, 0.00f, 0);
                        break;
                    case TileSide.Left_Bottom:
    
                        left.position += new Vector3(-0.03f, 0.01f, 0);
                        break;
                    case TileSide.Left_Top:
    
                        left.position += new Vector3(0.00f, 0.00f, 0);
                        break;
                    case TileSide.Right_Bottom:
    
                        left.position += new Vector3(0.03f, 0.01f, 0);
                        break;
                    case TileSide.Right_Top:
    
                        left.position += new Vector3(0.00f, 0.00f, 0);
                        break;
                }
            }
    right.position = bp.wp.position;
            if (i + 1 != pm.bPoints.Count)
            {
                switch (wt.TileSide)
                {
                    case TileSide.Top_Left:
    
                        right.position += new Vector3(0.02f, -0.01f, 0);
                        break;
                    case TileSide.Top_Right:
    
                        right.position += new Vector3(-0.02f, 0.01f, 0);
                        break;
                    case TileSide.Bottom_Left:
    
                        right.position += new Vector3(0.00f, 0.00f, 0);
                        break;
                    case TileSide.Bottom_Right:
    
                        right.position += new Vector3(-0.02f, -0.01f, 0);
                        break;
                    case TileSide.Left_Bottom:
    
                        right.position += new Vector3(0.00f, 0.00f, 0);
                        break;
                    case TileSide.Left_Top:
    
                        right.position += new Vector3(-0.02f, -0.01f, 0);
                        break;
                    case TileSide.Right_Bottom:
    
                        right.position += new Vector3(-0.02f, 0.01f, 0);
                        break;
                    case TileSide.Right_Top:
    
                        right.position += new Vector3(0.02f, -0.01f, 0);
                        break;
                }
            }
    


  • Sorry for the delay and thank you for sharing your process.

    It could be obvious, but as I wrote above, when using bezier paths did you actually try to select a waypoint and adjust its handles? Like I wrote above:

    the handles don't know how your requirement, on how far their distance should be to the waypoint

    So in the image below, dragging the blue handle even more to the top (distance to waypoint increases) would create a sharper curve. There is no need for an additional waypoint in the curve. The curve is defined by the handles on Waypoint 1 & 2.

    alt text

    A bezier path can be created by code. In addition to the waypoint transform, you will need additional two transforms for the left+right handle. They go in the "cp" array of the BezierPoint class (bPoints list).

    Scripting Reference:
    https://www.rebound-games.com/docs/sws/BezierPathManager.html



  • What.... I thought you meant bPoints by control points... was not aware of cp[transform]...

    So I just tried it out but how do you make the control point handles appear on the scene? I have given cp points values hence I see it rounded but can't figure out how to view its handles. The blue and red handles.

    Also you have 2 waypoints by the corner just like how I did recently instead of 1 waypoint at all corners.
    I just tried manipulating control points with only 1 waypoint at each corner and from far it looks fine but when I get closer it's actually awkward.. It is round but it doesn't look quite the way I want it to look.
    How are you setting the handle values? (cp[transform])



  • Also.. for rounding purpose you recommend cp but then what about bPoints? bPoints also create curves but probably not the same way but how..?

    I've played with cp for a bit now and I'm not getting the result I want at all the curve looks so awkward.. even worse than making curves by bPoints' left & right.



  • Your questions are confusing :-D

    As you can see in the scripting reference, "bPoints" is a list of "BezierPoint" classes. Each bezier point has a "wp" waypoint transform (yellow dot in the above screenshot)
    as well as a "cp" transform array for two control point transforms (blue dots in the above screenshot), shaping the curves for that waypoint.

    When creating bezier paths you need both. One Waypoint transform and two control point transforms.

    How are you setting the handle values? (cp[transform])

    Via code, just like you do it for a regular path. Create a transform and assign it to bPoints[index].cp[0 or 1]. Which one is left or right is written in the scripting documentation for BezierPoint. You always need to set both, left and right.

    In the editor, you just click on a waypoint (yellow dot) to make the blue handles appear. If they are not shown you probably have "Show Handles" disabled on the BezierPathManager.

    I've played with cp for a bit now and I'm not getting the result I want at all the curve looks so awkward

    If you create and modify the bezier path at runtime, you probably missed calling CalculatePath() on the BezierPathManager to recalculate the path.



  • Ugh... Sorry it turns out I already have been setting cp values programmatically this entire time lol
    I thought what I've been setting was different from cp.
    Yes I am setting cp values and recalculating etc

    However when I tried with only 1 waypoint at each corner, the result was not good it looked so awkward. It did not round corners the way I wanted hence using 2 waypoints around the corners did the trick. Perhaps this is because I just don't know how to apply cp values correctly but with 2 waypoints I got it work.

    So this is what I have -

    left.position = bp.wp.position;
            if (i != 0)
            {
                switch (wts[i].TileSide)
                {
                    case TileSide.Top_Left:
                        left.position += new Vector3(0.04f * rad, 0.02f * rad, 0);
                        break;
                    case TileSide.Top_Right:
                        break;
                    case TileSide.Bottom_Left:
                        left.position += new Vector3(0.04f * rad, -0.02f * rad, 0);
                        break;
                    case TileSide.Bottom_Right:
                        break;
                    case TileSide.Left_Bottom:
                        left.position += new Vector3(-0.04f * rad, 0.02f * rad, 0);
                        break;
                    case TileSide.Left_Top:
                        break;
                    case TileSide.Right_Bottom:
                        left.position += new Vector3(0.04f * rad, 0.02f * rad, 0);
                        break;
                    case TileSide.Right_Top:
                        break;
                }
            }
            right.position = bp.wp.position;
            if (i + 1 != pm.bPoints.Count)
            {
                switch (wts[i].TileSide)
                {
                    case TileSide.Top_Left:
                        break;
                    case TileSide.Top_Right:
                        right.position += new Vector3(-0.02f * rad, 0.01f * rad, 0);
                        break;
                    case TileSide.Bottom_Left:
                        break;
                    case TileSide.Bottom_Right:
                        right.position += new Vector3(-0.02f * rad, -0.01f * rad, 0);
                        break;
                    case TileSide.Left_Bottom:
                        break;
                    case TileSide.Left_Top:
                        right.position += new Vector3(-0.02f * rad, -0.01f * rad, 0);
                        break;
                    case TileSide.Right_Bottom:
                        break;
                    case TileSide.Right_Top:
                        right.position += new Vector3(0.02f * rad, -0.01f * rad, 0);
                        break;
                }
            }
    
            bp.cp = new[] { left, right };
            bp.wp.parent = pm.transform;
            bp.wp.SetSiblingIndex(i);
            pm.segmentDetail.Insert(i, pm.pathDetail);
            pm.bPoints.Insert(i, bp);
        }
    

    And I click on a waypoint but handles won't show up.

    alt text


Log in to reply