主なコンテンツ

〜主なコンテンツ〜

1. Unityで製作したゲームと製作Tips
  1. 三月精チャレンジ(東方Project二次創作)
    1. 作り方
  2. 英語学習2D(オリジナルスマホアプリ)
2. UE4
3. ゲームアプリ見学
4. Bitbucket & SourceTreeでの一連の流れ
  1. 前半
  2. 後半
5. Tips
  1. UnityのTips
  5. SQL文のTips
  6. Final IK
  7. GearVR+Unity

2016年12月22日木曜日

遅れてついてくるカメラについて

単純そうで意外と奥が深かったので、知識をこつこつまとめていく。

  • Smooth系とLerp系について
    • Mathfについての解説(参考
    • unity smoothdamp vs lerp(参考
      • smoothは曲線補間、lerpは線形補間とのこと
    • Unity側はsmoothdampを想定している(参考
  • 処理を行うUpdateの種類について
    • まずは基本のおさらい(公式:イベント関数の実行順
      • この情報自体が正しくないという話もあるので、あくまで基本
      • この図を見るとUpdate前に必ずFixedUpdateが呼ばれているように見えるが、FixedUpdateは固定フレームの物理演算用のUpdateなので通常のUpdateとは非同期
    • RigidBodyの処理はFixedUpdateで行う(参考
      • このことはFixedUpdateのリファレンスにも書いてある(参考
    • カメラの追従はLateUpdate推奨(参考
    • 低速での追従でどうしてもガタツキがでる現象について
      • FPSを意図的に落としてFixedUpdateで呼び出す(参考

    今回、ロボットの頭に追従するカメラを作成したが、最終的に次のようにした。

    using UnityEngine;
    using System.Collections;
    public class FollowingCocpit_2 : MonoBehaviour {
    private Transform _followedTarget;//<! 追従対象
    private Transform _cockpitPosTra;//<! コクピット収納位置
    private Transform _dummyTarget;//<! 追従対象のダミー(ダメージモーション等のとき、本来の頭の位置に設置する)
    private Transform _player;
    private float _t = 0f;
    [SerializeField] private float _limitRot = 0f;
    [SerializeField] private float _accelerationInLimitRot = 5f;
    [SerializeField] private float _rotSpeed = 1f;
    [SerializeField] private float _posSpeed = 0.3f;
    void Start()
    {
    // プレイヤーからアクセスできるよう自身を登録
    _player = GameObject.FindWithTag("Player").transform;
    _player.GetComponent<MSManager>().SetCockpitFollowing(this);
    // コクピット収納位置
    _cockpitPosTra = _player.GetComponent<MSManager>().msData.GetCockpitPositionTransform();
    transform.position = _cockpitPosTra.position;
    // 最初はコクピット収納位置に追従
    _followedTarget = _cockpitPosTra;
    //ダミーを複製しておく
    _dummyTarget = Object.Instantiate(_cockpitPosTra.gameObject).transform;
    _dummyTarget.name = _cockpitPosTra.gameObject.name + " Dummy";
    JoinToRealHead();
    }
    void Update()
    {
    if (_followedTarget == null) return;
    ControlRotation();
    ControlPosition();//アニメーション適用後なので、IKにより位置が変わると差異が生まれる
    Debug.DrawLine(_dummyTarget.position, _followedTarget.position,Color.red);
    }
    void ControlPosition()
    {
    if (transform.position == _cockpitPosTra.position && _t == 1) return;
    _t = Mathf.Clamp01(_t + Time.deltaTime * _posSpeed);
    Debug.Log(_t);
    Vector3 goal = Vector3.Lerp(_dummyTarget.position, _cockpitPosTra.position, _t);//_dummyTarget.position が _cockpitPosTra.positionと同値の場合、_tは無関係
    transform.position = goal;
    }
    void ControlRotation()
    {
    //回転の追従
    float angle = Quaternion.Angle(transform.rotation, _followedTarget.rotation);
    float amp = 1 + Mathf.InverseLerp(_limitRot, 180, angle) * _accelerationInLimitRot;
    transform.rotation = Quaternion.Slerp(transform.rotation, _followedTarget.rotation, Time.deltaTime * _rotSpeed * amp);
    }
    //! Animatorから呼び出す
    public void LeaveFromRealHead()
    {
    _t = 0;
    if (_followedTarget == _dummyTarget) return;
    Debug.Log("Leave");
    //! 呼ばれた時点での頭の座標と向きをコピー
    _dummyTarget.position = _cockpitPosTra.position;
    _dummyTarget.rotation = _cockpitPosTra.rotation;
    //親を変える
    _dummyTarget.parent = _player.transform;
    //! 追従対象を変える
    _followedTarget = _dummyTarget;
    }
    //! Animatorから呼び出す
    public void JoinToRealHead()
    {
    Debug.Log("Join");
    //! 呼ばれた時点での頭の座標と向きをコピー
    _dummyTarget.position = _cockpitPosTra.position;
    _dummyTarget.rotation = _cockpitPosTra.rotation;
    //親を変える
    _dummyTarget.parent = _cockpitPosTra.transform;
    //! 追従対象を変える
    _followedTarget = _cockpitPosTra;
    }
    }