360 degree movement inside of cylinder

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).

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.

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.

I might try with Transform.RotateAround() for the player. Mind if I keep the thread for prototyping?

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!

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:

using UnityEngine;
using System.Collections;

public class CylinderCamControl : MonoBehaviour {

    public float radius = 147;
    public float turnSpeed = 150;
    public float forwardSpeed = 10;

    void Update() {
        float boost = 1f;
        if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) boost = 5f;


        transform.Rotate(0f, Input.GetAxis("Mouse X") * turnSpeed * Time.deltaTime, 0f);

        transform.position += transform.forward * Input.GetAxis("Vertical")
            * forwardSpeed * boost * Time.deltaTime;

        Snap();
    }

    void OnGUI() {
        if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) {
            Rect r = new Rect(20, Screen.height-40, 100, 20);
            GUI.Label(r, "Super Speed");
        }
    }

    void Snap() {
        Vector3 pos = transform.position;
        float ang = Mathf.Atan2(pos.z, pos.x);
        Vector3 lookDir = transform.forward;
        pos.x = Mathf.Cos(ang) * radius;
        pos.z = Mathf.Sin(ang) * radius;
        transform.position = pos;
        Vector3 properUp = new Vector3(-pos.x, 0, -pos.z);
        Vector3 properLook = ProjectVectorOnPlane(properUp, lookDir);
        transform.rotation = Quaternion.LookRotation(properLook, properUp);
    }

    //Projects a vector onto a plane. The output is not normalized.
    static Vector3 ProjectVectorOnPlane(Vector3 planeNormal, Vector3 vector) {
        planeNormal.Normalize();
        return vector - (Vector3.Dot(vector, planeNormal) * planeNormal);
    }   
}

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:

using UnityEngine;
using System.Collections;
using System;

public class PlayerMovement : MonoBehaviour {


    public float Speed = 0;
    public float MaxSpeed = 1;
    public float rotationSpeed = 10;
    public float Acceleration = 10;
    public float Deceleration = 10;
    public Transform target;
    public float degrees = 10;
    // Use this for initialization
    void Start () {
   
    }
   
    // Update is called once per frame
    void Update () {

        if ((Input.GetKey ("w")) && (Speed < MaxSpeed))
            Speed = Speed - Acceleration * Time.deltaTime;
        else if ((Input.GetKey ("a")) && (Speed > -MaxSpeed))
            Speed = Speed + Acceleration * Time.deltaTime;
        else {
            if (Speed > Deceleration * Time.deltaTime)
                Speed = Speed - Deceleration * Time.deltaTime;
            else if (Speed < -Deceleration * Time.deltaTime)
                Speed = Speed + Deceleration * Time.deltaTime;
            else
                Speed = 0;
        }
        transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z + Speed * Time.deltaTime);


        RaycastHit rcHit;
       
        Vector3 theRay   = transform.TransformDirection(-Vector3.up);
       
        if (Physics.Raycast(transform.position, theRay, out rcHit))
        {
            float groundDis = rcHit.distance;
           
            transform.rotation = Quaternion.FromToRotation(Vector3.up,rcHit.normal);
           
            float movement = Input.GetAxis("Horizontal") * rotationSpeed * Time.deltaTime;
           
            transform.localPosition =
                new Vector3(transform.localPosition.x + movement, (transform.localPosition.y -  groundDis)+.2f, transform.localPosition.z);           
           
        }

    }

    }