Skip to content

Instantly share code, notes, and snippets.

@Taka414
Last active Jun 20, 2020
Embed
What would you like to do?
[Unity] Port 'Jumpby' from Cocos2d-x
//
// (c) 2020 Tapap.
// Licensed under MIT.
//
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Takap.Utility
{
/// <summary>
/// 2D用の放物投射運動を行います。
/// 動作が開始されたときの位置からの相対移動を行います。
/// </summary>
public class JumpBy : MonoBehaviour
{
//
// Fields & Inspectotors
// - - - - - - - - - - - - - - - - - - - -
// ジャンプパラメータを格納するリスト
[SerializeField] private List<JumpByParameter> _jumpParameterList = new List<JumpByParameter>();
// 実行終了後にコンポーネントを削除するかどうかのフラグ
// true : 削除する(既定値) / false : 削除しない
[SerializeField] private bool _isRemoveComponentFinished = true;
//
// Fields
// - - - - - - - - - - - - - - - - - - - -
// 現在のジャンプパラメーター
private JumpByParameter _currentParan;
// 一時停止中かどうかのフラグ
// true : 再生中 / false : 停止中
private bool _isRunning;
// ジャンプ開始位置
private Vector3 _startLocalPos;
// 経過時間(秒)
private float _elapsed;
// アニメーション実行通知を行ったかどうかのフラグ
// true : 通知済み完了 / false : まだ
private bool _isNotifyAnimationCompleted;
// transformのCache
private Transform _transform;
//
// Events
// - - - - - - - - - - - - - - - - - - -
/// <summary>
/// アニメーションが完了したときに1度だけ発生します。
/// </summary>
//public System.IObservable<ParabolicJumpBy> AnimationCompleted => this.completedSubject;
public Action AnimationCompleted { get; set; } = () => { /*Debug.Log("completed.");*/ };
//
// Props
// - - - - - - - - - - - - - - - - - - - -
/// <summary>
/// アニメーション開始位置(ローカル)を取得します。
/// </summary>
public Vector3 StartLocalPos => _startLocalPos;
//
// Runtime impl
// - - - - - - - - - - - - - - - - - - - -
protected void Update()
{
if (!_isRunning) return;
if (_elapsed > _currentParan.Duration)
{
_elapsed = _currentParan.Duration; // 最終位置を保障する
_transform.SetLocalPos(_startLocalPos + _currentParan.DeltaPos);
if (!_isNotifyAnimationCompleted) // 終了通知
{
if (_jumpParameterList.Count > 0)
{
this.Play();
return;
}
else
{
_isNotifyAnimationCompleted = true;
this.AnimationCompleted?.Invoke();
}
}
if (_isRemoveComponentFinished)
{
Destroy(this);
}
_isRunning = false;
return;
}
_elapsed += Time.deltaTime;
this.UpdatePos();
}
//
// Public Methods
// - - - - - - - - - - - - - - - - - - - -
/// <summary>
/// 動作パラメータを追加します。
/// </summary>
private void addParam(float duration, Vector3 deltaPos, float height/*, int jumps*/)
{
_jumpParameterList.Add(new JumpByParameter(duration, deltaPos, height/*, jumps*/));
}
/// <summary>
/// 指定したオブジェクトに対し2D用の放物投射運動を即座に実行します。
/// </summary>
public static JumpBy Play(Transform target, float dulation, Vector3 deltaPos, float height, int jumps = 1)
{
GameObject root = target.gameObject;
if (!root)
{
Debug.LogWarning("無効なゲームオブジェクトのためアニメーション実行を中止しました。");
return null;
}
JumpBy jumpByComp = root.GetComponent<JumpBy>();
if (!jumpByComp)
{
jumpByComp = root.AddComponent<JumpBy>();
jumpByComp.Abort();
}
jumpByComp.addParam(dulation, deltaPos, height/*, jumps*/);
jumpByComp.Play();
return jumpByComp;
}
/// <summary>
/// 次のアニメーションを実行します。
/// </summary>
public void Play()
{
if (_jumpParameterList.Count == 0)
{
Debug.Log("パラメータが設定されていません。"); // 全部消費したときもこれ
return;
}
// 次の動作パラメータをフィールドに入れておく
_currentParan = _jumpParameterList[0];
_jumpParameterList.RemoveAt(0);
// 現在位置で初期化
_transform = this.transform;
_startLocalPos = _transform.GetLocalPos();
_elapsed = 0;
_isRunning = true;
this.UpdatePos();
}
/// <summary>
/// アニメーションを中止します。現在のパラメーターは全て破棄されます。
/// </summary>
public void Abort()
{
_isRunning = false;
_jumpParameterList.Clear();
}
/// <summary>
/// この動作が終了した後に連続で動作を行う場合に指定します。
/// by Fluent Interface Pattern
/// </summary>
public JumpBy AppendJumpBy(float dulation, float dx, float dy, float height/*, int jumps = 1*/)
=> this.AppendJumpBy(dulation, new Vector3(dx, dy), height/*, jumps*/);
public JumpBy AppendJumpBy(float dulation, float dx, float dy, float dz, float height/*, int jumps = 1*/)
=> this.AppendJumpBy(dulation, new Vector3(dx, dy, dz), height/*, jumps*/);
public JumpBy AppendJumpBy(float dulation, Vector3 deltaPos, float height/*, int jumps = 1*/)
{
this.addParam(dulation, deltaPos, height/*, jumps*/); // パラメーターは事前に積んでおく
return this;
}
//
// Other Methods
// - - - - - - - - - - - - - - - - - - - -
/// <summary>
/// 現在の経過時間 (<see cref="_elapsed"/>) に従ってオブジェクトの位置を更新します。
/// </summary>
protected virtual void UpdatePos()
{
Vector3 _s = this.StartLocalPos + _currentParan.CalcPos(_elapsed);
_transform.localPosition = _s;
}
}
}
//
// (c) 2020 Tapap.
// Licensed under MIT.
//
using UnityEngine;
namespace Takap.Utility
{
/// <summary>
/// <see cref="Utility.JumpBy"/> に関係する
/// </summary>
public static class JumpByExtension
{
/// <summary>
/// [2D用] <see cref="Transform"/> を拡張し <see cref="Utility.JumpBy"/> 動作をオブジェクトに直接指定します。
/// <para>各パラメーターの意味は <see cref="JumpBy.Play(Transform, float, Vector3, float, int)"/> と同等です。</para>
/// </summary>
public static JumpBy JumpBy(this Transform self, float dulation, float deltax,
float deltay, float height, int jumps = 1)
{
return JumpBy(self, dulation, new Vector3(deltax, deltay), height, jumps);
}
/// <summary>
/// <see cref="Transform"/> を拡張し <see cref="Utility.JumpBy"/> 動作をオブジェクトに直接指定します。
/// <para>各パラメーターの意味は <see cref="JumpBy.Play(Transform, float, Vector3, float, int)"/> と同等です。</para>
/// </summary>
public static JumpBy JumpBy(this Transform self, float dulation, Vector3 deltaPos,
float height, int jumps = 1)
{
return Utility.JumpBy.Play(self, dulation, deltaPos, height, jumps);
}
/// <summary>
/// <see cref="Transform"/> を拡張し <see cref="Utility.JumpBy"/> 動作をオブジェクトに直接指定します。
/// <para>各パラメーターの意味は <see cref="JumpBy.Play(Transform, float, Vector3, float, int)"/> と同等です。</para>
/// </summary>
public static JumpBy JumpBy(this Transform self, float dulation, float deltax,
float deltay, float deltaz, float height, int jumps = 1)
{
return JumpBy(self, dulation, new Vector3(deltax, deltay, deltaz), height, jumps);
}
}
}
//
// (c) 2020 Tapap.
// Licensed under MIT.
//
using System;
//using UniRx;
using UnityEngine;
namespace Takap.Utility
{
//
// 4回バウンドしたいとき
//
// Height = 75, X=50, Dulation=1
//
// transform.JumpBy(_dulation, _destPos, _height)
// .AppendJumpBy(_dulation * 0.5f, _destPos * 0.5f, _height * 0.5f)
// .AppendJumpBy(_dulation * 0.25f, _destPos * 0.25f, _height * 0.25f)
// .AppendJumpBy(_dulation * 0.1f, _destPos * 0.1f, _height * 0.1f);
//
// ジャンプパラメーター
[Serializable]
public class JumpByParameter
{
// 終了位置(相対)
[SerializeField] private Vector3 _deltaPos = default;
// 実行時間(秒)
[SerializeField] private float _duration = default;
// ジャンプの高さ
[SerializeField] private float _height = default;
//// ジャンプ回数(既定値は1回)
//[SerializeField] private int _jumps = 1;
/// <summary>
/// 相対的な移動完了位置を設定または取得します。
/// </summary>
public Vector3 DeltaPos { get => _deltaPos; set => _deltaPos = value; }
/// <summary>
/// 実行時間を設定または取得します。
/// </summary>
public float Duration { get => _duration; set => _duration = value; }
/// <summary>
/// ジャンプの高さを設定または取得します。
/// </summary>
public float Height { get => _height; set => _height = value; }
///// <summary>
///// ジャンプ回数を設定または取得します。
///// </summary>
//public int Jumps { get => _jumps; set => _jumps = value; }
public JumpByParameter() { }
public JumpByParameter(float duration, Vector3 deltaPos, float height/*, int jumps = 1*/)
{
_deltaPos = deltaPos;
_duration = duration;
_height = height;
//_jumps = jumps;
}
/// <summary>
/// 現在のオブジェクトの値を使って経過時間に応じた位置を計算します。
/// </summary>
public Vector3 CalcPos(float elapsed)
{
// 経過時間の割合(0%~100% -> 0.0~1.0)
float per = elapsed / _duration;
// 鉛直
//float frac = (per * _jumps) % 1.0f;
float frac = per;
float y = _height * 4.0f * frac * (1.0f - frac);
y += _deltaPos.y * per;
// 水平
float x = _deltaPos.x * per;
float z = _deltaPos.z * per;
return new Vector3(x, y, z);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment