概述
最近在项目中遇到一个需求,要求软件中人物的操作为第一人称视角,并且不包含重力。要求用户可以自定义重力。
在经过一番思考之后,我想到了一种解决方案,那就是通过控制相机物体的transform属性,来对相机进行移动。至于相机的视角,我参考了unity自带的第一人称视角控制器的代码来实现。经过一番折腾是实现了,但是在测试过程中发现了一个问题。
那就是
在移动过程中,相机穿越了墙壁!!!!
就算给相机物体添加一个立方体gameobject作为父物体,并且给该父物体添加刚体,也还是没有用。墙壁的碰撞器虽然会触发碰撞事件。但是并没有作用,相机还是会穿越墙壁。这样完全不符合实际的使用需求。经过一番思考,猜测,验证。并参考了系统的FirstPersonController文件,终于找到了原因。原因是对于相机的移动,我是直接了对物体的transform值进行更改来使物体移动,这样我虽然给物体添加了刚体,但是物体并有进行物理学运动,因此物体不会遵循物理学运动现象。
知道了原因,那么就好结局了,既然是因为我对物体进行移动的操作方式有问题,那就换一种操作方式。unity有提供定义好的第一人称控制器,那我去修改一下控制器的代码,变成我需要的代码即可。
在研究了unity自带的控制器代码之后,我发现unity对于移动物体的方式是,对需要移动的物体施加力来进行移动。通过获取物体的rigidbody属性,然后通过AddForce的方式,来对物体进行移动。并且找到了控制器是通过StickToGroundHelper方法将物体固定在地板上,原理是物体向下发射一条射线,如果射线的长度不为0,物体会向下运动。那么是要将StickToGroundHelper方法去除,剩下的代码进行保留,那么就可以实现最基本的无重力第一人称视角。再通过自定义按键,给物体添加向上或者向下的力,来控制物体的向上或者向下运动,就能实现第一人称无重力控制器。
最终的实现代码如下:
public Transform target;
private float sliderMouseValue = 0.5f;
public bool isScaleFabric = false;
public float keyboardSpeed = 2f;
[Serializable]
public class MovementSettings
{
public float ForwardSpeed = 2.0f;
// Speed when walking forward
public float BackwardSpeed = 2.0f;
// Speed when walking backwards
public float StrafeSpeed = 2.0f;
// Speed when walking sideways
[HideInInspector]
public float CurrentTargetSpeed = 8f;
public void UpdateDesiredTargetSpeed(Vector2 input)
{
if (input == Vector2.zero) return;
if (input.x > 0 || input.x < 0)
{
//strafe
CurrentTargetSpeed = StrafeSpeed;
}
if (input.y < 0)
{
//backwards
CurrentTargetSpeed = BackwardSpeed;
}
if (input.y > 0)
{
//forwards
//handled last as if strafing and moving forward at the same time forwards speed should take precedence
CurrentTargetSpeed = ForwardSpeed;
}
}
}
public Camera cam;
public MovementSettings movementSettings = new MovementSettings();
public MouseLook mouseLook = new MouseLook();
private Rigidbody m_RigidBody;
private void Start()
{
m_RigidBody = GetComponent<Rigidbody>();
mouseLook.Init(transform, cam.transform);
}
private void Update()
{
if (isOpenCameraMove && !isScaleFabric && panelS.canEdit)
{
if (Cursor.visible == true) {
Cursor.visible = false;
}
RotateView();
}
if (Input.GetKeyDown(KeyCode.Z) && !isScaleFabric && panelS.canEdit)
{
inputKeyDownZ ();
}
}
private void inputKeyDownZ () {
isOpenCameraMove = !isOpenCameraMove;
//
鼠标显示隐藏
if (isOpenCameraMove) {
shadowAlphaTween.gameObject.SetActive (true);
shadowAlphaTween.PlayReverse ();
Cursor.visible = false;
} else {
shadowAlphaTween.PlayForward ();
StartCoroutine (HidePanel (shadowAlphaTween.gameObject));
#if UNITY_STANDALONE_WIN
SetCursorPos((int) panelS.device_width/2,(int)panelS.device_height/2);
#endif
Cursor.visible = true;
}
}
private void FixedUpdate()
{
if (isOpenCameraMove && target && !isScaleFabric && panelS.canEdit)
{
Vector2 input = GetInput();
//
if ((Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon) /*&& (advancedSettings.airControl || m_IsGrounded)*/)
//
{
// always move along the camera forward as it is the direction that it being aimed at
Vector3 desiredMove = cam.transform.forward * input.y + cam.transform.right * input.x;
desiredMove.x = desiredMove.x * movementSettings.CurrentTargetSpeed;
desiredMove.y = desiredMove.y * movementSettings.CurrentTargetSpeed;
desiredMove.z = desiredMove.z * movementSettings.CurrentTargetSpeed;
if (m_RigidBody.velocity.sqrMagnitude <
(movementSettings.CurrentTargetSpeed * movementSettings.CurrentTargetSpeed))
{
m_RigidBody.AddForce(desiredMove, ForceMode.Impulse);
}
//
}
m_RigidBody.drag = 5f;
//
if (Mathf.Abs(input.x) < float.Epsilon && Mathf.Abs(input.y) < float.Epsilon && m_RigidBody.velocity.magnitude < 1f)
//
{
//
m_RigidBody.Sleep();
//
}
if (Input.GetKey(KeyCode.Q)) {
m_RigidBody.AddForce(new Vector3(0f, keyboardSpeed, 0f), ForceMode.Impulse);
}
if (Input.GetKey(KeyCode.E))
{
m_RigidBody.AddForce(new Vector3(0f, -keyboardSpeed, 0f), ForceMode.Impulse);
}
}
}
private Vector2 GetInput()
{
Vector2 input = new Vector2
{
x = CrossPlatformInputManager.GetAxis("Horizontal"),
y = CrossPlatformInputManager.GetAxis("Vertical") + Input.GetAxis("Mouse ScrollWheel") * 2
};
movementSettings.UpdateDesiredTargetSpeed(input);
return input;
}
private void RotateView()
{
//avoids the mouse looking if the game is effectively paused
if (Mathf.Abs (Time.timeScale) < float.Epsilon)
return;
// get the rotation before it's changed
float oldYRotation = transform.eulerAngles.y;
mouseLook.LookRotation (transform, cam.transform);
// Rotate the rigidbody velocity to match the new direction that the character is looking
Quaternion velRotation = Quaternion.AngleAxis (transform.eulerAngles.y - oldYRotation, Vector3.up);
m_RigidBody.velocity = velRotation * m_RigidBody.velocity;
}
public void changeMouseSpeed (UISlider slider) {
//
this.movementSettings.StrafeSpeed = 0.5f + slider.value * 6f;
//
this.movementSettings.ForwardSpeed = 1f + slider.value * 10f;
//
this.movementSettings.BackwardSpeed = 0.5f + slider.value * 6f;
mouseLook.XSensitivity = 0.1f + 1.9f * slider.value;
mouseLook.YSensitivity = 0.1f + 1.9f * slider.value;
}
ps:如果需要更改视角的旋转速度,可以参考代码中的changeMouseSpeed方法,另外如果移动速度过快,肯能会导致unity来不及检测碰撞进行处理,最终使得物体仍然穿越墙壁。建议速度不要过大,另外也可以打开unity中的 Edit –> Project Settings –> Time 的属性面板,通过调节Fixed Timestep属性值,来缩短检测时间。
最后
以上就是苗条外套为你收集整理的Unity 之第一人称无重力控制器的全部内容,希望文章能够帮你解决Unity 之第一人称无重力控制器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复