项目场景:
需求:物体跟随鼠标所指引的方向移动,可以跳跃,奔跑,蹲下。
1.视野跟随鼠标移动
2.由键盘控制物体的上下左右移动过程
3.可以跳跃和奔跑等
解决方案:
有很多在中解决方法,这里讨论两种
1.刚体+胶囊碰撞检测+脚本
2.CharcterController + 脚本
详细讲解:
方案一
思路阐述
1.创建一个GameObject,重命名为FPController
2.在FPController下,创建一个Capsule对象,并给FPController添加 Capsule Collider组件
3.将Camera移动到FPController下
4.给FPController添加RigidBody组件,并限制Rotation x,z,Use Gravity去除。
5.创建FPMouseLook脚本挂载Camera对象上,此脚本的主要作用是根据鼠标的移动,来使照相机的视野发生旋转。 6.创建FPMovement脚本来控制物体的移动
具体结构
FPController对象的一些组件
代码展示
1.FPMouseLook(挂在Camera上的)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FPMouseLook : MonoBehaviour
{
//该脚本挂在Main Camera上
//摄像机的视野跟随着鼠标的移动而移动
private Transform cameraTransform;//摄像机所在的位置
[SerializeField] private Transform charcterTransform;//FPController 的transform
private Vector3 cameraRotation;//摄像机应该旋转的角度
public float MouseSensitivity;//鼠标灵敏度
public Vector2 MaxminAngle;//限制上下所能移动的最大角度
private void Start()
{
cameraTransform = transform;
}
private void Update()
{
var tmp_mouseX = Input.GetAxis("Mouse X");//获取鼠标移动的x轴
var tmp_mouseY = Input.GetAxis("Mouse Y");//获取鼠标移动的y轴
cameraRotation.y += tmp_mouseX * MouseSensitivity;//根据鼠标灵敏度*x轴移动距离 = Y方向上偏移的角度
cameraRotation.x -= tmp_mouseY * MouseSensitivity;//根据鼠标灵敏度*y轴移动距离 = X方向上偏移的角度
cameraRotation.x = Mathf.Clamp(cameraRotation.x,MaxminAngle.x,MaxminAngle.y);//要将垂直方向上偏移的角度控制在设置的范围内
cameraTransform.rotation = Quaternion.Euler(cameraRotation.x,cameraRotation.y,0);//改变摄像机的角度
charcterTransform.rotation = Quaternion.Euler(0, cameraRotation.y, 0);//将FPController的rotation的水平方向,即FPController需要跟着鼠标移动的水平方向移动
//不需要关注垂直方向的变化,简言之,就是头看天,人也不能忘天上走,还是要在水平方向走。
}
}
2.FPMovement(挂在FPController上)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FPMovement : MonoBehaviour
{
public float Speed;//行走速度
private Transform characterTransform;//当前人物的transform
private Rigidbody charcterRigidBody;//刚体
private bool isGrounded;//是否着地
public float Gravity;//重力
public float JumpHeight;//跳跃高度
private void Start()
{
characterTransform = transform;
charcterRigidBody = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
if (isGrounded)
{
//在着地情况下才能移动
var tmp_Horizontal = Input.GetAxis("Horizontal");
var tmp_Vertical = Input.GetAxis("Vertical");
var tmp_CurrentDirection = new Vector3(tmp_Horizontal, 0, tmp_Vertical);// 将用户的移动封装成一个Vector向量
tmp_CurrentDirection = characterTransform.TransformDirection(tmp_CurrentDirection); //FPController需要根据这个方向行动
tmp_CurrentDirection *= Speed;//行动方向*速度 = 矢量
var tmp_CurrentVelocity = charcterRigidBody.velocity;//刚体现有速度
var tmp_VelocityChange = tmp_CurrentDirection - tmp_CurrentVelocity;//矢量相减得到现有速度
tmp_VelocityChange.y = 0;//只关注x,z轴,y轴的矢量为0
charcterRigidBody.AddForce(tmp_VelocityChange, ForceMode.VelocityChange);//刚体添加力
if (Input.GetButtonDown("Jump"))
{
charcterRigidBody.velocity = new Vector3(tmp_CurrentVelocity.x,CalculateJumpHeightSpeed(), tmp_CurrentVelocity.z);
}
}
charcterRigidBody.AddForce(new Vector3(0,-Gravity*charcterRigidBody.mass,0));
}
private float CalculateJumpHeightSpeed()
{
//物理公式,v=开方2gh
return Mathf.Sqrt(2 * Gravity * JumpHeight);
}
private void OnCollisionStay(Collision collision)
{
isGrounded = true;
}
private void OnCollisionExit(Collision collision)
{
isGrounded = false;
}
}
方案二
思路阐述
1.创建一个GameObject,重命名为CharcterController
2.在FPController下,创建一个Capsule对象
3.将Camera移动到CharcterController下
4.创建FPMouseLook脚本挂载Camera对象上,此脚本的主要作用是根据鼠标的移动,来使照相机的视野发生旋转。 5.创建FPCharcterControllerMovement脚本控制移动,不同的是,该对象具有charcterController组件,代码很简单。 #### 具体结构
FPController对象的一些组件
代码展示
1.FPMouseLook(挂在Camera上的)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FPMouseLook : MonoBehaviour
{
//该脚本挂在Main Camera上
//摄像机的视野跟随着鼠标的移动而移动
private Transform cameraTransform;//摄像机所在的位置
[SerializeField] private Transform charcterTransform;//FPController 的transform
private Vector3 cameraRotation;//摄像机应该旋转的角度
public float MouseSensitivity;//鼠标灵敏度
public Vector2 MaxminAngle;//限制上下所能移动的最大角度
private void Start()
{
cameraTransform = transform;
}
private void Update()
{
var tmp_mouseX = Input.GetAxis("Mouse X");//获取鼠标移动的x轴
var tmp_mouseY = Input.GetAxis("Mouse Y");//获取鼠标移动的y轴
cameraRotation.y += tmp_mouseX * MouseSensitivity;//根据鼠标灵敏度*x轴移动距离 = Y方向上偏移的角度
cameraRotation.x -= tmp_mouseY * MouseSensitivity;//根据鼠标灵敏度*y轴移动距离 = X方向上偏移的角度
cameraRotation.x = Mathf.Clamp(cameraRotation.x,MaxminAngle.x,MaxminAngle.y);//要将垂直方向上偏移的角度控制在设置的范围内
cameraTransform.rotation = Quaternion.Euler(cameraRotation.x,cameraRotation.y,0);//改变摄像机的角度
charcterTransform.rotation = Quaternion.Euler(0, cameraRotation.y, 0);//将FPController的rotation的水平方向,即FPController需要跟着鼠标移动的水平方向移动
//不需要关注垂直方向的变化,简言之,就是头看天,人也不能忘天上走,还是要在水平方向走。
}
}
2.FPCharcterControllerMovement(挂在CharcterController上)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FPCharcterControllerMovement : MonoBehaviour
{
private CharacterController characterController;
private Transform charcterTransform;
private float Gravity = 9.8f;
private Vector3 movementDirection;
private bool isCrouch;
public float crouchHeight = 1f;
private float originHeight;
public float walkSpeed;
public float jumpHeight;
public float sprintingSpeed;
public float sprintingSpeedCrouched;
public float walkSpeedCrouched;
void Start()
{
characterController = GetComponent<CharacterController>();
charcterTransform = transform;
originHeight = characterController.height;
}
// Update is called once per frame
void Update()
{
float tmp_Speed = walkSpeed;
if (characterController.isGrounded)
{
var tmp_Horizontal = Input.GetAxis("Horizontal");
var tmp_Vertical = Input.GetAxis("Vertical");
movementDirection =
charcterTransform.TransformDirection(new Vector3(tmp_Horizontal, 0, tmp_Vertical));
if (Input.GetButtonDown("Jump"))
{
movementDirection.y = jumpHeight;
}
if (isCrouch)
{
tmp_Speed = Input.GetKey(KeyCode.LeftShift) ? sprintingSpeedCrouched : walkSpeedCrouched;
}
else
{
tmp_Speed = Input.GetKey(KeyCode.LeftShift) ? sprintingSpeed : walkSpeed;
}
if (Input.GetKeyDown(KeyCode.C))
{
var temp_CurentHeight = isCrouch ? originHeight : crouchHeight;
StartCoroutine(DoCrouch(temp_CurentHeight));
isCrouch = !isCrouch;
}
}
movementDirection.y -= Gravity * Time.deltaTime;
characterController.Move(movementDirection * Time.deltaTime * tmp_Speed);
}
IEnumerator DoCrouch(float target)
{
float tmp_CurrentHeight = 0;
while (Mathf.Abs(characterController.height - target) > 0.1f)
{
yield return null;
characterController.height = Mathf.SmoothDamp(characterController.height,target,ref tmp_CurrentHeight,Time.deltaTime*5);
}
}
}
总结:
通过两种不同的方式来移动对象,学习到了很多知识,尤其是transform变换这一块。