低い場所に入るためにしゃがみのアクションが必要になることがあります。ここではしゃがむための機能を実装しましょう。
目次
実装概要
今回はやや複雑に感じるスクリプトかも。
完成品
しゃがみ処理は変更するパラメータが多いため、シーンビューを見ながら動かすとイメージがしやすくなります。緑のカプセルが形を変えているのはCharacterControllerの高さなどを変更している影響です。
身につくもの
普段はプリセットして利用するCharacterControllerの動的な変更が必要になります。
- CharacterControllerの高さ変更
- FPController固有の問題
- Cameraの高さなどは独自の問題
- await/asyncでの非同期処理
実装開始ッ!
FPCrouchコンポーネント作成
今回はちょっと変数などが多いです。注意点や実装の中での補足は以下
- 実装でのポリシー
- インスペクターでのコントロール
- しゃがんだときの高さを指定
- しゃがみボタンのキー
- しゃがみに必要な時間
- 起動時の高さを基準に、しゃがんだときの高さで比率を計算
- CharacterControllerの高さと中心を比率にあわせて操作
- インスペクターでのコントロール
- 非同期処理を実装するためにusing System.Threading.Tasks;を追加
- await/asyncを利用するために必要になります
using System.Threading.Tasks;
using UnityEngine;
public class FPCrouch : FPComponentBase
{
[SerializeField] private float crouchingHeight = 1.0f;
[SerializeField] private KeyCode crouchKey = KeyCode.LeftControl;
[SerializeField] private float duration = 0.5f;
private bool isCrouchAvailable = true;
private bool isCrouching = false;
private Transform cameraRootTransform;
private float standingCameraHeight;
private float standingHeight;
private Vector3 standingCenter;
private float crouchingCameraHeight;
private Vector3 crouchingCenter;
public override void initialize()
{
base.initialize();
cameraRootTransform = Controller.PlayerCamera.transform.parent;
standingCameraHeight = cameraRootTransform.localPosition.y;
standingHeight = Controller.CharacterController.height;
standingCenter = Controller.CharacterController.center;
float crouchingHeightRatio = crouchingHeight / standingHeight;
crouchingCameraHeight = cameraRootTransform.transform.localPosition.y * crouchingHeightRatio;
crouchingCenter = standingCenter * crouchingHeightRatio;
}
private void Update()
{
if (isCrouchAvailable && Input.GetKeyDown(crouchKey))
{
isCrouchAvailable = false;
isCrouching = !isCrouching;
CrouchAction(isCrouching);
}
}
private async void CrouchAction(bool isCrouch)
{
float currentHeight = Controller.CharacterController.height;
float targetHeight = isCrouch ? crouchingHeight : standingHeight;
Vector3 currentCenter = Controller.CharacterController.center;
Vector3 targetCenter = isCrouch ? crouchingCenter : standingCenter;
float currentCameraHeight = cameraRootTransform.localPosition.y;
float targetCameraHeight = isCrouch ? crouchingCameraHeight : standingCameraHeight;
float time = 0;
while (time < duration)
{
time += Time.deltaTime;
await Task.Delay((int)(Time.deltaTime * 1000));
float cameraHeight = Mathf.Lerp(currentCameraHeight, targetCameraHeight, time / duration);
cameraRootTransform.localPosition = new Vector3(cameraRootTransform.localPosition.x, cameraHeight, cameraRootTransform.localPosition.z);
Controller.CharacterController.height = Mathf.Lerp(currentHeight, targetHeight, time / duration);
Controller.CharacterController.center = Vector3.Lerp(currentCenter, targetCenter, time / duration);
}
isCrouchAvailable = true;
}
}
コメント