根据按键旋转GameObject并基于地形坡度/曲率

时间:2017-08-19 23:20:01

标签: c# unity3d rotation game-physics

我在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;

     }
 }

1 个答案:

答案 0 :(得分:2)

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

对于对象的位置,您可以使用this帖子中描述的Terrain.activeTerrain.SampleHeight来计算,或者您可以像使用问题中的代码一样使用RaycastHit.point。< / p>

下面是我上面描述的一个例子。它是一个 minimal 代码,用于在地形上移动/旋转对象。您可以修改它以适合您的四个角色腿场景。

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);
    }
}