【问题标题】:Rotate GameObject based on key presses and based on Terrain slope/curvature根据按键和地形坡度/曲率旋转游戏对象
【发布时间】:2017-08-19 23:20:00
【问题描述】:

我在 Unity 的游戏中使用 C# 编写代码,需要根据地形的坡度旋转玩家,但 RotateTowards 函数(计算坡度和角度)不允许将对象侧向旋转以移动它在不同的方向。如果我取出 rotateTowards 函数,横向旋转会起作用。如果我不这样做,正确的坡度旋转会起作用,但按下按钮时播放器不会侧向旋转。

我该如何解决这个问题,以便播放器可以双向旋转?

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

 public class PlayerController1 : MonoBehaviour
 {
     [System.Serializable]
     public class MoveSettings
     {
         public float forwardVel = 10f;      // walk speed

         public float rotateVel = 100;       // character rotation speed, character can walk 360 degree

         public float jumpVel = 25f;
         public LayerMask ground;

         public Transform backLeft;   // back left feet
         public Transform backRight;  // back right feet
         public Transform frontLeft;  // front left feet 
         public Transform frontRight; // front left feet
     }

     [System.Serializable]
     public class PhysicsSettings
     {
         public float downAccel = 0.75f;     // down speed when not grounded
     }

     public GameObject Model;
      public GameObject Origin;
     public MoveSettings moveSettings = new MoveSettings();
     public PhysicsSettings physicsSettings = new PhysicsSettings();

     private Vector3 velocity = Vector3.zero;
     private Quaternion targetRotation;
     private CharacterController cc;

     private float forwardInput, turnInput, jumpInput = 0;

     private RaycastHit lr;
     private RaycastHit rr;
     private RaycastHit lf;
     private RaycastHit rf;
     private Vector3 upDir;

     private Animator Anim; // global private variable



     private void Start()

     {   
         Anim = GetComponent<Animator>(); // in the Start function
         targetRotation = transform.rotation;
         cc = GetComponent<CharacterController>();
     }


     public bool Grounded()
     {
         return cc.isGrounded;
     }



     private void FixedUpdate()
     {

         Run();  // calculate the velocity to be applied on character controller, stored in the velocity variable
         Jump(); // code for jumping
          GetInput();     // movement input keys
         Turn();         // character movement direction input

         cc.Move(transform.TransformDirection(velocity) * Time.deltaTime);
         RotateTowardsGround();
     }

     private void GetInput()
     {

 Anim.SetFloat("vSpeed", forwardInput); // in the GetInput() function
 Anim.SetFloat("Direction", 1f);
         forwardInput = Input.GetAxis("Vertical");
         turnInput = Input.GetAxis("Horizontal");
         jumpInput = Input.GetAxisRaw("Jump");
     }

     private void Turn()
     {
         targetRotation *= Quaternion.AngleAxis(moveSettings.rotateVel * turnInput * Time.deltaTime, Vector3.up);
         transform.rotation = targetRotation;



     }

     public void Jump()
     {
         if (jumpInput > 0 && Grounded())
         {
             velocity.y = moveSettings.jumpVel;
         }
         else if (jumpInput == 0 && Grounded())
         {
             velocity.y = 0;
         }
         else
         {
             velocity.y -= physicsSettings.downAccel;
         }
     }

     private void Run()
     {

         velocity.z = moveSettings.forwardVel * forwardInput;
     }

         public void RotateTowardsGround()
     {

         // we have four feet

         Physics.Raycast(moveSettings.backLeft.position + Vector3.up, Vector3.down, out lr);
         Physics.Raycast(moveSettings.backRight.position + Vector3.up, Vector3.down, out rr);
         Physics.Raycast(moveSettings.frontLeft.position + Vector3.up, Vector3.down, out lf);
         Physics.Raycast(moveSettings.frontRight.position + Vector3.up, Vector3.down, out rf);
         upDir = (Vector3.Cross(rr.point - Vector3.up, lr.point - Vector3.up) +
                  Vector3.Cross(lr.point - Vector3.up, lf.point - Vector3.up) +
                  Vector3.Cross(lf.point - Vector3.up, rf.point - Vector3.up) +
                  Vector3.Cross(rf.point - Vector3.up, rr.point - Vector3.up)
                 ).normalized;
         Debug.DrawRay(rr.point, Vector3.up);
         Debug.DrawRay(lr.point, Vector3.up);
         Debug.DrawRay(lf.point, Vector3.up);
         Debug.DrawRay(rf.point, Vector3.up);



         Model.transform.up = upDir;

     }
 }

【问题讨论】:

    标签: c# unity3d rotation game-physics


    【解决方案1】:

    根据地形坡度/曲率旋转对象的正确方法是首先抛出光线投射,然后获取返回的RaycastHit.normal 值并将其分配给对象的transform.up。最好使用LerpSlerp 来完成这种形式的平滑配给。

    至于对象的位置,您可以使用Terrain.activeTerrain.SampleHeight 计算,如this 帖子中所述,或者您可以使用RaycastHit.point,就像您在问题代码中所做的那样。

    下面是我上面描述的一个例子。这是在地形上移动/旋转对象的最小代码。您可以修改它以适合您的四人腿场景。

    public class Hover : MonoBehaviour
    {
        public Transform objectToMove;
        public float maxSpeed = 10f;
        public float angleSpeed = 5f;
        public float groundDistOffset = 2f;
        private Vector3 toUpPos = Vector3.zero;
    
        void Update()
        {
            float hInput = Input.GetAxis("Horizontal");
            float vInput = Input.GetAxis("Vertical");
    
            Vector3 objPos = objectToMove.position;
            objPos += objectToMove.forward * vInput * maxSpeed * Time.deltaTime;
            objPos += objectToMove.right * hInput * maxSpeed * Time.deltaTime;
    
            RaycastHit hit;
    
            if (Physics.Raycast(objectToMove.position, -Vector3.up, out hit))
            {
                //Get y position
                objPos.y = (hit.point + Vector3.up * groundDistOffset).y;
    
                //Get rotation
                toUpPos = hit.normal;
            }
    
            //Assign position of the Object
            objectToMove.position = objPos;
    
            //Assign rotation/axis of the Object
            objectToMove.up = Vector3.Slerp(objectToMove.up, toUpPos, angleSpeed * Time.deltaTime);
        }
    }
    

    【讨论】:

    • 这是对代码的一个很大的改变,但它仍然不允许我根据键输入横向旋转播放器,因为它总是随着地形旋转。这只是让我可以在各个方向移动它,但不能旋转
    • 这是很久以前我做的,我仍然希望它能够工作。当我有时间时,我将创建一个地形并再次对其进行测试以确保其正常运行。你能创建一个简单的 3D 胶囊和这段代码来控制它在地形上。看看它是否旋转。不要对其进行任何更改。
    • 是的,我已经尝试过了,玩家可以向各个方向移动并根据地形旋转,但是当按下左键时不要向左移动,我需要它向左旋转,斜坡旋转不允许
    • 我认为我不明白这个问题。你能放一个动画 gif 或视频来显示所描述的问题吗?那会很有帮助。
    • 不在我的电脑上测试,看看是什么原因导致口吃。当我在我的电脑上时,我会回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多