Search Unity

Dynamic Rail System

Discussion in 'Scripting' started by Dranore, Jun 15, 2007.

  1. Dranore

    Dranore

    Joined:
    May 23, 2007
    Posts:
    57
    I'm using this as a sort of mental scratching pad.

    Another experiment I've been playing with to learn by is to make some sort of dynamic rail system. Preferably one that could be attached and detached from on the fly. It seems easy to make objects follow the waypoints once on the rail, but is there a way to detect collisions with the space between the two points? I want to have something that doesn't need to have lots of box collisions set up manually. I want to just be able to lay out the way points and have the attach/detach script deal with the placement on the rail based on the relationship between the two rails. Or perhaps something that generates and scales the colision boxes automatically? I dunno. Not sure of the best approach offhand. Thinking it over still. If anyone here has already done some work along these lines, I'm interested in your thoughts.

    Ultimately with little modification the user experience should follow that the user would be able to guide any sort of avatar (first or third person) up to the rail or begin on the rail, if off - trigger the attach, then begin moving on the rail in a fixed direction or direction relative to original direction of the avatar/camera at either a constant or physics based momentum, and then be able to detach either on command or at the last way point.

    EDIT: I think I'll start with the dynamic collision box generation.

    EDIT 2: W00T! I have it laying out collision boxes the along paths. Also cleaned up the code. Have to stop for the moment. Will post the code later and as I work on it here.
     
  2. shepherd

    shepherd

    Joined:
    Oct 16, 2006
    Posts:
    12
    I'm not sure if this is what you want, but here is what I did to follow a rail...

    I created a spline in Max, then attached a dummy object to the spline. Then, I had the dummy object follow the spline as an animation and exported that. Within Unity, I attach my character to the dummy object (sometimes with a collision trigger), and play the animation on the dummy object. This drags the character along with the dummy object. Should he hit something (again, another collision trigger), I detach him from the dummy object. Is this along the lines you are looking for?
     
  3. Dranore

    Dranore

    Joined:
    May 23, 2007
    Posts:
    57
    That's an interesting solution, not quite what I had in mind, but good food for thought.

    Here's the afore mentioned code I've been working on. Now I have to figure out how I want to attach and detach the character - which I'm still thinking over.

    My first goal is thus: When the player collides with the box, attach the player to the rail at the position where the player collided with the box. Then I'll force the player controls to move only towards the next point and still allow the player controls to move forward and backward on the rail, then I'll add the constant motion and physics/momentum stuff.

    Again, I want it to be versatile, so with only a little modification you can apply it to whatever situation.

    For anyone interested, here is the rail generation code at the moment. If you can think of a more efficient way to handle any of this, feel free to make recommendations.

    Code (csharp):
    1. // The next RailPoint, this variable needs to be assigned in the inspector.
    2. var nextRailpoint : RailPoint;
    3. var lastRailpoint : RailPoint;
    4. var endRailpoint : boolean = false;
    5. private var rail : Object;
    6.  
    7.  
    8. // Set the rail's collider width and height, the length is determined by distance between this RailPoint and the next
    9. var railWidth = 1;
    10. var railHeight = 1;
    11.  
    12. //Point to the CollisionBox prefab
    13. var boxPrefab : Transform;
    14.  
    15. function Awake () {
    16.     //Generate the CollisionBoxes on Awake - if it's not the end of the rail.
    17.     if (nextRailpoint) {
    18.         GenerateCollisionBox(nextRailpoint.transform.position);
    19.     }
    20. }
    21.  
    22. function Update () {
    23.     // If it's not the end of the rail
    24.     if (nextRailpoint != null) {
    25.         // For testing purposes only, updates the rail if you drag it around in the Scene.
    26.         UpdateCollisionBox(nextRailpoint.transform.position, rail);
    27.     }
    28. }
    29.  
    30. // Dynamically creates and scales the collision box for the rail from a prefab cube
    31. function GenerateCollisionBox (position : Vector3) {
    32.    
    33.     // Create the rail collision box...
    34.     rail = Instantiate ( boxPrefab, transform.position, transform.rotation);
    35.    
    36.     // Call the update to set the size and position...
    37.     UpdateCollisionBox(position, rail);
    38.    
    39. }
    40.  
    41. // Use this in your Update() function if you have have a dynamically moving/stretching waypoint...
    42. function UpdateCollisionBox (position : Vector3, rail) {
    43.    
    44.     // Determine the length of the box by comparing the distance between the two points
    45.     var railLength = Vector3.Distance (transform.position, position);
    46.  
    47.     // ... and point the box at the next target. Then set the size and position it.
    48.     // Finally make it a child of the current RailPoint.
    49.     rail.transform.LookAt(nextRailpoint.transform);
    50.     rail.collider.size = Vector3(railHeight,railWidth,railLength);
    51.     rail.collider.center.z = railLength/2;
    52.     rail.transform.parent = transform;
    53. }
    54.  
    55. // Draw the RailPoint pickable gizmo
    56. function OnDrawGizmos () {
    57.     Gizmos.DrawIcon (transform.position, "R.tif");
    58. }
    59.  
    60. // Draw the RailPoint lines only when you select one of the waypoints
    61. function OnDrawGizmosSelected () {
    62.     if (nextRailpoint) {
    63.         Gizmos.color = Color.green;
    64.         Gizmos.DrawLine (transform.position, nextRailpoint.transform.position);
    65.     }
    66.     if (lastRailpoint) {
    67.         Gizmos.color = Color.red;
    68.         Gizmos.DrawLine (transform.position, lastRailpoint.transform.position);
    69.     }
    70. }
    EDIT: Okay. A bit more practical of a question. So I'm not sure how to distribute the code. The code above is great for making the rails. But now I need to figure out how to distribute the functionality. I need the player to collide with the above boxes. Then attach to the rail at the point. Get the next or current rail point (based on current angle of the player on collision). Move the player onto the rail and make it look at the next point and only allow players to move forward toward that point until collision and then get the next point and so on.

    So I need to need to detect when the player hits the box and then move the player based on that collisions. So it sounds like I need to have a new script for the boxes detecting the collisions that passes info to the player maybe? Then the RailRide script on the player to control the players movement? And some how pass info around these three scripts? Hmm... That's not sounding very clear to me at this point on how to divide up the functionality.
     
  4. Dranore

    Dranore

    Joined:
    May 23, 2007
    Posts:
    57
    Anybody have any suggestions? I'm kinda stumped here on how to approach...
     
  5. dacloo

    dacloo

    Joined:
    Jun 30, 2005
    Posts:
    469
    I am not sure if I understand you correctly :)
    Do you have a screenshot explaining the situation?
     
  6. Dranore

    Dranore

    Joined:
    May 23, 2007
    Posts:
    57
    Perhaps a visual will indeed help. I've attached a simple diagram. Pardon the crude.

    There exists "rails" in the scene. They are effectively waypoints. Empty game objects with the above posted script attached. This allows easy setup of railpoints and their collision boxes. In the diagram there are two such points "C" and "N" - which represent "currentRailpoint" and "nextRailpoint" respectively. The collision box (the grey wireframe in the diagram) is a child object of point C.

    So the blue circle would be an entity that can collide with the "rail" box collider (a player or enemy or camera or whatever you want to have use the rails). The blue object collides with the box at the yellow point. The blue object is then "attached" to the rail and moved to the green point, which is the place on the rail closest to the collision point. Once the player is attached, it's control scheme is changed to a different one and the player is automatically moved along the rail until it reaches point N, where it either follows the next rail or detaches (restoring the original controls) if there is no nextRailpoint defined.

    I hope that helps. If not, let me know, and I will attempt to clarify further.

    I believe I need to add a secondary collision box to the railpoints themselves to trigger the change between rails, I'm more worried about figuring out how to divide up the functionality at this point.

    EDIT: I updated the above script to it's current version. Didn't handle not having a nextRailpoint - now it works as it should at this point.
     

    Attached Files:

  7. aaronsullivan

    aaronsullivan

    Joined:
    Nov 10, 2005
    Posts:
    986
    Hmm... just some quick thoughts.

    As soon as the blue object collides, measure the distance between it and C (Vector3.distance() I believe.)

    Then, you can use a Ray with the same distance to figure out the green point (that is a rough number, though, you could do better with that.)

    You could lock the blue object right to the new found point instantly or do some sort of Vector3.Lerp()... Probably would look best if you LERPed from where you were to where it "should" be on the rail ( a point that begins moving right at collision time.)

    Now, just keep moving the object to a point that can be determined over and over by using a Ray with an ever increasing distance until it reaches N.

    Does that help?
     
  8. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
  9. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Ignore that. ;) I have a better system now that reads data from the mesh directly so it doesn't use physics, with an optional camera angle editor for the path. It constructs bezier curves from the mesh data at run-time, so you can use few points and still get perfectly smooth non-linear movement. I'm working on some other stuff at the moment, but I'll clean it up and post a project folder by the end of the week probably.

    --Eric
     
  10. drJones

    drJones

    Joined:
    Oct 19, 2005
    Posts:
    1,351
    yeah, but does it run linux?

    ; )

    seriously though that sounds really cool.
     
  11. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Nope. ;) I stumbled on this page a little while ago, which gave me the idea. It's actually relatively simple, and since the code there is Actionscript, that made it easy enough to understand and steal a couple of lines from (given that it's pretty similar to Javascript in Unity).

    OK, thread hijack over! Sorry. :)

    --Eric
     
  12. Dranore

    Dranore

    Joined:
    May 23, 2007
    Posts:
    57
    W00t. Thanks for the responses. I'm excitedly curious to see your newer method in action Eric.

    Ideally I'd like this to be able to be both smoothed and angular depending on it's application, and it would be really cool if I could somehow flag or separately export the verts on a models that would be the railPoints and them have Unity automatically plug them in if I wanted.


    Anywho, Aaron, that sounds like a very reasonable approach. I'll play with that - thanks.

    Actually - and perhaps I'm just being stupid - my issue now is figuring out which object should have what functions - and then getting them to retrieve the right variables from the different scripts - which are at least three so far - something for the box - something for the railPoints - and something for the collidee.

    The rail collision box has to detect the collision. The railPoint objects have the path information stored in the variables. The blue object needs to change it's "mode" and somehow get info from the relevant railPoints when it makes the collision.

    I just can't seem to wrap my head around it. I'll keep playing though. Thanks again for the help so far. Keep it coming. I guess I just have to post more pictures. hehehe...