zoukankan      html  css  js  c++  java
  • Unity3D第三人称摄像机

    作为算法竞赛的蒟蒻在打了若干次铁后,和队友一起退役了.JPG

    Unity3D设置一个第三人称摄像机,为了画面的有趣性,先选择下载一个带基本动作的角色包,笔者选择了免费的Warrior Pack Bundle 3 FREE.

    将某个角色的prefab拖动到scene设置animator controller为其对应的动作。

    尝试运行。

     角色只能在原地打转,因为这里并没有控制角色的位移的脚本,moving时仅仅设置了动画的播放。

    控制角色转动的函数如下。

        void GetCameraRelativeMovement()
        {  
            Transform cameraTransform = Camera.main.transform;
    
            // Forward vector relative to the camera along the x-z plane   
            Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);
            forward.y = 0;
            forward = forward.normalized;
            //print(forward.x+' '+forward.y+' '+forward.z);
            // Right vector relative to the camera
            // Always orthogonal to the forward vector
            Vector3 right= new Vector3(forward.z, 0, -forward.x);
    
            //directional inputs
            float v = Input.GetAxisRaw("Vertical");
            float h = Input.GetAxisRaw("Horizontal");
    
            // Target direction relative to the camera
            targetDirection = h * right + v * forward;
    
        }
    
        //face character along input direction
        void RotateTowardMovementDirection()  
        {
            if(inputVec != Vector3.zero)
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(targetDirection), Time.deltaTime * rotationSpeed);
            }
        }
    
    
    
        void UpdateMovement()
        {
            //get movement input from controls
            Vector3 motion = inputVec;
    
            //reduce input for diagonal movement
            motion *= (Mathf.Abs(inputVec.x) == 1 && Mathf.Abs(inputVec.z) == 1) ? 0.7f:1;
            RotateTowardMovementDirection();
            GetCameraRelativeMovement();
            ///CameraRotate();
            ///MoveTowardsFace();
            ///CameraMove();
        }

    这些是下载角色自带的函数,控制角色根据和主摄像机的位置来决定转向。

    以只狼的移动模式为目标。按下向右移动时,角色完成转向并向前走,摄像机始终和只狼保持距离,并且将狼放在中央。

    为了模拟这个过程,首先加入按下方向键时向角色正面的方向进行移动。

        void MoveTowardsFace()
        {
            if (inputVec.x != 0 || inputVec.z != 0)
            {
                transform.Translate(Time.deltaTime * moveSpeed * transform.forward, Space.World);
            }
        }

    控制角色在摄像机中央,此时摄像机只用完成看着角色旋转。

    void CameraRotate()
        {
            cameraTargetDirection = transform.position - Camera.main.transform.position;
            cameraTargetDirection.y = 0;
            Camera.main.transform.rotation = Quaternion.Slerp(Camera.main.transform.rotation, Quaternion.LookRotation(cameraTargetDirection)
                , Time.deltaTime * rotationSpeed
                );
        }

    Quaternion是四元组用来描述一个方向向量,其值分别为w,x,y,z,w为以标量,x,y,z分别为在方向上的投影,具体换算我拒绝书写......打算把这一使用暂时当黑盒运算。

    接着是摄像机的移动,在前两部完成摄像机看着角色后,摄像机会准确地将角色控制在中间,应该说Unity神奇呢,还是该说微积分神奇呢。摄像机现在只需要使用负反馈调节来控制和人物间的距离。

        float GetDistance(Vector3 a, Vector3 b)
        {
            return Mathf.Sqrt(Mathf.Pow(a.x - b.x, 2) + Mathf.Pow(a.z - b.z, 2));
        }
        void CameraMove()
        {
            //if (inputVec.x != 0 || inputVec.z != 0)
            //{
            //print(Camera.main.transform.position);
            //print(transform.position);
            //print(GetDistance(Camera.main.transform.position, transform.position));
            Camera.main.transform.Translate(Camera.main.transform.forward * Time.deltaTime * 10 *
            (GetDistance(Camera.main.transform.position, transform.position) - distanceToCharacter)
            , Space.World);
            //  }
        }

    值得注意的是,我们从小接触的平面直角坐标系甚至大学的教材是苏联人的那一套,x,y作为平面的两个轴,在Unity中的坐标系默认是西方的那一套也就是x,z作为平面的两个轴,这点害我出了很多问题还不知道在哪。

     

     这里不放动图视频进行展示了,除了纵轴y,平面上摄像机已经完全控制在范围中了。

    这里考虑一个问题,负反馈调节时采用指数函数会不会效果更好?

    整个脚本

    using UnityEngine;
    using System.Collections;
    
    public class WarriorAnimationDemoFREE : MonoBehaviour 
    {
        public Animator animator;
        float rotationSpeed = 30;
        float moveSpeed = 10;
        float distanceToCharacter = 10;
        Vector3 inputVec;
        Vector3 targetDirection;
        Vector3 cameraTargetDirection;
    
        //Warrior types
        public enum Warrior{Karate, Ninja, Brute, Sorceress, Knight, Mage, Archer, TwoHanded, Swordsman, Spearman, Hammer, Crossbow};
        public Warrior warrior;
        private void Start()
        {
           // animator = this.GetComponent<Animator>();
            
        }
        void Update()
        {
            //Get input from controls
            float z = Input.GetAxisRaw("Horizontal");
            float x = -(Input.GetAxisRaw("Vertical"));
            inputVec = new Vector3(x, 0, z);
    
            //Apply inputs to animator
            animator.SetFloat("Input X", z);
            animator.SetFloat("Input Z", -(x));
    
            if (x != 0 || z != 0 )  //if there is some input
            {
                print("hehe");
                //set that character is moving
                animator.SetBool("Moving", true);
            }
            else
            {
                //character is not moving
                animator.SetBool("Moving", false);
            }
    
            if (Input.GetButtonDown("Fire1"))
            {
                animator.SetTrigger("Attack1Trigger");
                if (warrior == Warrior.Brute)
                    StartCoroutine (COStunPause(1.2f));
                else if (warrior == Warrior.Sorceress)
                    StartCoroutine (COStunPause(1.2f));
                else
                    StartCoroutine (COStunPause(.6f));
            }
    
            //update character position and facing
            UpdateMovement();
        }
        
        public IEnumerator COStunPause(float pauseTime)
        {
            yield return new WaitForSeconds(pauseTime);
        }
        void CameraRotate()
        {
            cameraTargetDirection = transform.position - Camera.main.transform.position;
            cameraTargetDirection.y = 0;
            Camera.main.transform.rotation = Quaternion.Slerp(Camera.main.transform.rotation, Quaternion.LookRotation(cameraTargetDirection)
                , Time.deltaTime * rotationSpeed
                );
        }
    
        void MoveTowardsFace()
        {
            if (inputVec.x != 0 || inputVec.z != 0)
            {
                transform.Translate(Time.deltaTime * moveSpeed * transform.forward, Space.World);
            }
        }
        float GetDistance(Vector3 a, Vector3 b)
        {
            return Mathf.Sqrt(Mathf.Pow(a.x - b.x, 2) + Mathf.Pow(a.z - b.z, 2));
        }
        void CameraMove()
        {
            //if (inputVec.x != 0 || inputVec.z != 0)
            //{
            //print(Camera.main.transform.position);
            //print(transform.position);
            //print(GetDistance(Camera.main.transform.position, transform.position));
            Camera.main.transform.Translate(Camera.main.transform.forward * Time.deltaTime * 10 *
            (GetDistance(Camera.main.transform.position, transform.position) - distanceToCharacter)
            , Space.World);
            //  }
        }
        //converts control input vectors into camera facing vectors
        void GetCameraRelativeMovement()
        {  
            Transform cameraTransform = Camera.main.transform;
    
            // Forward vector relative to the camera along the x-z plane   
            Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);
            forward.y = 0;
            forward = forward.normalized;
            //print(forward.x+' '+forward.y+' '+forward.z);
            // Right vector relative to the camera
            // Always orthogonal to the forward vector
            Vector3 right= new Vector3(forward.z, 0, -forward.x);
    
            //directional inputs
            float v = Input.GetAxisRaw("Vertical");
            float h = Input.GetAxisRaw("Horizontal");
    
            // Target direction relative to the camera
            targetDirection = h * right + v * forward;
    
        }
    
        //face character along input direction
        void RotateTowardMovementDirection()  
        {
            if(inputVec != Vector3.zero)
            {
                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(targetDirection), Time.deltaTime * rotationSpeed);
            }
        }
    
    
    
        void UpdateMovement()
        {
            //get movement input from controls
            Vector3 motion = inputVec;
    
            //reduce input for diagonal movement
            motion *= (Mathf.Abs(inputVec.x) == 1 && Mathf.Abs(inputVec.z) == 1) ? 0.7f:1;
            RotateTowardMovementDirection();
            GetCameraRelativeMovement();
            CameraRotate();
            MoveTowardsFace();
            CameraMove();
        }
    
        //Placeholder functions for Animation events
        void Hit()
        {
        }
    
        void FootR()
        {
        }
    
        void FootL()
        {
        }
    
        void OnGUI () 
        {
            if (GUI.Button (new Rect (25, 85, 100, 30), "Attack1")) 
            {
                animator.SetTrigger("Attack1Trigger");
                //if character is Brute or Sorceress
                switch (warrior)
                {
                    case Warrior.Brute:
                    case Warrior.Sorceress:
                        StartCoroutine(COStunPause(1.2f));
                        break;
                    default:
                        StartCoroutine(COStunPause(.6f));
                        break;
                }
                
                
            }
        }
    }
  • 相关阅读:
    MongoDB面试题
    spider 爬虫文件基本参数(3)
    命令行工具(2)
    初始scrapy,简单项目创建和CSS选择器,xpath选择器(1)
    数据分析实例(离海洋距离与最高温度之间的关系分析)
    路飞业务分析
    MYSQL 主从复制,读写分离(8)
    pyquery 学习
    selenium case报错重新执行
    python小技巧
  • 原文地址:https://www.cnblogs.com/DevilInChina/p/11846551.html
Copyright © 2011-2022 走看看