using UnityEngine;
using System.Collections;
[RequireComponent(typeof(Rigidbody ))]//编译时加一个判断是否有刚体
[RequireComponent(typeof(CapsuleCollider ))]//是否有碰撞器
public classPlayerController : MonoBehaviour {
[System .Serializable ]//解决可视化的问题 让这个类可以在unity面板中看到 //new了也可以看到
//这是个内部类
publicclassMoveSetting//定义一个控制速度的类
{
publicfloatForwarSpeed = 5f;//前进的速度
publicfloatBackSpeed = 3f;//后退的速度
publicfloatHorizonSpeed = 4f;//平移的速度
publicfloatRunValue = 2f;//跑的速度(加速)(倍数)
publicfloatJumpForce = 50f;//跳
}
[System.Serializable]
publicclassMouseLook//定义一个鼠标看的速度(视角移动的速度)
{
publicfloatXSensitive = 2f;//鼠标X轴移动速度
publicfloatYSensitive = 2f;//鼠标Y轴移动速度
}
publicMoveSetting moveSet;//实例化一个这个类的对象
publicMouseLook CameraSet;//同样实例化一个
privatefloatcurrentSpeed;//定义一个当前速度
privateboolm_jump;//是否跳跃的布尔值
privateCapsuleCollider m_capsule;//胶囊的碰撞器
privateRigidbody m_rigidody;//胶囊的刚体
privateCamera m_camera;//定义相机
//定义相机的Transtorm(减少Update中transform的调用)
privateTransform m_camTrans;
//定义主角的transform
privateTransform m_chaTrans;
//定义主角的欧拉角
privateVector3 m_chaRotate;
//定义摄像机欧拉角
privateVector3 m_camRotate;
//定义主角的旋转四元素
privateQuaternion m_chaQuaternion;
//定义摄像机旋转四元素
privateQuaternion m_camQuaternion;
[HideInInspector]//用来在unity面板上隐藏public
publicfloatTestParam;//测验
publicboolm_isOnGround;//是否在地面上的布尔值
publicAnimationCurve SlopCurve;//利用AnimationCurve 工具
privateVector3 curGroundNormal;
//Use this for initialization
voidStart () {
m_capsule = GetComponent<CapsuleCollider>();//拿到胶囊的碰撞器
m_rigidody = GetComponent<Rigidbody>();//拿到胶囊的刚体
m_camera = Camera.main; //拿到主 摄像机
m_camTrans = m_camera.transform;//拿到摄相机的transform
m_chaTrans = transform;//拿到player的transform
m_chaQuaternion = m_camTrans.rotation ;//拿到摄像机的四元素
m_camQuaternion = m_chaTrans.rotation;//拿到player的四元素
}
//Update is called once per frame
voidUpdate () {
RotateView();//调用视图旋转的方法
if(Input.GetKeyDown (KeyCode.Space))
{
m_jump = true;
}
}
voidFixedUpdate()
{
DoMove();//一般执行物理效果的都在这里 如果放在Update里会跳帧 因为Update的渲染时间是不固定的工作量大了时间会长
}
//视图的旋转
voidRotateView()
{
floatxRot = Input.GetAxis("MouseY") * CameraSet .YSensitive ;//定义一个鼠标垂直方向上的变化的值
floatyRot = Input.GetAxis("MouseX") * CameraSet .XSensitive;//定义一个鼠标水平方向上的变化的值
//摄像机的上下旋转 //四元素的使用
{
m_camQuaternion *= Quaternion.Euler(-xRot,0f, 0f);//四元素进行运算(后面是欧拉角)赋值给摄像机的四元素
m_camQuaternion = ClampRotation(m_camQuaternion);//将四元素转换为新的四元素
m_camTrans.localRotation = m_camQuaternion;//将四元素赋值给摄像机的transform按自身旋转
m_chaQuaternion *= Quaternion.Euler(0f,yRot, 0f);//同理
//m_chaQuaternion = ClampRotation(m_chaQuaternion);//人物可以旋转所以水平不用约束
m_chaTrans.rotation = m_chaQuaternion;
}
}
//关于运动的方法
voidDoMove()
{
CheckGround();//先检测地面 判断是否在地面上
Vector2 input = GetInput();//调用GetInput 方法得到input
CaculateSpeed(input);//调用计算速度方法得出什么情况该使用什么样的速度
//如果input.x和input.y有一个大于零而且在地面上
if((Mathf.Abs(input.x) > float.Epsilon || Mathf .Abs (input.y) > float.Epsilon) && m_isOnGround )
{
Vector3 desireMove = m_camTrans.forward * input.y +m_camTrans.right * input.x;//摄像机的前方*input.y得到一个向前(或向后)的向量,player的左边*input.x 得到一个向左(或向右)的向量 再相加得到一个新的方向向量
desireMove = Vector3.ProjectOnPlane(desireMove,curGroundNormal).normalized;//投影在地面上 返回一个单位向量
desireMove*= currentSpeed;//将单位向量*=当前速度 用来区分当前是什么状态什么速度
if(m_rigidody .velocity .sqrMagnitude < currentSpeed * currentSpeed )//拿到 刚体.速度.的Vector3的平方和与定义的当前速度比较 (也就是实在的当前前进速度不能大于5,后退速度不能大于3。。。)
{
m_rigidody.AddForce(desireMove * SlopeValue(), ForceMode.Impulse);//加一个持续的力方向为desireMove 与 地面有关系
}
}
//跳跃方法
if(m_isOnGround )
{
m_rigidody.drag = 5f;//如果在地面上阻力位5
jumptime = 0;//在这里给jumptime重新赋值
if(m_jump )//在地面如果按下空格m_jump变为true 可以起跳
{
JumpUp();
}
}
else
{
if( m_jump)//如果不再地面
{
jumptime++;//jumptime++,第一次起跳为1//第二次跳完 为2
if (jumptime <2)//如果小于2
{
JumpUp();//还可以跳
}
}
Debug.Log(jumptime);
m_rigidody.drag = 0f;//如果不在地面阻力为0
}
m_jump = false; //如果在地面m_jump为false 可以起跳
CheckBuffer();
}
intjumptime = 0;//不能放在update方法里面,会重新初始化
voidJumpUp()
{
m_rigidody.drag = 0f;//如果跳起阻力位0
m_rigidody.velocity = new Vector3(m_rigidody.velocity.x, 0f, m_rigidody.velocity.z);//起跳后速度为
m_rigidody.AddForce(new Vector3(0, moveSet.JumpForce, 0), ForceMode.Impulse);//Y轴加一个持续的力
}
//检测方向键输入
Vector2 GetInput()
{
//得到一个Vector2参数(input水平的float值,input垂直的float值)
Vector2 input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));//定义Vector2类型变量 input
returninput;//返回input
}
//计算速度
voidCaculateSpeed(Vector2 _input)
{
currentSpeed = moveSet.ForwarSpeed;//开始当前速度为向前的速度
//前进 后退
if(Mathf.Abs(_input .x)>float.Epsilon)//input.x为input的第一个参数 因为是-1到1 有正有负所以用一下绝对值计算float.Epsilon为float值的最小值无限接近0
{
currentSpeed = moveSet.HorizonSpeed;//如果成立速度改变为平移速度
}
elseif(_input.y<0)//第二个参数,
{
currentSpeed = moveSet.BackSpeed;//如果为负就改为后退速度
}
elseif(Input .GetKey (KeyCode.LeftShift ))//如果按下LeftShift就改为加速
{
currentSpeed *= moveSet.RunValue;//加速是倍数 要乘
}
Debug.Log("currentSpeed: "+ currentSpeed);//打印当前速度
}
//爬坡参数
floatSlopeValue()
{
floatangle = Vector3.Angle(curGroundNormal, Vector3.up);//定义一个角度为地面法向量为y轴的夹角
floatvalue = SlopCurve.Evaluate(angle);//使用Evaluate方法来求当一个值为angle时对应曲线上的另一个值
returnvalue;//返回这个值
}
//检测地面
void CheckGround()
{
RaycastHit hit;//射线检测
//球形射线检测 //射线的起点 //球形的半径,胶囊 //射线的方向//射线的信息 //检测的最大距离+ 余富量
if(Physics .SphereCast (m_capsule .transform .position ,m_capsule.radius,Vector3 .down ,outhit ,((m_capsule .height /2 - m_capsule.radius )+0.01f) ))//方法返回值为booltrue为检测到了,false为没有
{
curGroundNormal = hit.normal;//将射线检测时拿到的垂直于地面的的法线向量赋值给我们定义的地面法向量
m_isOnGround = true;//说明碰到了地面 在地面上 设为true
}
else
{
curGroundNormal = Vector3.up;//如果没有检测到法向量默认为向上的
m_isOnGround = false;//没在地面上
}
}
voidCheckBuffer()
{
floatDownSpeed = m_rigidody.velocity.y;
if(DownSpeed < 0)
{
RaycastHit hit;//射线检测
if(Physics.SphereCast(m_capsule.transform.position,m_capsule.radius, Vector3.down, outhit, ((m_capsule.height / 2 - m_capsule.radius) + 1f)))//方法返回值为bool true为检测到了,false为没有//将检测的最大距离增大 实现一个还未落地的控制减速缓冲的效果
{
DownSpeed *= 0.5f;
m_rigidody.velocity = new Vector3(m_rigidody.velocity.x, DownSpeed,m_rigidody.velocity.z);
}
}
}
Quaternion ClampRotation(Quaternionq)//将四元素约束在某个区间内的方法
{
q.x/= q.w;
q.y/= q.w;
q.z /=q.w;
q.w =1;
floatangle = 2 * Mathf.Rad2Deg * Mathf.Atan(q.x);//将弧长转换为float的角度值
angle= Mathf.Clamp(angle, -50f, 50f);//将角度约束
q.x =Mathf.Tan(Mathf.Deg2Rad* (angle / 2));//转换为四元素 (将角度转换为弧长)
returnq;
}
}