HitStop実装

This commit is contained in:
kimura 2022-07-25 16:59:55 +09:00
parent 003bcf3b0f
commit 9af78cb3ac
3 changed files with 39 additions and 30 deletions

View File

@ -32,6 +32,7 @@ namespace MyGame.Scenes.MiniGame.Scripts
[SerializeField] private ResultManager resultManager; [SerializeField] private ResultManager resultManager;
[SerializeField] private GameObject readyObject; [SerializeField] private GameObject readyObject;
[SerializeField] private GameObject tutorialPopupObject; [SerializeField] private GameObject tutorialPopupObject;
[SerializeField] private float resultWaitTime = 1f;
#if UNITY_EDITOR #if UNITY_EDITOR
[SerializeField] private bool isDebug; [SerializeField] private bool isDebug;
#endif #endif
@ -214,6 +215,11 @@ namespace MyGame.Scenes.MiniGame.Scripts
player.SetSpeed(x); player.SetSpeed(x);
}).AddTo(this); }).AddTo(this);
player.OnEndHit.Subscribe(_ =>
{
state.Value = GameState.Success;
}).AddTo(this);
player.OnHitItem.Where(_ => state.Value == GameState.Play).Subscribe(x => player.OnHitItem.Where(_ => state.Value == GameState.Play).Subscribe(x =>
{ {
if (!x.TryGetComponent<StageItem>(out var item)) if (!x.TryGetComponent<StageItem>(out var item))
@ -264,11 +270,6 @@ namespace MyGame.Scenes.MiniGame.Scripts
} }
player.Hit(x.ClosestPoint(playerTransform.position)); player.Hit(x.ClosestPoint(playerTransform.position));
x.enabled = false; x.enabled = false;
// ゲーム終了
Observable.Timer(TimeSpan.FromSeconds(1f)).Subscribe(_ =>
{
state.Value = GameState.Success;
}).AddTo(this);
break; break;
case StageItem.Type.Item1: case StageItem.Type.Item1:
break; break;
@ -294,16 +295,13 @@ namespace MyGame.Scenes.MiniGame.Scripts
scoreCount.Value = 0; scoreCount.Value = 0;
resultManager.Reset(); resultManager.Reset();
gameCompositeDisposable.Clear(); gameCompositeDisposable.Clear();
state.SkipLatestValueOnSubscribe().Subscribe(x => state.SkipLatestValueOnSubscribe()
{ .First(x => x == GameState.Success)
if (x == GameState.Success) .SelectMany(Observable.Timer(TimeSpan.FromSeconds(resultWaitTime)))
.Subscribe(x =>
{ {
this.CallWaitForSeconds(1f, () => resultManager.ShowResult(scoreCount.Value, placeList, stageData);
{ }).AddTo(gameCompositeDisposable);
resultManager.ShowResult(scoreCount.Value, placeList, stageData);
});
}
}).AddTo(gameCompositeDisposable);
resultManager.OnRetry.ThrottleFirst(TimeSpan.FromSeconds(.2f)).Subscribe(_ => resultManager.OnRetry.ThrottleFirst(TimeSpan.FromSeconds(.2f)).Subscribe(_ =>
{ {

View File

@ -14,6 +14,7 @@ namespace MyGame.Scenes.MiniGame.Scripts
[SerializeField] private float hitJumpTime = 1f; [SerializeField] private float hitJumpTime = 1f;
[SerializeField] private float hitTime = 1.5f; [SerializeField] private float hitTime = 1.5f;
[SerializeField] private float hitWaitTime = 1f; [SerializeField] private float hitWaitTime = 1f;
[SerializeField] private float hitStopTime = 1f;
[SerializeField] private AnimationCurve jumpAnimationCurve; [SerializeField] private AnimationCurve jumpAnimationCurve;
[SerializeField] private AnimationCurve hitAnimationCurve; [SerializeField] private AnimationCurve hitAnimationCurve;
[SerializeField] private float flyingFallSpeed = 1f; [SerializeField] private float flyingFallSpeed = 1f;
@ -37,6 +38,7 @@ namespace MyGame.Scenes.MiniGame.Scripts
private bool isHole; private bool isHole;
private bool isWall; private bool isWall;
private bool isResult; private bool isResult;
private bool isHitStop;
private float currentFallSpeed; private float currentFallSpeed;
private float currentSpeedMultiply; private float currentSpeedMultiply;
public bool IsHit => isHit; public bool IsHit => isHit;
@ -46,12 +48,16 @@ namespace MyGame.Scenes.MiniGame.Scripts
private readonly ReactiveProperty<int> count = new ReactiveProperty<int>(); private readonly ReactiveProperty<int> count = new ReactiveProperty<int>();
public IObservable<Collider2D> OnHitItem => itemHitCollider.OnTriggerEnter2DAsObservable().TakeUntilDestroy(this); public IObservable<Collider2D> OnHitItem => itemHitCollider.OnTriggerEnter2DAsObservable().TakeUntilDestroy(this);
public IObservable<Collider2D> OnHitObstacle => obstacleHitCollider.OnTriggerEnter2DAsObservable().TakeUntilDestroy(this); public IObservable<Collider2D> OnHitObstacle => obstacleHitCollider.OnTriggerEnter2DAsObservable().TakeUntilDestroy(this);
private readonly Subject<Unit> endHitSubject = new();
public IObservable<Unit> OnEndHit => endHitSubject;
private void Start() private void Start()
{ {
count.AddTo(this); count.AddTo(this);
jumpCompositeDisposable.AddTo(this); jumpCompositeDisposable.AddTo(this);
hitCompositeDisposable.AddTo(this); hitCompositeDisposable.AddTo(this);
endHitSubject.AddTo(this);
animator = GetComponent<Animator>(); animator = GetComponent<Animator>();
basePos = transform.localPosition; basePos = transform.localPosition;
@ -74,6 +80,7 @@ namespace MyGame.Scenes.MiniGame.Scripts
isHole = false; isHole = false;
isWall = false; isWall = false;
isResult = false; isResult = false;
isHitStop = false;
currentSpeedMultiply = 1f; currentSpeedMultiply = 1f;
} }
@ -88,7 +95,7 @@ namespace MyGame.Scenes.MiniGame.Scripts
public void Move() public void Move()
{ {
if (isHitStay || isWall) if (isHitStay || isWall || isHitStop)
{ {
return; return;
} }
@ -192,18 +199,31 @@ namespace MyGame.Scenes.MiniGame.Scripts
} }
Instantiate(hitEffectPrefab, hitPos, Quaternion.identity, transform.parent); Instantiate(hitEffectPrefab, hitPos, Quaternion.identity, transform.parent);
animator?.Play("Brother_pink_FallDown", 0, 0f);
isHit = true; isHit = true;
isHitStop = true;
hitCompositeDisposable.Clear(); hitCompositeDisposable.Clear();
jumpCompositeDisposable.Clear(); jumpCompositeDisposable.Clear();
animator?.Play("Brother_pink_FallDown", 0, 0f);
animator.speed = 0f;
var hitStopTimer = Observable.Timer(TimeSpan.FromSeconds(hitStopTime)).Share();
hitStopTimer.Subscribe(_ =>
{
isHitStop = false;
animator.speed = currentSpeedMultiply;
}).AddTo(hitCompositeDisposable);
var cachePosY = transform.localPosition.y; var cachePosY = transform.localPosition.y;
var diffHeight = cachePosY - basePos.y; var diffHeight = cachePosY - basePos.y;
var groundPos = isHole ? cachePosY : basePos.y; var groundPos = isHole ? cachePosY : basePos.y;
var hitJumpCoroutine = MonoBehaviourExtensions.DoCallLerp(diffHeight <= 0f ? 0f : hitJumpTime, t => var hitJumpCoroutine = MonoBehaviourExtensions.DoCallLerp(diffHeight <= 0f ? 0f : hitJumpTime / currentSpeedMultiply, t =>
{ {
transform.SetLocalPositionY(cachePosY + hitAnimationCurve.Evaluate(t)); transform.SetLocalPositionY(cachePosY + hitAnimationCurve.Evaluate(t));
}); });
Observable.FromCoroutine(_ => hitJumpCoroutine).Subscribe(_ =>
// HitStop後、Hit跳ね返りアニメーション
hitStopTimer.SelectMany(hitJumpCoroutine).Subscribe(_ =>
{ {
// 落下時間不定によりアニメ再生停止 // 落下時間不定によりアニメ再生停止
animator.speed = 0f; animator.speed = 0f;
@ -217,12 +237,12 @@ namespace MyGame.Scenes.MiniGame.Scripts
currentFallSpeed = 0f; currentFallSpeed = 0f;
isJump = false; isJump = false;
isFall = false; isFall = false;
Observable.Timer(TimeSpan.FromSeconds(hitTime)).Subscribe(_ => { }, () => Observable.Timer(TimeSpan.FromSeconds(hitTime / currentSpeedMultiply)).Subscribe(_ => { }, () =>
{ {
isHitStay = true; isHitStay = true;
Observable.Timer(TimeSpan.FromSeconds(hitWaitTime)).Subscribe(_ => { }, () => Observable.Timer(TimeSpan.FromSeconds(hitWaitTime)).Subscribe(_ => { }, () =>
{ {
// 入れ子対策するならコルーチンにして工程ごとに分けてSelectManyするのがよい。 endHitSubject.OnNext(Unit.Default);
isHit = false; isHit = false;
isHitStay = false; isHitStay = false;
if (isResult) if (isResult)

View File

@ -29,15 +29,6 @@ namespace MyGame.Scenes.MiniGame.Scripts
fenceSubject.AddTo(this); fenceSubject.AddTo(this);
difficulty.AddTo(this); difficulty.AddTo(this);
} }
/*
*
* CurrentDifficulteyが切り替わると生成コース変更
* 3調
* Difficultyでゲームスピード切り替え
* deltaTimeを倍にする
* deltaTime以外の影響はプレイヤーのAnimatorのSpeed()
*/
public void SetBeginStages(Transform[] newStages) public void SetBeginStages(Transform[] newStages)
{ {