using System; using System.Collections; using System.Linq; using AibisDream.FixSystem; using AibisDream.Framework; using AibisDream.Kit; using AibisDream.Utility; using DG.Tweening; using UnityEngine; using UnityEngine.Serialization; namespace AibisDream { public class EngineSystem : SystemHasData { public static string DataPath = Application.streamingAssetsPath + "/LevelData/EngineSystem/"; private SpriteRenderer _cover; [Header("系统配置")] [SerializeField] public EngineConfig config; [Header("系统数据")] [SerializeField] private EngineData engineData; [FormerlySerializedAs("盖板移动时间")] [SerializeField] private float coverMoveDuration = 5f; [FormerlySerializedAs("盖板移动距离")] [SerializeField] private float coverMoveDistance = 2.8f; private bool IsValid => engineData.isValid.Value; public event Action UpdateDashboard; private void Awake() { FixSystemCenter.SystemDic.Register(this); _cover = transform.Find("Cover").GetComponent(); } private void OnEnable() { engineData = new EngineData(config.invalidTime); DialogController.Instance?.SetVariable("$curAirLevel", 2); } private void Update() { // 更新部分按时间自然计算的指标 DataAutoChange(); // 更新看板 UpdateDashboard?.Invoke(engineData); } private void DataAutoChange() { // 自然减速 engineData.OilChange(-config.oilDownRatio); engineData.CalcAir(config.airMaxRatio, config.airMinRatio, config.baseAirMax); // 推算速度 engineData.CalcSpeed(config.acceleratedSpeed, config.resistance); // 判断是否成功 if (engineData.CheckSuccess(config.targetSpeed)) { DialogController.Instance?.StartDialogNode("EngineSuccess"); } } /// /// 加速过程 /// public void AddOil() { if (IsValid) { engineData.OilChange(config.oilUpRatio); } // 失效期无法加油门 } /// /// 更新引擎气门变化 /// /// 当前气门等级 public void UpdateAirLevel(int curLevel) { engineData.UpdateAirLevel(curLevel, config.maxLevel); DialogController.Instance.SetVariable("$curAirLevel", curLevel + 1); DialogController.Instance.StartDialogNode("调整进气档位"); } /// /// 打开盖板 /// /// 动画序列 public Tween OpenCover() { var sq = DOTween.Sequence(); // 盖板上移 var moveDis = new Vector3(0, coverMoveDistance, 0); sq.Join(_cover.transform.DOBlendableMoveBy(moveDis, coverMoveDuration)); // 盖板淡出 sq.Join(_cover.DOFade(0, coverMoveDuration)); // 为引擎系统解锁 sq.OnComplete(Unlock); return sq; } public IEnumerator OpenCoverAsync() { var sq = OpenCover(); if (sq.active && !sq.IsComplete()) { yield return null; } } /// /// 关闭盖板 /// /// 动画序列 public Tween CloseCover() { var sq = DOTween.Sequence(); sq.Join(_cover.DOFade(1, coverMoveDuration)); var moveDis = new Vector3(0, -coverMoveDistance, 0); sq.Join(_cover.transform.DOBlendableMoveBy(moveDis, coverMoveDuration)); // 锁定引擎系统 sq.OnComplete(Lock); return sq; } public IEnumerator CloseCoverAsync() { var sq = CloseCover(); if (sq.active && !sq.IsComplete()) { yield return null; } } public void Lock() { // 禁止油门和气门 } public void Unlock() { // 开启油门和气门 } #region 数据加载与保存 private string[] _keyOptions; public override string CurDataKey { get; set; } public override string[] GetDataKeyOptions() { return _keyOptions ??= ConfigUtil.Instance.GetFileNames(DataPath); } public override void Load() { if (string.IsNullOrEmpty(CurDataKey)) { Debug.Log("配置项名称为空"); return; } if (!ConfigUtil.Instance.TryLoadConfig(DataPath + CurDataKey, out var data)) { Debug.Log("没有找到配置项"); return; } config = data; // 重置Data OnEnable(); } public override void Save() { if (string.IsNullOrEmpty(CurDataKey)) { Debug.Log("名称不为空"); return; } ConfigUtil.Instance.SaveConfig(config, DataPath + CurDataKey); if (!_keyOptions.Contains(CurDataKey)) { // 重新读取key _keyOptions = ConfigUtil.Instance.GetFileNames(DataPath); } } #endregion } [Serializable] public struct EngineConfig { public float oilDownRatio; public float oilUpRatio; public float acceleratedSpeed; public float resistance; public float airMaxRatio; public float airMinRatio; public float baseAirMax; public int maxLevel; public float targetSpeed; public float invalidTime; } [Serializable] public struct EngineData { private const float SuccessDuration = 1.5f; public float curSpeed; public float curOil; public float curAir; public float curAirMin; public float curAirMax; public int curAirLevel; public AutoFlipBool isValid; public bool inAirRange; public float reachTargetTime; public bool isSuccess; public EngineData(float flipDelayTime) { isValid = new AutoFlipBool(flipDelayTime, true); curSpeed = 0; curOil = 0; curAir = 0; curAirMin = 0; curAirMax = 0; curAirLevel = 0; inAirRange = false; reachTargetTime = 0; isSuccess = false; } public void OilChange(float oilChangeRatio) { curOil = CommonUtil.Limit(curOil + oilChangeRatio * Time.deltaTime, 1f, 0f); } public void CalcSpeed(float acceleratedSpeed, float resistance) { var addNum = inAirRange && isValid.Value ? (curOil * acceleratedSpeed - curSpeed * resistance) * Time.deltaTime : -curSpeed * resistance * Time.deltaTime; curSpeed = CommonUtil.Limit(curSpeed + addNum, 1f, 0f); } public void CalcAir(float airMaxRatio, float airMinRatio, float baseAirMax) { curAirMax = CommonUtil.Limit(curSpeed * (curAirLevel + 1) * airMaxRatio + baseAirMax, 1f, 0f); curAirMin = CommonUtil.Limit(curSpeed * (curAirLevel + 1) * airMinRatio, 0.8f, 0f); curAir = curOil; // 如果离开范围且当前在系统有效期,就进入一段失效期 var curInAirRange = curAir <= curAirMax && curAir >= curAirMin; if (inAirRange && !curInAirRange && !isSuccess) { // 出界的话 if (curAir > curAirMax) DialogController.Instance.StartDialogNode("引擎过速"); if (curAir < curAirMin) DialogController.Instance.StartDialogNode("引擎掉速"); isValid.Value = false; } inAirRange = curInAirRange; } public void UpdateAirLevel(int level, int maxLevel) { curAirLevel = level; if (curAirLevel > maxLevel) { curAirLevel = maxLevel - 1; } if (curAirLevel < 0) { curAirLevel = 0; } } public bool CheckSuccess(float targetSpeed) { // 已经成功就不用校验了 if (isSuccess) return false; if (curSpeed >= targetSpeed) { reachTargetTime += Time.deltaTime; } else { reachTargetTime = 0; } // 如果速度达标时间足够就判断成功 if (!(reachTargetTime >= SuccessDuration)) return false; isSuccess = true; return true; } } }