一、摄像机绕转脚本
1、定义游戏对象
[SerializeField] private Transform target;
使用Transform是因为所有的游戏对象的层级视图里面都有Transform属性。定义Transform和定义GameObject是等同的。大多数情况下都可以把游戏对象定义为Transform,Transform这个类型会有很多方便的方法。
2、起始角度和偏移值的初始化
//起始的y的角度
_rotY = transform.eulerAngles.y;
//偏移值=player的位置减掉摄像机的位置
_offset = target.position - transform.position;
使用四元数,偏移值使得摄像机始终指向某一个位置,做差值比较方便
3、LateUpdate方法中控制摄像机位置的移动
也是逐帧执行,区别于Update, LateUpdate是所有的Update做完之后再执行
float horInput = Input.GetAxis("Horizontal");
if(horInput!=0)
{
//键盘旋转摄像机
_rotY += horInput * rotSpeed;
}
else
{
//使用鼠标快速旋转摄像机
_rotY += Input.GetAxis("Mouse X") * rotSpeed * 3;
}
Quaternion rotation = Quaternion.Euler(0, _rotY, 0);
transform.position = target.position - (rotation * _offset);
transform.LookAt(target);
基于目标的位置和旋转值来定位摄像机,Quaternion来存储和表示对象的旋转角度
①Quaternion rotation = Quaternion.Euler(0, _rotY, 0);
四元数表示对象的旋转角度。摄像机的旋转与移动,X方向移动鼠标或者按键盘会产生X方向的旋转,旋转角度为_rotY,这个角度通过鼠标的输入或者键盘的输入来确定
②transform.position = target.position - (rotation * _offset);
摄像机的位置为玩家的位置再减掉偏移值成旋转的角度
③transform.LookAt(target);
使摄像机朝向玩家
二、player绕摄像机移动
先转方向后移动
1、关联摄像机
[SerializeField] private Transform target;
2、针对着摄像机进行左右的运动
Quaternion direction = Quaternion.LookRotation(movement);
transform.rotation = Quaternion.Lerp(transform.rotation, direction, rotSpeed * Time.deltaTime);
三、利用垂直速度和加速度实现起跳和下落
1、定义
public float jumpSpeed = 15.0f;//跳跃时向上的速度
public float gravity = -9.8f;//重力加速度
public float terminalVelocity = -10.0f;//最大的向下速度
public float minFall = -1.5f;//默认状态下给的向下的速度
private float _vertSpeed;//当前速度
2、在Update方法中产生相应的控制
if(_charController.isGrounded)//在地面
{
if(Input.GetButtonDown("Jump"))//按下空格
{
_vertSpeed = jumpSpeed;//给一个向上的速度
}
else
{
_vertSpeed = minFall;//给一个向下的速度压着
}
}
else//不在地面
{
_vertSpeed += gravity * 5 * Time.deltaTime;//速度快速减小
if(_vertSpeed<terminalVelocity)//下落速度最小为terminalVelocity
{
_vertSpeed = terminalVelocity;
}
}
movement.y = _vertSpeed;
分为player是否在地面上的判断。在地面上的话就判断时候按下跳跃的按键(默认空格),如果按下就给_vertSpeed速度向上,如果没有按下就给_vertSpeed速度向下,使得player在地面上。不在地面上的话就让_vertSpeed加上重力加速度使得_vertSpeed减小,模拟重力加速度的作用,等到_vertSpeed一直减小到terminalVelocity这个最小的下落速度的时候保持这个速度不变直到到达地面。最后给movement.y = _vertSpeed实现player的移动
3、在边缘会产产生悬空的行为
解决方法:从player的脚底打出一条射线,会返回player和地面之间距离。如果这个值小于某个值则是在地面上,如果大于这个值则处于悬空状态。
1)定义变量
private ControllerColliderHit _contract;
2)
if(_vertSpeed<0&&Physics.Raycast(transform.position,Vector3.down,out hit))
{
float check = (_charController.height + _charController.radius) / 1.9f;
hitGround = hit.distance <= check;
}
用于确定hitGround的值,如果说hit.distance <= check就说明还在地面上,所以hitGround=true;否则说明不在地面上,hitGround=false
2)
if(hitGround)
{
if(Input.GetButtonDown("Jump"))
{
_vertSpeed = jumpSpeed;
}
else
{
_vertSpeed = minFall;
}
}
else//不在地面
{
_vertSpeed += gravity * 5 * Time.deltaTime;//速度快速减小
if(_vertSpeed<terminalVelocity)//下落速度最大为terminalVelocity
{
_vertSpeed = terminalVelocity;
}
if (_charController.isGrounded)
{
if (Vector3.Dot(movement, _contract.normal) < 0)//朝外
{
movement = _contract.normal * moveSpeed;
}
else
{
movement += _contract.normal * moveSpeed;
}
}
}
如果在地面上,在判断是否按下“Jump”按键。如果按下了还是给player一个向上的速度,如果没有按下就给一个向下的速度压住;如果不在地面上,给当前速度_vertSpeed加上重力加速度使得速度不断减小,同样当速度等于某一个值terminalVelocity的时候使得速度不再改变。还要判断_charController.isGrounded是否在地面上,如果在,继续判断Vector3.Dot(movement, _contract.normal) < 0是否成立,成立即player是朝外的,就让movement = _contract.normal * moveSpeed;;否则,说明是朝内的,就让movement += _contract.normal moveSpeed;。