Search Unity

360 degree movement inside of cylinder

Discussion in 'Scripting' started by AlexGorcea, Sep 17, 2014.

  1. AlexGorcea

    AlexGorcea

    Joined:
    Aug 20, 2013
    Posts:
    22
    Hello everyone.

    I've been scratching my head about this for a month now. How can I achieve a movement like the one here?



    There's a cylinder, and the object sticks to the interior walls, effectively performing a 360 degree spin. Also, there's the issue of the cylinder bending in some parts, so it's effectively a magnetic field holding the object down (or up, or whichever way).
     
  2. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    Which objects are you talking about? Obstacles or the player?

    The obstacles look like they're a child of the tunnel. The player meanwhile either has something moving him down continuously kinda like gravity, or the player is positioned to be a specific distance from the tunnel's center. There could be a spline that runs down the center of the tunnel that can be used to position things a certain distance from the center.
     
  3. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    As for rotations...

    I'm pretty sure there's something representing the middle of the tunnel, even if it's not visible. The middle would be a line or a spline. You could rotate the player around using Transform.RotateAround() with the center line/spline as the axis of rotation.
     
  4. AlexGorcea

    AlexGorcea

    Joined:
    Aug 20, 2013
    Posts:
    22
    I might try with Transform.RotateAround() for the player. Mind if I keep the thread for prototyping?
     
  5. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    Feel free to keep the thread open, though you might get quicker and better answers by making a new concise topic for each specific problem you run into. Whatever works best for you!
     
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I did something like this recently with my internal colony prototype for High Frontier.



    This works by just beating the position and rotation into submission with math every frame. That is, I know that the camera is supposed to be a certain distance from the cylinder axis, and its "up" vector is supposed to point at the cylinder axis, so I just force it to the closest position/orientation that satisfies those constraints. Here's the code, in case there's anything useful in it for you:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CylinderCamControl : MonoBehaviour {
    5.  
    6.     public float radius = 147;
    7.     public float turnSpeed = 150;
    8.     public float forwardSpeed = 10;
    9.  
    10.     void Update() {
    11.         float boost = 1f;
    12.         if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) boost = 5f;
    13.  
    14.  
    15.         transform.Rotate(0f, Input.GetAxis("Mouse X") * turnSpeed * Time.deltaTime, 0f);
    16.  
    17.         transform.position += transform.forward * Input.GetAxis("Vertical")
    18.             * forwardSpeed * boost * Time.deltaTime;
    19.  
    20.         Snap();
    21.     }
    22.  
    23.     void OnGUI() {
    24.         if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) {
    25.             Rect r = new Rect(20, Screen.height-40, 100, 20);
    26.             GUI.Label(r, "Super Speed");
    27.         }
    28.     }
    29.  
    30.     void Snap() {
    31.         Vector3 pos = transform.position;
    32.         float ang = Mathf.Atan2(pos.z, pos.x);
    33.         Vector3 lookDir = transform.forward;
    34.         pos.x = Mathf.Cos(ang) * radius;
    35.         pos.z = Mathf.Sin(ang) * radius;
    36.         transform.position = pos;
    37.         Vector3 properUp = new Vector3(-pos.x, 0, -pos.z);
    38.         Vector3 properLook = ProjectVectorOnPlane(properUp, lookDir);
    39.         transform.rotation = Quaternion.LookRotation(properLook, properUp);
    40.     }
    41.  
    42.     //Projects a vector onto a plane. The output is not normalized.
    43.     static Vector3 ProjectVectorOnPlane(Vector3 planeNormal, Vector3 vector) {
    44.         planeNormal.Normalize();
    45.         return vector - (Vector3.Dot(vector, planeNormal) * planeNormal);
    46.     }  
    47. }
    48.  
     
  7. AlexGorcea

    AlexGorcea

    Joined:
    Aug 20, 2013
    Posts:
    22
    Alright, I made a little bit of progress.

    http://labs.marcoff-weyland.com/BLS/BLD.html

    Unfortunately, as you can see, the player only rotates to 90 degrees, -90 respectively, then stops. The forward/backward is broken, because it doesn't take into consideration the raycast.

    Here's the movement code:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4.  
    5. public class PlayerMovement : MonoBehaviour {
    6.  
    7.  
    8.     public float Speed = 0;
    9.     public float MaxSpeed = 1;
    10.     public float rotationSpeed = 10;
    11.     public float Acceleration = 10;
    12.     public float Deceleration = 10;
    13.     public Transform target;
    14.     public float degrees = 10;
    15.     // Use this for initialization
    16.     void Start () {
    17.    
    18.     }
    19.    
    20.     // Update is called once per frame
    21.     void Update () {
    22.  
    23.         if ((Input.GetKey ("w")) && (Speed < MaxSpeed))
    24.             Speed = Speed - Acceleration * Time.deltaTime;
    25.         else if ((Input.GetKey ("a")) && (Speed > -MaxSpeed))
    26.             Speed = Speed + Acceleration * Time.deltaTime;
    27.         else {
    28.             if (Speed > Deceleration * Time.deltaTime)
    29.                 Speed = Speed - Deceleration * Time.deltaTime;
    30.             else if (Speed < -Deceleration * Time.deltaTime)
    31.                 Speed = Speed + Deceleration * Time.deltaTime;
    32.             else
    33.                 Speed = 0;
    34.         }
    35.         transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z + Speed * Time.deltaTime);
    36.  
    37.  
    38.         RaycastHit rcHit;
    39.        
    40.         Vector3 theRay   = transform.TransformDirection(-Vector3.up);
    41.        
    42.         if (Physics.Raycast(transform.position, theRay, out rcHit))
    43.         {
    44.             float groundDis = rcHit.distance;
    45.            
    46.             transform.rotation = Quaternion.FromToRotation(Vector3.up,rcHit.normal);
    47.            
    48.             float movement = Input.GetAxis("Horizontal") * rotationSpeed * Time.deltaTime;
    49.            
    50.             transform.localPosition =
    51.                 new Vector3(transform.localPosition.x + movement, (transform.localPosition.y -  groundDis)+.2f, transform.localPosition.z);          
    52.            
    53.         }
    54.  
    55.     }
    56.  
    57.     }
    58.