像 F-Zero GX 一样在管道内移动

Move Inside Pipe Like F-Zero GX

我已经在这个项目上工作了一段时间 - 我一直在尝试获得一个简单的立方体,玩家可以使用箭头向左或向右移动能够绕管道旋转,类似于赛车手可以在 F-Zero GX 中围绕管道移动:

https://www.youtube.com/watch?v=RlS1i7aCnvg

现在,我知道我不是第一个尝试实施这些物理学的人,因为我已经阅读了两三个一直在尝试实施类似技术的人的帖子。问题是我试过使用这些不同的方法或它们的变体。其中一个已经非常接近我想要的行为 - 但玩家立方体在立方体从地面到整个管道壁的一半时仍然会意外地在其 X 轴上旋转。这是我正在谈论的关卡构建的视觉效果:

整个想法是,立方体可以 "move" 或 "walk" 围绕整个管道壁,就像您在 F-Zero 视频的管道部分中看到的那样,同时当然还在前进。我有一个圆柱体实际上在你看到的那个里面,它实际上只是一个凸触发器 - 所以它用于确保当立方体在管道模型内时玩家立方体的重力刻度关闭。

我已经快要完成这项工作了,但问题是看到玩家能够一直移动一个完整的圆圈,即。以圆周运动完全回到底部或玩家进入管道时开始的位置。然而,立方体喜欢 "flip" 当它完成墙壁移动的一半多一点时。我在另一个 post 中读到,有人实际上改变了物体的刚体以使 "ship" 保持直立,这与它有什么关系吗?

https://forum.unity.com/threads/f-zero-esque-control-question.157909/

"Essentially I gave my vehicle a hover-skirt."

我应该考虑相应地改变刚体的形状吗?执行此操作的最佳资源是什么?或者我应该改用角色控制器?我仍然依赖刚体设置,但在阅读这些内容后我已经对这种可能性敞开心扉。

这个 Raycast 代码非常接近我想要的,没有骰子:

float distDown = Mathf.Infinity;
            RaycastHit hitDown;
            if (Physics.SphereCast(transform.position, 0.25f, -transform.up, out hitDown, 5))
            {
                distDown = hitDown.distance;
            }
transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitDown.normal), hitDown.normal), Time.deltaTime * 1.0f);

我尝试探索的另一种可能性是创建你自己的引力 - 我什至有一个 class 试图做到这一点,FauxGravity,它附加到玩家与之碰撞的对象(在这个以圆柱为例):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FauxGravity : MonoBehaviour {

    public Transform attractor;
    public Transform player;
    public Transform collider;
    Rigidbody attractRB;
    Rigidbody playerRB;
    Vector3 myNormal;
    public Vector3 vectorFromPipeCenter;
    public Vector3 forwardPipeVector;
    Vector3 project2Center;
    public Vector3 pipeGravityPull;
    public int gravity = 1;

    // Use this for initialization
    void Start () {

        //Physics.gravity.magnitude = 0;
    }

    // Update is called once per frame
    void Update () {

    }

    //private void OnCollisionEnter(Collision collision)
    //{
    //    //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    //    //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    //    myNormal = playerRB.transform.up;
    //    //playerRB = collision.gameObject.GetComponent<Rigidbody>();

    //    gravity = 0;
    //    //playerRB.isKinematic = true;
    //    //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    //}

    public void FixedUpdate()
    {
        if (gravity == 0)
        {
            //playerRB.isKinematic = true;
            //Debug.Log("Gravity is 0.");
            attractRB = attractor.GetComponent<Rigidbody>();
            playerRB = player.GetComponent<Rigidbody>();
            //playerRB.AddForce(-10 * playerRB.mass * myNormal);
            Debug.Log("PlayerRB position: " + playerRB.position);
            Debug.Log("AttractRB position: " + attractRB.position);
            vectorFromPipeCenter = playerRB.position - attractRB.position;
            vectorFromPipeCenter.z = 0;
            //vectorFromPipeCenter.Normalize();
            Debug.Log("Player distance from pipe center: " + vectorFromPipeCenter.magnitude);
            Debug.Log("Player vector from pipe center" + vectorFromPipeCenter);
            //vectorFromPipeCenter = attractRB.position - playerRB.position;
            Debug.Log("playerRB forward is " + playerRB.rotation.z);
            Debug.Log("playerRB magnitude is " + player.forward.magnitude);
            forwardPipeVector = player.forward.magnitude * Vector3.forward;
            Debug.Log("Player forward vector? " + forwardPipeVector);
            // or
            //Vector forwardPipeVector = pipeTransform.forward;
            // And finally
            project2Center = Vector3.Project(vectorFromPipeCenter, forwardPipeVector);
            Debug.Log("What is project2Center? " + project2Center);
            float radiusFromCrossectionCenter = vectorFromPipeCenter.magnitude;
            double playerY = System.Convert.ToDouble(playerRB.position.y);
            double playerX = System.Convert.ToDouble(playerRB.position.x);
            //float inverseTan = System.Convert.ToSingle(System.Math.Atan(playerY / playerX));
            //Debug.Log("Normal is: " + Quaternion.AngleAxis(inverseTan, forwardPipeVector));
            // pipe pull force = distance from pipe center to power 2
            //pipeGravityPull = Quaternion.AngleAxis(inverseTan, playerRB.transform.forward) * project2Center * Mathf.Pow ( (radiusFromCrossectionCenter * 1 ), 2 );
            pipeGravityPull = new Vector3(playerRB.position.x, radiusFromCrossectionCenter - playerRB.position.y, 0)/Mathf.Sqrt(Mathf.Pow(playerRB.position.x,2) + Mathf.Pow((radiusFromCrossectionCenter-playerRB.position.y),2));
            Debug.Log("Pipe gravity vector? " + pipeGravityPull);
            //playerRB.useGravity = true;
            Debug.DrawLine(pipeGravityPull, pipeGravityPull);
            Debug.Log("Adding force from FG");
            //playerRB.AddForce(pipeGravityPull);
        }
        if (gravity == 1)
        {
            player.GetComponent<Rigidbody>().useGravity = true;
            //playerRB.isKinematic = false;
        }
    }

    private void OnCollisionExit(Collision collision)
    {
        //Debug.Log("Gravity is 1 again.");
        //player.gameObject.GetComponent<Rigidbody>().useGravity = true;
        //gravity = 1;
        //playerRB.useGravity = true;
        playerRB.isKinematic = false;
        //playerRB.AddForce(10, 20, 0);
    }

    void gravityAttract(Collider colliderObject)
    {
        var rb = colliderObject.GetComponent<Rigidbody>();
        rb.AddForce(Vector3.down * 30, ForceMode.Force);
        rb.AddForce(Vector3.up * 30, ForceMode.Force);
    }
}

我是否需要将 FixedUpdate 逻辑移至 Update 方法?我在这种方法中探索的最后一个算法本质上是确保拉力始终等于 1,根据我父亲的说法(他是一个天体物理学家)。

这是我的玩家的动作 class,它有几次尝试旋转立方体的评论和未评论的尝试,以便让立方体的下侧在它攀爬时始终面对管壁:

using System;
using UnityEngine;

public class PlayerMovement : MonoBehaviour {

    public Rigidbody rb;

    public float forwardForce = 2000f;
    public float sidewaysForce = 500f;
    public Boolean fauxGravity = false;
    public Vector3 distanceFromPipeCenter = new Vector3(0, 0, 0);
    public Vector3 pipePull = new Vector3(0,0,0);

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame use fixed update for Unity Fizzix
    void FixedUpdate () {
        //distanceFromPipeCenter.Normalize();
        //add forward force
        rb.AddForce(0, 0, forwardForce * Time.deltaTime);

        if (Input.GetKey(KeyCode.RightArrow)/* && !fauxGravity*/)
        {
            rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
        }

        if (Input.GetKey(KeyCode.LeftArrow)/* && !fauxGravity*/)
        {
            rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
        }
        if (pipePull.x == 0)
        {
            pipePull.x = 1;
        }
        if (pipePull.y == 0)
        {
            pipePull.y = 1;
        }
        //transform.rotation = Quaternion.identity;
        //pipePull.z = 0;
        if (Input.GetKey(KeyCode.RightArrow) && fauxGravity)
        {
            Debug.Log("Right pressed");
            //Debug.Log("Rotation before: " + rb.rotation);
            //rb.rotation = rb.rotation * Quaternion.FromToRotation(rb.transform.up, pipePull);
            //rb.rotation = Quaternion.Lerp(rb.rotation, Quaternion.LookRotation(Vector3.Cross(rb.transform.right, pipePull), pipePull), Time.deltaTime * 5.0f);
            //Debug.Log("Rotation after: " + rb.rotation);
            //if (distanceFromPipeCenter.y < 0)
            //{
            //    Debug.Log("Right A, pull positive: " +pipePull);
                //rb.AddForce(sidewaysForce * pipePull.x * Time.deltaTime, sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
            //}
            //else
            //{
            //    Debug.Log("Right B, pull negative: " + distanceFromPipeCenter);
            //    rb.AddForce(sidewaysForce * pipePull.x * Time.deltaTime, -sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
            //}
            //Debug.Log(rb.angularVelocity);
            //float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
            //Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
            //align with surface normal
            //transform.rotation = Quaternion.FromToRotation(transform.up, distanceFromPipeCenter) * transform.rotation;
            //apply heading rotation
            //transform.rotation = headingDelta * transform.rotation;
        }
        if (Input.GetKey(KeyCode.LeftArrow) && fauxGravity)
        {
            Debug.Log("Left pressed");
            //Debug.Log("Rotation before: " + rb.rotation);
            //rb.rotation = rb.rotation * Quaternion.FromToRotation(rb.transform.up, pipePull);
            //rb.rotation = Quaternion.Lerp(rb.rotation, Quaternion.LookRotation(Vector3.Cross(rb.transform.right, pipePull), pipePull), Time.deltaTime * 5.0f);
            //Debug.Log("Rotation after: " + rb.rotation);
            //if (distanceFromPipeCenter.y < 0)
            //{
            //    Debug.Log("Left A, pull positive: " +pipePull);
                //rb.AddForce(-sidewaysForce * pipePull.x * Time.deltaTime, sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
            //}
            //else
            //{
            //    Debug.Log("Left B, pull negative: " + distanceFromPipeCenter);
            //    rb.AddForce(-sidewaysForce * pipePull.x * Time.deltaTime, -sidewaysForce * pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
            //}
            //Debug.Log(rb.angularVelocity);
            //float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
            //Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
            //align with surface normal
            //transform.rotation = Quaternion.FromToRotation(transform.up, distanceFromPipeCenter) * transform.rotation;
            //apply heading rotation
            //transform.rotation = headingDelta * transform.rotation;
        }
        if (fauxGravity)
        {
            rb.useGravity = false;

            ///*We get the user input and modifiy the direction the ship will face towards*/
            //float yaw = Time.deltaTime * Input.GetAxis("Horizontal");
            ///*We want to save our current transform.up vector so we can smoothly change it later*/
            //Vector3 prev_up = rb.transform.up;
            ///*Now we set all angles to zero except for the Y which corresponds to the Yaw*/
            //transform.rotation = Quaternion.Euler(0, yaw, 0);

            //RaycastHit hit;
            //if (Physics.Raycast(transform.position, -prev_up, out hit))
            //{
            //    Debug.DrawLine(transform.position, hit.point);

            //    /*Here are the meat and potatoes: first we calculate the new up vector for the ship using lerp so that it is smoothed*/
            //    Vector3 desired_up = Vector3.Lerp(prev_up, hit.normal, Time.deltaTime /** pitch_smooth*/);
            //    /*Then we get the angle that we have to rotate in quaternion format*/
            //    Quaternion tilt = Quaternion.FromToRotation(transform.up, desired_up);
            //    /*Now we apply it to the ship with the quaternion product property*/
            //    transform.rotation = tilt * transform.rotation;

            //    /*Smoothly adjust our height*/
            //    //smooth_y = Mathf.Lerp(smooth_y, hover_height - hit.distance, Time.deltaTime * height_smooth);
            //    //transform.localPosition += prev_up * smooth_y;
            //}
            //float distForward = Mathf.Infinity;
            //RaycastHit hitForward;

            //if (Physics.SphereCast(transform.position, 0.25f, -transform.up + transform.forward, out hitForward, 5))
            //{
            //    distForward = hitForward.distance;
            //}
            float distDown = Mathf.Infinity;
            RaycastHit hitDown;
            if (Physics.SphereCast(transform.position, 0.25f, -transform.up, out hitDown, 5))
            {
                distDown = hitDown.distance;
            }
            //float distBack = Mathf.Infinity;
            //RaycastHit hitBack;
            //if (Physics.SphereCast(transform.position, 0.25f, -transform.up + -transform.forward, out hitBack, 5))
            //{
            //    distBack = hitBack.distance;
            //}

            //if (distForward < distDown && distForward < distBack)
            //{
            //    transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitForward.normal), hitForward.normal), Time.deltaTime * 5.0f);
            //}
            //else if (distDown < distForward && distDown < distBack)
            //{
            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitDown.normal), hitDown.normal), Time.deltaTime * 1.0f);
            //}
            //else if (distBack < distForward && distBack < distDown)
            //{
            //    transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitBack.normal), hitBack.normal), Time.deltaTime * 5.0f);
            //}

            //GetComponent<Rigidbody>().AddForce(-transform.up * Time.deltaTime * 10);
        }
        if (rb.position.y <-1f)
        {
            FindObjectOfType<GameManagement>().EndGame();
        }
    }

    //void OnCollisionEnter(Collision collision)
    //{
    //    //collision.gameObject.GetComponent<Rigidbody>().transform.up = Vector3.zero;
    //    //player.gameObject.GetComponent<Rigidbody>().useGravity = false;
    //    System.Console.WriteLine("Player has collided with: " + collision.collider.name);
    //    if(collision.gameObject.name == "PipeBasic 1")
    //    {
    //        System.Console.WriteLine("Player Collided with Pipe");
    //        fauxGravity = true;
    //    }
    //    //playerRB.isKinematic = true;
    //    //player.gameObject.GetComponent<Rigidbody>().AddRelativeForce()
    //}
}

任何人都可以提供一些额外的提示、提示和技巧吗?我认为使用 Raycast,甚至是它的 SphereCast,可能是最接近我想要的方法,但我只是坚持如何在不冒旋转玩家立方体的风险的情况下准确地实现它错误的一面并搞砸了物理相互作用。是不是我想太多了?

在此先感谢大家。

更新:

我一直在改变玩家 Y 速度的逻辑,因为在圆圈中移动必须涉及特定的物理,如下页给出的方程式:

https://www.physicsclassroom.com/class/circles/Lesson-1/Speed-and-Velocity

但是,我仍在努力寻找一个好的时间值来划分等式的顶部。到目前为止,这是我向右移动时的移动代码:

if (distanceFromPipeCenter.y < 0)
            {
                //Debug.Log("Right A, pull positive: " + pipePull);
                //Debug.Log("X Pull: " + pipePull.x);
                rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, (sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
            }
            else if(distanceFromPipeCenter.x>=3)
            {
                //Debug.Log("Right B, pull negative: " + distanceFromPipeCenter);

                rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, (sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
            }
            else if(distanceFromPipeCenter.x>0)
            {

                rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, (sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
            }
            else if(distanceFromPipeCenter.y>0)
            {
                Debug.Log("X distance: " + distanceFromPipeCenter.x);
                Debug.Log("Radius: " + radiusInPipe);
                Debug.Log("Frame count? " + Time.fixedDeltaTime);
                Vector3 pull = new Vector3(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((-sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.fixedDeltaTime) * Time.deltaTime, 0);
                Debug.Log("About to apply: " + pull );
                rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, (-sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
            }
            else
            {
                rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, (-sidewaysForce * 2 * radiusInPipe * (float)Math.PI) / Time.deltaTime, 0, ForceMode.VelocityChange);
            }

似乎除以 Time.deltaTime 只会让玩家跳出很远的距离——这不是我想要的。我还尝试使用自游戏开始以来的时间量作为分隔符,然后将整个结果乘以 Time.deltaTime - 但正如您可能推断的那样,帧只是增加然后最终减慢速度这样。

还有什么想法或建议吗?

1.禁用重力

当玩家进入管道时有一个触发器怎么样,你禁用他们的刚体使用重力。我尝试了这个并且它似乎有效,虽然我的立方体在接近顶部时会翻转,因为它没有粘在地板上。

2。仅在循环管道时才在播放器下方对撞机

对此的一个潜在解决方法是在玩家下方(作为玩家的 child)生成一个对撞机,它也在管道之外 - 因此玩家永远不会飘离管道。 注意:我没有自己测试,因为我的测试圆柱体只有很多四边形。

  • 绿色圆圈是阻止玩家从管道两侧漂浮的对撞机。

  • green square是激活绿色圆圈对撞机的触发器,ontriggerenter激活它,ontriggerexit停用它。

所以,事实证明我忽略了整个,或者更确切地说,忽略了这个游戏引擎中的一个关键和惊人的功能。

我试图计算所有这些运动,因为我认为我们必须计算游戏世界起源的力和运动。那段时间,我一直在对自己说各种咆哮,心想,"Man, it'd be so much easier if you could just add a force/torque in the object's local coordinates..."

输入 AddRelativeForce() 而不是 AddForce()。

有了这个,并使用从我正在穿过的隧道传入的半径,在重力关闭的情况下,我能够更轻松地获得所需的效果。

这段代码此时可能有点臃肿,但关键是我使用的 nextLeft 和 nextRight Vector3 对象。我希望这对以后的人有所帮助。如果我可以澄清任何事情或以任何其他方式使这个 post 更好,请告诉我。

void FixedUpdate () {
        //distanceFromPipeCenter.Normalize();
        //add forward force
        rb.AddForce(0, 0, forwardForce * Time.deltaTime);

        if (Input.GetKey(KeyCode.RightArrow) && !fauxGravity)
        {
            rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
        }

        if (Input.GetKey(KeyCode.LeftArrow) && !fauxGravity)
        {
            rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
        }
        if(radiusInPipe == 0)
        {
            radiusInPipe = 1;
        }
        //transform.rotation = Quaternion.identity;
        //pipePull.z = 0;
        Vector3 nextRight = new Vector3(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0);
        Vector3 nextLeft = new Vector3(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0);
        if (Input.GetKey(KeyCode.RightArrow) && fauxGravity)
        {
            //Debug.Log("Right pressed");
            //Debug.Log("Rotation before: " + rb.rotation);
            //rb.rotation = rb.rotation * Quaternion.FromToRotation(rb.transform.up, pipePull);
            //rb.rotation = Quaternion.Lerp(rb.rotation, Quaternion.LookRotation(Vector3.Cross(rb.transform.right, pipePull), pipePull), Time.deltaTime * 5.0f);
            //Debug.Log("Rotation after: " + rb.rotation);
            //Vector3 next = new Vector3(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0);
            if (distanceFromPipeCenter.y < 0)
            {
                //Debug.Log("Right A, pull positive: " + pipePull);
                //Debug.Log("X Pull: " + pipePull.x);
                Debug.Log("Current deltaTime: " + Time.deltaTime);
                //Vector3 next = new Vector3(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI)/(sidewaysForce))  * Time.fixedDeltaTime, 0);
                Debug.Log("About to apply: " + nextRight);
                rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
            }
            else if(distanceFromPipeCenter.x>=3)
            {
                //Debug.Log("Right B, pull negative: " + distanceFromPipeCenter);

                //rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) * (sidewaysForce)) * Time.deltaTime, 0, ForceMode.VelocityChange);
                rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
            }
            else if(distanceFromPipeCenter.x>0)
            {
                rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
                //rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) * (sidewaysForce)) * Time.deltaTime, 0, ForceMode.VelocityChange);
            }
            else if(distanceFromPipeCenter.y>0)
            {
                Debug.Log("X distance: " + distanceFromPipeCenter.x);
                Debug.Log("Radius: " + radiusInPipe);
                Debug.Log("Frame count? " + Time.fixedDeltaTime);
                Vector3 pull = new Vector3(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, -((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0);
                Debug.Log("About to apply: " + pull );

                //rb.AddForce(-sidewaysForce /** pipePull.x*/ * Time.deltaTime, -((2 * radiusInPipe * (float)Math.PI) * sidewaysForce) * Time.deltaTime, 0, ForceMode.VelocityChange);
                rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
            }
            else
            {
                rb.AddRelativeForce(nextRight, ForceMode.VelocityChange);
                //rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, ((2 * radiusInPipe * (float)Math.PI) / (sidewaysForce)) * Time.fixedDeltaTime, 0, ForceMode.VelocityChange);
            }
            //Debug.Log(rb.angularVelocity);
            float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
            Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, -transform.up);
            headingDelta.y = 0;
            headingDelta.x = 0;
            //align with surface normal
            transform.rotation = Quaternion.FromToRotation(-transform.up, distanceFromPipeCenter) * transform.rotation;
            //apply heading rotation
            transform.rotation = headingDelta * transform.rotation;
        }
        if (Input.GetKey(KeyCode.LeftArrow) && fauxGravity)
        {
            //Debug.Log("Left pressed");
            //Debug.Log("Rotation before: " + rb.rotation);
            //rb.rotation = rb.rotation * Quaternion.FromToRotation(rb.transform.up, pipePull);
            //rb.rotation = Quaternion.Lerp(rb.rotation, Quaternion.LookRotation(Vector3.Cross(rb.transform.right, pipePull), pipePull), Time.deltaTime * 5.0f);
            //Debug.Log("Rotation after: " + rb.rotation);
            //if (distanceFromPipeCenter.y < 0)
            //{
            //    //Debug.Log("Left A, pull positive: " + pipePull);
            //    rb.AddForce(-sidewaysForce/* * pipePull.x*/ * Time.deltaTime, sidewaysForce /pipePull.y * Time.deltaTime, Math.Abs(pipePull.z) * Time.deltaTime, ForceMode.VelocityChange);
            //}
            //else if(distanceFromPipeCenter.x >=0)
            //{
            //    //Debug.Log("Left B, pull negative: " + distanceFromPipeCenter);
            //    rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, sidewaysForce * -pipePull.y * Time.deltaTime, Math.Abs(pipePull.z) * Time.deltaTime, ForceMode.VelocityChange);
            //}
            //else
            //{
            //    //rb.AddForce(sidewaysForce /** pipePull.x*/ * Time.deltaTime, sidewaysForce * -pipePull.y * Time.deltaTime, 0, ForceMode.VelocityChange);
            //    Debug.Log("Deadzone. PAUSE. Pull: " + pipePull);
            //}
            rb.AddRelativeForce(nextLeft, ForceMode.VelocityChange);
            //Debug.Log(rb.angularVelocity);
            float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * sidewaysForce;
            Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, -transform.up);
            headingDelta.y = 0;
            headingDelta.x = 0;
            //align with surface normal
            transform.rotation = Quaternion.FromToRotation(-transform.up, distanceFromPipeCenter) * transform.rotation;
            //apply heading rotation
            transform.rotation = headingDelta * transform.rotation;

        }
        if (fauxGravity)
        {
            rb.useGravity = false;
            if(rb.position.y-ground.position.y > 2)
            {
                roller.isTrigger = false;
            }
            else
            {
                roller.isTrigger = true;
            }
            //rb.AddForce(pipePull);
            //roller.isTrigger = false;
            ///*We get the user input and modifiy the direction the ship will face towards*/
            //float yaw = Time.deltaTime * Input.GetAxis("Horizontal");
            ///*We want to save our current transform.up vector so we can smoothly change it later*/
            //Vector3 prev_up = rb.transform.up;
            ///*Now we set all angles to zero except for the Y which corresponds to the Yaw*/
            //transform.rotation = Quaternion.Euler(0, yaw, 0);

            //RaycastHit hit;
            //if (Physics.Raycast(transform.position, -prev_up, out hit))
            //{
            //    Debug.DrawLine(transform.position, hit.point);

            //    /*Here are the meat and potatoes: first we calculate the new up vector for the ship using lerp so that it is smoothed*/
            //    Vector3 desired_up = Vector3.Lerp(prev_up, hit.normal, Time.deltaTime /** pitch_smooth*/);
            //    /*Then we get the angle that we have to rotate in quaternion format*/
            //    Quaternion tilt = Quaternion.FromToRotation(transform.up, desired_up);
            //    /*Now we apply it to the ship with the quaternion product property*/
            //    transform.rotation = tilt * transform.rotation;

            //    /*Smoothly adjust our height*/
            //    //smooth_y = Mathf.Lerp(smooth_y, hover_height - hit.distance, Time.deltaTime * height_smooth);
            //    //transform.localPosition += prev_up * smooth_y;
            //}
            //float distForward = Mathf.Infinity;
            //RaycastHit hitForward;

            //if (Physics.SphereCast(transform.position, 0.25f, -transform.up + transform.forward, out hitForward, 5))
            //{
            //    distForward = hitForward.distance;
            //}
            float distDown = Mathf.Infinity;
            RaycastHit hitDown;
            if (Physics.SphereCast(transform.position, 0.25f, -transform.up, out hitDown, 5))
            {
                distDown = hitDown.distance;
            }
            //float distBack = Mathf.Infinity;
            //RaycastHit hitBack;
            //if (Physics.SphereCast(transform.position, 0.25f, -transform.up + -transform.forward, out hitBack, 5))
            //{
            //    distBack = hitBack.distance;
            //}

            //if (distForward < distDown && distForward < distBack)
            //{
            //    transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitForward.normal), hitForward.normal), Time.deltaTime * 5.0f);
            //}
            //else if (distDown < distForward && distDown < distBack)
            //{
            //transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitDown.normal), hitDown.normal), Time.deltaTime * 1.0f);
            //}
            //else if (distBack < distForward && distBack < distDown)
            //{
            //    transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.Cross(transform.right, hitBack.normal), hitBack.normal), Time.deltaTime * 5.0f);
            //}

            //GetComponent<Rigidbody>().AddForce(-transform.up * Time.deltaTime * 10);
            transformDifference = rb.position;
            previousFrame = Time.frameCount;
        }
        if (rb.position.y <-1f)
        {
            FindObjectOfType<GameManagement>().EndGame();
        }
    }