[测试发布]unity第三⼈称⾓⾊移动控制⼀个标准的第三⼈称⾓⾊移动控制按下W⾯向前移动; 按下S⾯向后移动; 按下A⾯向左移动; 按下D⾯向右移动按下LeftShift加速移动Player静⽌时摄像头⾃由旋转观察⾓⾊移动时⾓⾊rotation跟随⿏标 , 也就是⿏标能控制⾓⾊移动⽅向层级⾯板⽬录结构Player(PlayerControl挂载在此处) 模型 : 模型在Player的⼦⽬录下 Target : Target是个空物体, ⼤概在⾓⾊头部位置, ⽤于附着相机对象 Camera(CameraControl挂载在此处) : 就是游戏的主摄像机 , 在空物体Target的⼦⽬录下其中Player要有Animator组件, Rigidbody组件, Capsule Collider组件和⾃定义脚本PlayerControl组件Camera要有⾃定义脚本CameraControl组件之所以弄成这么个层级 , 主要是为了分离⾓⾊和摄像机 , 摄像机可以⾃由旋转⽽不影响⾓⾊ , 那个Target⼤概就是为了能让相机正冲⾓⾊后脑勺.怎样实现?理⼀下思路PlayerControl脚本的内容获取WASD输⼊ , 根据输⼊改变整个Player⽗对象的rotation , 并且控制⾓⾊移动.最后要做到⾓⾊平滑转向 , 还要实现0速到移动速度的平滑转向 需要在类中声明的变量 //***变量声明区域***/float walkSpeed = 5;float runSpeed = 10;Animator animator;//创建⼀个animator变量以待赋值(在start()⽅法⾥赋值)public float turnSmoothTime = 0.13f;//设定⾓⾊转向平滑时间float turnSmoothVelocity;//平滑函数需要这么⼀个平滑加速度, 不需要为他赋值, 但是需要把这个变量当参数传⼊public float speedSmoothTime = 0.13f;//⽤于平滑速度float speedSmoothVelocity;float currentSpeed;public Transform cameraT; //cameraT这个本来是想⽤cameraT = Camera.main.transform;在start函数赋值的,但是不知道这个函数是不是过时了,赋值不上,所以还是采⽤public的⽅式,在编辑器拖动给变量赋值 最普通的WASD移动⽅式void Update(){ float hor = Input.GetAxis("Horizontal");float ver = Input.GetAxis("Vertical");Vector3 PlayerMovement = new vector3(hor,0f,ver)*targetSpeed*Time.deltaTime; transform.Translate(PlayerMovement,Space.Self);} 威⼒加强版未加⼊平滑函数的WASD移动⽅式 void Update(){ //***WASD输⼊***//Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical"));Vector2 inputDir = input.normalized;//反正就是返回⼀个单位长度的这个变量if(inputDir != Vector2.zero) //可能是因为键盘⾃动输⼊0, 玩家不输⼊的时候⾓⾊就会⾃动⾯向正⽅向, 所以加⼀个判定, 输⼊为0的话就是没输⼊, 所以就不要转向{//未加⼊平滑函数的转向transform.eulerAngles =Vector3.up* Mathf.Atan2(inputDir.x,inputDir.y)*Mathf.Rad2Deg; //关于上边这句话详情看unity坐标分析(还没写),这其实就是根据玩家键盘WASD算出来的旋转⾓度}transform.Translate(transform.forward*targetSpeed*Time.deltaTime,Space.World); //因为上边更改了transform的朝向,所以可以直接向transform的正⽅向前进就能达到按照键盘输⼊前进的效果.} 威⼒加强版加⼊平滑和⿏标⼲预的WASD移动⽅式void Update(){ Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical"));Vector2 inputDir = input.normalized; bool running = Input.GetKey(KeyCode.LeftShift);//根据是否按下左shift设定⼀个布尔变量在下⼀句设定是奔跑速度还是⾛路速度float targetSpeed = ((running)?runSpeed:walkSpeed)*inputDir.magnitude; //根据布尔变量获取速度后乘以输⼊向量的长度,当没有任何键盘输⼊时,这个长度是0,有任何输⼊时长度都是1,所以其实是⽤来在键盘没有输⼊时将⽬标速度置0⽤的 transform.Translate(transform.forward*targetSpeed*Time.deltaTime,Space.World); //***转向部分代码***//if(inputDir != Vector2.zero){ //***加⼊⿏标⼲预***//float targetRotation = Mathf.Atan2(inputDir.x,inputDir.y)*Mathf.Rad2Deg+cameraT.eulerAngles.y; //这个cameraT是引⽤的主摄像机(也不知道具体是不是引⽤,等回学校看看headfirstC#),传⼊了主摄像机的y值,⽽在后⾯摄像机的控制代码中,这个y值是受⿏标控制的transform.eulerAngles = Vector3.up*Mathf.SmoothDampAngle(transform.eulerAngles.y,targetRotation,ref turnSmoothVelocity,turnSmoothTime);//上边这个函数是⾓度渐变, 也可以叫平滑吧, 这个ref是什么意思, 以后再说, 还有这个turnSmoothVelocity也以后再说}} 动画状态机代码控制 float animationSpeedPercent = ((running)?0.75f:0.25f)*inputDir.magnitude;//通过布尔变量给这个变量赋值,下⼀句要⽤animator.SetFloat("speedPercent",animationSpeedPercent,speedSmoothTime,Time.deltaTime);//1. 通过调⽤animator变量的setfloat函数给混合状态机的speedPercent参数赋值//2. 这个函数有四个参数, 第三个是⾃带的平滑参数, 也就是说这个aimator⾃带平滑功能,直接输⼊参数就可以调⽤需要创建⼀个状态机, 然后创建⼀个混合状态图层, 新建⼀个控制参数, 就是这个speedPercent, 导⼊⾓⾊动画, 静⽌动画, ⾛路动画, 跑步动画啥的, 就能通过给这个speedPercent赋值来控制⾓⾊动画这个动画状态机后⾯还要专门整理, 包括动画融合等内容摄像机控制(还需要补充层级⾯板配置结构)void LateUpdate()//摄像机控制代码⼀般放在lateupdate函数⾥{CameraControl();}void CameraControl(){mouseX +=Input.GetAxis("Mouse X")*rotationSpeed;mouseY -=Input.GetAxis("Mouse Y")*rotationSpeed;mouseY = Mathf.Clamp(mouseY,-35,60);//限制摄像机旋转⾓度//transform.LookAt(Target);这句话没啥⽤(我也不知道为啥就⾃动看着TargetTarget.rotation = Quaternion.Euler(mouseY,mouseX,0);//Player.rotation = Quaternion.Euler(0,mouseX,0);这句话会因为和PlayerControl内代码同时改变Player⾓度⽽引发摄像机剧烈抖动 //现在PlayerControl脚本⾥旋转那⾥加⼊了摄像机的y轴的值,所以不需要⽤这句话来画蛇添⾜了}全部代码保存(如果有⼀天我真要⽤这份代码 , 最好还是能直接复制粘贴全部代码)PlayerController代码using System.Collections;using System.Collections.Generic;using UnityEngine;public class PlayerController : MonoBehaviour{/***变量声明区域***/float walkSpeed = 5;float runSpeed = 10;Animator animator;//创建⼀个animator变量以待赋值(在start()⽅法⾥赋值)public float turnSmoothTime = 0.13f;//设定⾓⾊转向平滑时间float turnSmoothVelocity;//平滑函数需要这么⼀个平滑加速度, 不需要为他赋值, 但是需要把这个变量当参数传⼊public float speedSmoothTime = 0.13f;//⽤于平滑速度float speedSmoothVelocity;float currentSpeed;public Transform cameraT;// Start is called before the first frame updatevoid Start(){animator = GetComponent<Animator>();//cameraT = Camera.main.transform;}// Update is called once per framevoid Update(){//***WASD输⼊***//Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical"));//获取键盘输⼊Vector2 inputDir = input.normalized;//反正就是返回⼀个单位长度的这个变量//***⾓⾊移动部分***//bool running = Input.GetKey(KeyCode.LeftShift);//按了左shift则bool变量running就是1float targetSpeed = ((running)?runSpeed:walkSpeed)*inputDir.magnitude;//Vector3 PlayerMovement = new Vector3(hor,0f,ver)*targetSpeed*Time.deltaTime;transform.Translate(transform.forward*targetSpeed*Time.deltaTime,Space.World);//让游戏⾓⾊位置移动//transform.Translate(PlayerMovement,Space.Self);//***转向部分***//if(inputDir != Vector2.zero)//可能是因为键盘⾃动收⼊0, 玩家不输⼊的时候⾓⾊就会⾃动⾯向正⽅向, 所以加⼀个判定, 输⼊为0的话就是没输⼊, 所以就不要转向{//平滑转向代码float targetRotation = Mathf.Atan2(inputDir.x,inputDir.y)*Mathf.Rad2Deg+cameraT.eulerAngles.y;//这就是根据玩家键盘输⼊算出来的⽬标转向⾓度(y轴的)transform.eulerAngles = Vector3.up*Mathf.SmoothDampAngle(transform.eulerAngles.y,targetRotation,ref turnSmoothVelocity,turnSmoothTime);//上边这个函数是⾓度渐变, 也可以叫平滑吧, 这个ref是什么意思还存疑, 以后肯定能解决, 还有这个turnSmoothVelocity是什么意思以后迟早能知道, 不急于⼀时 //这个ref就是引⽤参数 , 学点C#就知道了 , ⽤这个参数把⽅法内的数据给保存出来}/***位置运动部分***///这个inputDir是个单位向量,inputDir.magnitude是他的长度,有任何输⼊的时候单位向量的长度都是1, 在键盘没有输⼊的时候这个长度就是0//其实之所以乘以这个长度就是为了能够在玩家没有输⼊的时候把速度变成0//currentSpeed = Mathf.SmoothDamp(currentSpeed,targetSpeed,ref speedSmoothVelocity,speedSmoothTime);//看起来这个函数SmoothDamp以及上边的SmoothDampAngle⼀样, 他们的第⼀个参数其实是被赋值的, 直接把空参数传进去, 就能获得合适的值float animationSpeedPercent = ((running)?0.75f:0.25f)*inputDir.magnitude;//通过布尔变量给动画状态机控制变量赋值animator.SetFloat("speedPercent",animationSpeedPercent,speedSmoothTime,Time.deltaTime);//1. 通过调⽤animator变量的setfloat函数给混合状态机的speedPercent参数赋值//2. 这个函数有四个参数, 第三个是⾃带的平滑参数, 可以通过给这个参数赋值来实现动画状态机⾃动平滑动作}} CameraController代码using System.Collections;using System.Collections.Generic;using UnityEngine;public class ThirdPersonCamera : MonoBehaviour{//****变量声明部分***float yaw; //yaw的中⽂意思是航向, 也就是物体绕y轴旋转⾓度float pitch;//pitch是俯仰, 也就是物体绕x轴旋转⾓度public float mouseSensitivity = 10f;//⿏标灵敏度,因为⿏标要控制摄像机转向public Transform target,player;//1. 这⾥想要获取⼀个对象的transform组件的实例, 先声明⼀个transform以待赋值, 要获取的是游戏⾓⾊⼦对象, ⽤于确定相机位置//2. 这个target会通过编辑器赋值, 就是我创建的CameraPosition⼦对象, 但是其实直接把相机作为⾓⾊的⼦对象岂不是更好??//public float dstFromTarget = 2;//就是相机就距离CameraPosition这个对象两⽶远// Start is called before the first frame updatevoid Start(){}// Update is called once per framevoid Update(){}void LateUpdate(){yaw+=Input.GetAxis("Mouse X")*mouseSensitivity;pitch-=Input.GetAxis("Mouse Y")*mouseSensitivity;Vector3 targetRotation = new Vector3(pitch,yaw,0);//显然我们是不需要摄像机左右倾斜的, 所以z轴锁定为0Vector3 playerRotation = new Vector3(0,yaw,0);//显然我们是不需要摄像机左右倾斜的, 所以z轴锁定为0//***设置相机旋转***//这句话必须要放在下边那句给摄像机⾓度赋值的语句前边才有⽤//transform.LookAt(target.position);//transform.eulerAngles = targetRotation;// player.transform.eulerAngles = playerRotation;//***设置相机位置***//transform.position = target.position-transform.forward*dstFromTarget;//总之是Vector3变量做加减, target.position说的是cameraPosition⼦对象的位置,是在编辑器⾥赋值的, 这个位置的x轴减两⽶就是本对象位置(也就是相机位置) target.rotation = Quaternion.Euler(pitch,yaw,0);//设置摄像机旋转// if(Input.GetKey(KeyCode.W))// {// player.rotation = Quaternion.Euler(0,yaw,0);//设置⾓⾊旋转// }}}。