209 lines
7.6 KiB
C#
209 lines
7.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using Code.Game.OfficeGame.BattleMode;
|
|
using Code.Infrastructure.Camera;
|
|
using Code.OfficeGame.BattleMode.Actions;
|
|
using Code.OfficeGame.BattleMode.Actions.Deciders;
|
|
using Code.OfficeGame.BattleMode.UI;
|
|
using Cysharp.Threading.Tasks;
|
|
using R3;
|
|
using UnityEngine;
|
|
|
|
namespace Code.OfficeGame.BattleMode.Timeline
|
|
{
|
|
public class BattleTimeline
|
|
{
|
|
public const int TicksPerSecond = 60;
|
|
public const float TickDelta = 1f / TicksPerSecond;
|
|
|
|
private readonly ReactiveProperty<int> _currentBattleFrame = new(0);
|
|
public ReadOnlyReactiveProperty<int> CurrentBattleFrame => _currentBattleFrame;
|
|
|
|
private readonly BattleTimelinePanel _timelinePanel;
|
|
private List<EntityProperties> _entities;
|
|
private DisposableBag _battleSubscriptions;
|
|
|
|
private Dictionary<BattleActionType, BattleAction> _battleActions;
|
|
private Dictionary<DeciderType, BattleActionDecider> _battleActionDeciders;
|
|
|
|
private Dictionary<EntityId, BattleActionDecisionResult> _actionDecisionResults = new();
|
|
private Dictionary<EntityId, BattleActionData> _battleActionDatas = new();
|
|
private BattleActionDecisionPanel _battleActionDecisionPanel;
|
|
private CameraStateMachine _cameraStateMachine;
|
|
|
|
public BattleTimeline(
|
|
BattleTimelinePanel timelinePanel,
|
|
IEnumerable<BattleAction> battleActions,
|
|
IEnumerable<BattleActionDecider> battleActionDeciders,
|
|
BattleActionDecisionPanel battleActionDecisionPanel,
|
|
CameraStateMachine cameraStateMachine)
|
|
{
|
|
_cameraStateMachine = cameraStateMachine;
|
|
_battleActionDecisionPanel = battleActionDecisionPanel;
|
|
_timelinePanel = timelinePanel;
|
|
_battleActions = battleActions.ToDictionary(x=>x.ActionType);
|
|
_battleActionDeciders = battleActionDeciders.ToDictionary(x => x.DeciderType);
|
|
}
|
|
public async UniTask RunBattleLoopAsync(List<EntityProperties> entities, CancellationToken ctx)
|
|
{
|
|
_entities = entities;
|
|
_currentBattleFrame.Value = 0;
|
|
|
|
_battleSubscriptions = new DisposableBag();
|
|
|
|
try
|
|
{
|
|
_currentBattleFrame
|
|
.Subscribe(_timelinePanel.OnFrameTick)
|
|
.AddTo(ref _battleSubscriptions);
|
|
|
|
// foreach (var entity in entities)
|
|
// entity.OnActionSet
|
|
// .Subscribe(action =>
|
|
// {
|
|
// action.Frame += _currentBattleFrame.Value;
|
|
// _timelinePanel.SetAction(action);
|
|
// })
|
|
// .AddTo(ref _battleSubscriptions);
|
|
|
|
await DecideActions(_entities, ctx);
|
|
|
|
while (!ctx.IsCancellationRequested)
|
|
{
|
|
List<EntityProperties> entitiesNeedOrders = await PlayTimelineUntilPause(ctx);
|
|
|
|
await DecideActions(entitiesNeedOrders, ctx);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_battleSubscriptions.Dispose();
|
|
}
|
|
}
|
|
|
|
private async UniTask DecideActions(List<EntityProperties> entities, CancellationToken ctx)
|
|
{
|
|
foreach (var entity in entities)
|
|
{
|
|
Debug.Log($"Deciding action for {entity.name}");
|
|
|
|
var entityId = entity.GetEntityId();
|
|
|
|
_actionDecisionResults.Remove(entityId);
|
|
|
|
_actionDecisionResults[entityId] = await DecideAction(ctx, entity);
|
|
|
|
_battleActionDatas.Remove(entityId);
|
|
|
|
var decidedAction = _actionDecisionResults[entityId];
|
|
|
|
_battleActionDatas[entityId] =
|
|
_battleActions[decidedAction.ActionType]
|
|
.MountAndGetFrames(entity, decidedAction);
|
|
}
|
|
}
|
|
|
|
private async UniTask<List<EntityProperties>> PlayTimelineUntilPause(CancellationToken ctx)
|
|
{
|
|
float accumulator = 0f;
|
|
var readyEntities = new List<EntityProperties>();
|
|
|
|
while (readyEntities.Count == 0 && !ctx.IsCancellationRequested)
|
|
{
|
|
await UniTask.Yield(PlayerLoopTiming.Update, ctx);
|
|
|
|
accumulator += Time.unscaledDeltaTime;
|
|
|
|
while (accumulator >= TickDelta)
|
|
{
|
|
accumulator -= TickDelta;
|
|
SimulateSingleFrame(readyEntities);
|
|
|
|
if (readyEntities.Count > 0) return readyEntities;
|
|
}
|
|
}
|
|
|
|
return readyEntities;
|
|
}
|
|
|
|
private void SimulateSingleFrame(List<EntityProperties> outReadyEntities)
|
|
{
|
|
_currentBattleFrame.Value++;
|
|
|
|
foreach (var entity in _entities)
|
|
{
|
|
var entityId = entity.GetEntityId();
|
|
|
|
var finished = _battleActions[_actionDecisionResults[entityId].ActionType]
|
|
.Tick(
|
|
TickDelta,
|
|
entity,
|
|
_actionDecisionResults[entityId],
|
|
_battleActionDatas[entityId]);
|
|
|
|
entity.animator.Update(TickDelta);
|
|
|
|
if (finished)
|
|
{
|
|
outReadyEntities.Add(entity);
|
|
}
|
|
}
|
|
|
|
Physics.Simulate(TickDelta);
|
|
Physics.SyncTransforms();
|
|
}
|
|
|
|
private async UniTask<BattleActionDecisionResult> DecideAction(CancellationToken ctx, EntityProperties entity)
|
|
{
|
|
_battleActionDecisionPanel.SetEntityInfo(entity.battleActionTypes);
|
|
|
|
BattleActionType decidedAction = BattleActionType.None;
|
|
|
|
BattleActionDecisionResult decision = null;
|
|
|
|
while (decidedAction == BattleActionType.None || ctx.IsCancellationRequested)
|
|
{
|
|
Cursor.lockState = CursorLockMode.Confined;
|
|
|
|
((CameraBattleModeState)_cameraStateMachine.CurrentBaseState).battleDeciding = true;
|
|
|
|
await _battleActionDecisionPanel.Open(ctx);
|
|
|
|
decidedAction = await _battleActionDecisionPanel.GetDecision(ctx);
|
|
|
|
if (decidedAction == BattleActionType.None) continue;
|
|
|
|
var deciderType = _battleActions[decidedAction].DeciderType;
|
|
|
|
_battleActionDeciders[deciderType].MountDecider();
|
|
|
|
while (!ctx.IsCancellationRequested)
|
|
{
|
|
Cursor.lockState = CursorLockMode.Locked;
|
|
|
|
((CameraBattleModeState)_cameraStateMachine.CurrentBaseState).battleDeciding = false;
|
|
|
|
await _battleActionDecisionPanel.Close(ctx);
|
|
|
|
decision = await _battleActionDeciders[deciderType].GetDecision();
|
|
|
|
if (decision.ResultCode == BattleActionDecisionResultCode.CancelDecision)
|
|
decidedAction = BattleActionType.None;
|
|
|
|
if (decision.ResultCode != BattleActionDecisionResultCode.Deciding)
|
|
break;
|
|
}
|
|
|
|
_battleActionDeciders[deciderType].UnmountDecider();
|
|
}
|
|
|
|
if (decision == null) throw new ArgumentNullException(nameof(decision));
|
|
|
|
decision.ActionType = decidedAction;
|
|
|
|
return decision;
|
|
}
|
|
}
|
|
} |