Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
1
Question by PvtPuddles · Feb 25, 2020 at 03:57 AM · pathfollowingbezier

How can you make a path with a switch in it?

I have been thinking this project over for a couple years, but I cannot figure out how to make an object follow a bezier curve, but able to swap to a different path midway (say with a railroad switch).

Recently I have been working with Sebastian Lague's Path Creator tool (which is outstanding for applications outside of this, by the way), but there is no easy way to split a path into two. The route I was planning on taking was switching the path object attached to the follower when it reached the end of the path to one of the two paths that start at that endpoint. Unfortunately, Lague's end behavior is math based (ie. clamp the %-time value to 1) as part of calculating it's position, and thus there is no easy (to my untrained eye) way to access the endpoint behavior outside of this system.

Does anyone have any other suggestions for creating a pathing system that can be split, merged, and otherwise futzed around with? The only other option I'm seeing would be to rebuild Lague's with easier to access end behavior, but that would be an enormous time sink for a tiny change.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by PvtPuddles · Feb 27, 2020 at 09:14 PM

With enough hours swearing and crying, I though it would be best to share my solution, so that all of y'all can use this if you need it. This solution is based off of Sebastian Lague's Path Creator, which videos of can be found on YouTube (as well as download links).


Step 1: Disable Lague's default Endpoint Behavior

Lague did an excellent job making loop, reverse, and stop behavior using clamp01, pingpong, and the like, but we don't need it. Instead, we will add a fourth option to EndOfPathInstruction, SwitchPath.

 public enum EndOfPathInstruction {SwitchPath, Loop, Reverse, Stop};

This will allow the block to reach the end of the path.

Step 4: Add some helper functions

In vertexPath.cs, navigate to the Public methods and Actors field, where we will add the following two methods:

 public float GetTAtDist(float dst, EndOfPathInstruction endOfPathInstruction = EndOfPathInstruction.SwitchPath)
         {
             float t = dst / length;
             return t;
         }
         
         // Gets a distance value based on t value
         public float GetDistAtT(float t, EndOfPathInstruction endOfPathInstruction = EndOfPathInstruction.SwitchPath)
         {
             float dist = t * length;
             return dist;
         }

While this functionality is already built into Lague's system, it relies on the time value t to always be between 0 and 1, but we need to be able to tell when t is outside of those bounds.

Step 3: Add our own Endpoint Behavior

First, we will add a RailController.cs script to the current rail (or path) to store what the next and previous rails are to this one. using System.Collections; using System.Collections.Generic; using UnityEngine;

 namespace PathCreation.Examples
 {
     public class RailController : MonoBehaviour
     {
         public GameObject previousRail;
         public GameObject nextRail;
 
 
         public GameObject NextRail()
         {
             if(nextRail != null)
             {
                 return nextRail;
             }
             return null;
         }
         public GameObject PreviousRail()
         {
             if (previousRail != null)
             {
                 return previousRail;
             }
             return null;
         }
     }
 }

The game objects attached to this script should be the parent objects that Lague's PathCreator script is attached to for the next and previous rail, respectively.

Next, in PathFollower.cs, we need to add:

 public GameObject rail;
 public RailController railController;
 float railDist;

Note: railDist is being used to replace distanceTraveled, so that we can continue tracking the total distance the object has traveled. If this is not important to you, you can continue using distanceTraveled wherever you see railDist.

 if (rail != null)
        {
            pathCreator = rail.GetComponent<PathCreator>();
            railController = rail.GetComponent<RailController>();
        }

Remember to initialize the path creator and rail controller in start().

In update(), we are going to want something that looks like this:

 if (rail != null)
                 {
                     if (pathCreator != null)
                     {
                         //Total distance traveled
                         distanceTravelled += speed * Time.deltaTime;
                         //Distance on this particular rail
                         railDist += speed * Time.deltaTime;
     
                         transform.position = pathCreator.path.GetPointAtDistance(railDist, endOfPathInstruction);
                         transform.rotation = pathCreator.path.GetRotationAtDistance(railDist, endOfPathInstruction);
                     }
     
                     if (endOfPathInstruction == EndOfPathInstruction.SwitchPath)
                     {
                         float t = pathCreator.path.GetTAtDist(railDist, endOfPathInstruction);
                         // Goes to previous rail if you have backed off
                         if (t <= 0 && railController.PreviousRail())
                         {
                             // Updates the rail that the follower is on, as well as the pathcreator object
                             rail = railController.PreviousRail();
                             pathCreator = rail.GetComponent<PathCreator>();
                             railController = rail.GetComponent<RailController>();
                             // Puts the follower at the end of the next rail, rather than the beginning
                             railDist = pathCreator.path.GetDistAtT(1, endOfPathInstruction);
                         }
                         // Goes to next rail
                         else if (t >= 1 && railController.NextRail())
                         {
                             // Updates the rail that the follower is on, as well as the pathcreator object
                             rail = railController.NextRail();
                             pathCreator = rail.GetComponent<PathCreator>();
                             railController = rail.GetComponent<RailController>();
                             // Puts the follower at the beginning of the next rail, rather than the end
                             railDist = 0;
                         }
                     }
                 }

At this point, we should have the ability to move from one path to another (which don't necessarily even need to touch), which at the moment is a little redundant, given that Lague has support for compound curves. However, the real treat is in....

Step 5

Now we have the infrastructure to create a short and simple SwitchController.cs. This gets attached to the base of the switch, or the segment before the split.

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 namespace PathCreation.Examples
 {
     public class SwitchController : MonoBehaviour
     {
         public bool nextRail = true;
         public int target = 1;
         public GameObject option1;
         public GameObject option2;
         private RailController rail;
 
         void Update()
         {
             rail = gameObject.GetComponent<RailController>();
         if (nextRail)
         {
             if (target == 1)
             {
                 rail.nextRail = option1;
             }
             else
             {
                 rail.nextRail = option2;
             }
         }
         else
         {
             if (target == 1)
             {
                 rail.previousRail = option1;
             }
             else
             {
                 rail.previousRail = option2;
             }
         }
         }
     }
 }

Option 1 and 2 are the game objects of the two rails you want the switch to switch between, and target is a simple int to change the rail selected, and is scale-able up to as many rails as you want per junction. Disable nextRail if the switch is a merger, so that going backwards it still acts like a switch.

With this, you should be done. If you find any errors with this (besides nullpointer errors, because I haven't even started to weed those out), please let me know. Also, this code is horrendous. Any suggestions for improved readability or just simplification would be greatly appreciated!

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image sandalu_gamo · Jan 19, 2021 at 07:07 AM 0
Share

Where do we add SwithController?

avatar image PvtPuddles sandalu_gamo · Jan 23, 2021 at 05:34 PM 0
Share

Lets say we have a 'y' junction with two 'arms' and a 'base'. You want to add the switch controller as a component to the rail you are using as the base. Options 1 and 2 are the two arms that the switch will swap between.

avatar image Mookmac · Jan 01 at 07:05 PM 0
Share

This is awesome, I was also trying to work out a solution to the move to another path at end problem. I've tried to take your solution from the answer here but run into a small issue where an index out of bounds exception occurs in VertexPath.CalculatePercentOnPathData at the point where there's a while loop trying to find the closest vertices. This happens at the end of my path. Is there something missing from your answer, perhaps a new case statement for SwitchPath which needs adding to this method?

thanks in advance

avatar image Mookmac Mookmac · Jan 01 at 07:15 PM 1
Share

Follow up - I've lazily worked around the issue by constraining the index "i" with a Math.Min call so I have: int i = System.Math.Min((NumPoints - 1), Mathf.RoundToInt (t * (NumPoints - 1))); // starting guess

avatar image PvtPuddles Mookmac · Jan 01 at 07:50 PM 0
Share

I don’t recall running into this problem myself, but that sounds like a viable solution

avatar image
0

Answer by streeetwalker · Feb 25, 2020 at 06:48 PM

Interesting problem. I'm sure you can dig into his code and find where the actual control points are.

He does provide a method, if you read his documentation to, to create a Bezier path using a list of Vector2 or 3's. If you did that, then you'd know where the endpoints are...

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image PvtPuddles · Feb 26, 2020 at 03:08 AM 1
Share

...yes. So you are right that finding the endpoints isn't too hard, but what I am looking for is something more along the lines of the object that follows the path figuring out whether or not it is at the end of the path it is on. This is tricky because as far as the object is aware, it gives its current position to the path object, then the path does a bunch of magic-wizardry, then returns a new position for the object to move to. During that magic wizardry, the path handles cases where the object has finished following the path. It is not clear to me if the path can then communicate back to the follower object and tell it that it has reached the end (or the beginning, if it is going backwards).

avatar image streeetwalker PvtPuddles · Feb 26, 2020 at 04:04 AM 0
Share

$$anonymous$$aybe you're trying to make it too hard? If you know the start and end points say in world coordinates (and any points in between that you've passed to that function), you can compare world position of the object as it moves it to those points outside of anything his script is doing.

So you write a script that compares those in an update loop. Then when the object is close enough to one of those points, I'm sure you can figure out how to kill the current animation and swap it out to a new path... Not sure how easy that is but it is doable. Seems like you just need to remove the object from it's parent path and make it a child of the new path.

You might contact him, because I am sure he is approachable and up for suggestions. $$anonymous$$aybe he'd consider adding features that would allow you to say, jump an object to a new path, or take a longer path and split it up if you don't want to figure it out yourself. At the very least I think he'd give you some pointers.

avatar image PvtPuddles streeetwalker · Feb 26, 2020 at 03:39 PM 0
Share

I think I am making it a little too hard, but thats mostly because this is going to be the base of my game, so it needs to work exactly how I would like it to. Your solution sounds plausible, so I may resort to that as a last-ditch solution. The main problem I see with it is when speed is high, but the segment length is low. In this scenario, it is possible to move past the entire segment in one frame, and so the path never realizes you passed the end. This is a problem I had grappled with in previous attempts, but using the t time values, Lague's completely solves it. Once you know you need to swap out the path, it's nice and easy. You just assign a different path node to the follower, so that shouldn't be a problem. Lague's script even takes care of making sure that the object is on the path you swap to.
I'll see if I can shoot him an email, but this project of his is over a year old, so it's a hit or miss.

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

200 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Using triggers to then follow a specified path 0 Answers

Making the player follow a path 0 Answers

Math Library for bezier curves. 0 Answers

Hi, I'm working on a city traffic project My problem is that cars always   At each point of the path they come to the starting point of the track when starting the game While I want to move where they are placed along the designated path this is my code 0 Answers

How can I setup a AI Bot to Pathfind around my small map? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges