后处理+FEEL完全改进
This commit is contained in:
@@ -10,11 +10,14 @@ using SLSFramework.LeanPoolAssistance;
|
||||
using SLSFramework.WwiseAssistance;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public abstract partial class AttackAreaBase : MonoBehaviour
|
||||
{
|
||||
private static Dictionary<string, int> areaNameCountDictionary = new Dictionary<string, int>();
|
||||
|
||||
[Title("References")]
|
||||
public CharacterBase creator;
|
||||
public ItemBase itemSource;
|
||||
@@ -25,6 +28,7 @@ namespace Cielonos.MainGame
|
||||
public Dictionary<string, GameObject> functionalParts;
|
||||
|
||||
[Title("Status")]
|
||||
public string areaName;
|
||||
public bool isEnabling;
|
||||
public bool canTriggerHitEvent = true;
|
||||
public Action updateAction;
|
||||
@@ -79,6 +83,12 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
topParent = topParent.parent;
|
||||
}
|
||||
|
||||
if (!areaNameCountDictionary.TryAdd(topParent.name, 1))
|
||||
{
|
||||
areaNameCountDictionary[topParent.name]++;
|
||||
}
|
||||
areaName = $"{topParent.name}_{areaNameCountDictionary[topParent.name]}";
|
||||
|
||||
foreach (TrailRenderer trail in GetComponentsInChildren<TrailRenderer>())
|
||||
{
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
public bool isOverridingHitEffect;
|
||||
public GameObject hitVFXPrefab;
|
||||
public GameObject damageNumberRegularPrefab;
|
||||
public GameObject damageNumberCriticalPrefab;
|
||||
public DamageNumber damageNumberRegularPrefab;
|
||||
public DamageNumber damageNumberCriticalPrefab;
|
||||
|
||||
public AttackValue originalAttackValue;
|
||||
public AttackValue modifiedAttackValue;
|
||||
@@ -45,9 +45,9 @@ namespace Cielonos.MainGame
|
||||
|
||||
public void SpawnDamageNumber(Vector3 position, bool isCritical, float finalDamage)
|
||||
{
|
||||
GameObject damageNumberGameObject = isCritical ? damageNumberCriticalPrefab : damageNumberRegularPrefab;
|
||||
DamageNumber damageNumber = Object.Instantiate(damageNumberGameObject, position, Quaternion.identity).GetComponent<DamageNumber>();
|
||||
damageNumber.number = finalDamage;
|
||||
DamageNumber finalDN = isCritical ? damageNumberCriticalPrefab : damageNumberRegularPrefab;
|
||||
DamageNumber damageNumber = finalDN.Spawn(position, finalDamage);
|
||||
damageNumber.spamGroup = attackArea.areaName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,16 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
public partial class HitSubmodule : AttackAreaSubmoduleBase
|
||||
{
|
||||
public int hitCount;
|
||||
public int originalHitCount;
|
||||
public int currentHitIndex;
|
||||
public float hitInterval;
|
||||
private float currentIntervalTime;
|
||||
|
||||
public List<GameObject> checkedObjects;
|
||||
public bool isAutoPlayHitSound;
|
||||
public List<string> hitSoundList;
|
||||
public List<Action<CharacterBase, Vector3>> hitEventList;
|
||||
public List<Action<CharacterBase, Vector3>> generalHitEventList;
|
||||
public SortedList<int, Action<CharacterBase, Vector3>> specificHitEventList;
|
||||
|
||||
public HitSubmodule(AttackAreaBase attackArea) : base(attackArea)
|
||||
{
|
||||
@@ -30,15 +32,17 @@ namespace Cielonos.MainGame
|
||||
}
|
||||
|
||||
private void InitializeAsOnceHit()
|
||||
{
|
||||
this.hitCount = 1;
|
||||
{
|
||||
this.originalHitCount = 1;
|
||||
this.currentHitIndex = 0;
|
||||
this.hitInterval = -1;
|
||||
this.currentIntervalTime = 0;
|
||||
}
|
||||
|
||||
private void InitializeAsMultipleHit(float hitInterval, int hitCount)
|
||||
{
|
||||
this.hitCount = hitCount;
|
||||
this.originalHitCount = hitCount;
|
||||
this.currentHitIndex = 0;
|
||||
this.hitInterval = hitInterval;
|
||||
this.currentIntervalTime = 0;
|
||||
}
|
||||
@@ -48,7 +52,8 @@ namespace Cielonos.MainGame
|
||||
isAutoPlayHitSound = true;
|
||||
checkedObjects = new List<GameObject>();
|
||||
hitSoundList = new List<string>();
|
||||
hitEventList = new List<Action<CharacterBase, Vector3>>();
|
||||
generalHitEventList = new List<Action<CharacterBase, Vector3>>();
|
||||
specificHitEventList = new SortedList<int, Action<CharacterBase, Vector3>>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +83,16 @@ namespace Cielonos.MainGame
|
||||
|
||||
public HitSubmodule AddHitEvent(Action<CharacterBase, Vector3> hitEvent)
|
||||
{
|
||||
hitEventList.Add(hitEvent);
|
||||
generalHitEventList.Add(hitEvent);
|
||||
return this;
|
||||
}
|
||||
|
||||
public HitSubmodule AddHitEvent(Action<CharacterBase, Vector3> hitEvent, params int[] indexes)
|
||||
{
|
||||
foreach (int i in indexes)
|
||||
{
|
||||
specificHitEventList[i] = hitEvent;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -87,7 +101,7 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
public void Update()
|
||||
{
|
||||
if (!isEnabling || hitCount <= 1 || attackArea.timeSm.delayTime > 0)
|
||||
if (!isEnabling || currentHitIndex >= originalHitCount - 1 || attackArea.timeSm.delayTime > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -101,10 +115,10 @@ namespace Cielonos.MainGame
|
||||
//attackArea.attackSm.modifiedAttackValue = attackArea.attackSm.originalAttackValue;
|
||||
}
|
||||
currentIntervalTime -= hitInterval;
|
||||
hitCount--;
|
||||
currentHitIndex++;
|
||||
}
|
||||
|
||||
if (hitCount <= 0)
|
||||
if (currentHitIndex >= originalHitCount - 1)
|
||||
{
|
||||
attackArea.isEnabling = false;
|
||||
}
|
||||
@@ -126,10 +140,16 @@ namespace Cielonos.MainGame
|
||||
{
|
||||
if (attackArea.canTriggerHitEvent)
|
||||
{
|
||||
foreach (Action<CharacterBase, Vector3> hitEvent in hitEventList)
|
||||
foreach (Action<CharacterBase, Vector3> hitEvent in generalHitEventList)
|
||||
{
|
||||
hitEvent.Invoke(target, hitPosition);
|
||||
}
|
||||
|
||||
Debug.Log($"[HitSubmodule] Invoking specific hit event for hit index {currentHitIndex}.");
|
||||
if (specificHitEventList.ContainsKey(currentHitIndex))
|
||||
{
|
||||
specificHitEventList[currentHitIndex].Invoke(target, hitPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Sirenix.OdinInspector;
|
||||
using SLSFramework.General;
|
||||
using SLSFramework.WwiseAssistance;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using UniRx;
|
||||
@@ -220,4 +221,24 @@ namespace Cielonos.MainGame.Characters
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class CharacterBase
|
||||
{
|
||||
public Vector2 GetNormalizedScreenPosition(Camera cam = null)
|
||||
{
|
||||
if (this is Player player)
|
||||
{
|
||||
cam ??= player.viewSc.playerCamera;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cam == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(cam), "Camera must be provided for non-player characters.");
|
||||
}
|
||||
}
|
||||
|
||||
return SpaceConverter.WorldPointToNormalizedScreenPoint(flexibleCenterPoint.position, cam);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace Cielonos.MainGame.Characters
|
||||
|
||||
private void BoneShakeLateUpdate()
|
||||
{
|
||||
float dt = Time.deltaTime;
|
||||
float dt = owner.selfTimeSm.DeltaTime;
|
||||
|
||||
for (int i = activeShakes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -267,7 +267,7 @@ namespace Cielonos.MainGame.Characters
|
||||
}
|
||||
else
|
||||
{
|
||||
animator.CrossFade("Empty", 0f, fullBodyActionIndex, 0);
|
||||
animator.CrossFade("Empty", 0.1f, fullBodyActionIndex, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
foreach (var feedbackUnit in feedbacks.Values)
|
||||
{
|
||||
float timeScaleMultiplier = owner.selfTimeSm.TimeScale;
|
||||
feedbackUnit.feedback.ExternalTimeScale = timeScaleMultiplier;
|
||||
feedbackUnit.Update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,9 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
sourceItem.audioContainer.PlaySoundFX("PerfectBlock");
|
||||
sourceItem.feedbackSc["PerfectBlock"]?.Play();
|
||||
sourceItem.blockData.InstantiateBlockEffect(perfectEffectName, blockEffectPosition, Quaternion.identity);
|
||||
GameObject pObj = sourceItem.blockData.InstantiateBlockEffect(perfectEffectName, sourceCharacter, blockEffectPosition, Quaternion.identity);
|
||||
pObj.GetComponent<ParticleSystem>().Simulate(0.1f, true, true);
|
||||
pObj.GetComponent<ParticleSystem>().Play();//TODO: 增加起点时间参数
|
||||
}
|
||||
|
||||
onPerfectBlock?.Invoke(attackArea);
|
||||
@@ -153,7 +155,7 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
sourceItem.audioContainer.PlaySoundFX("NormalBlock");
|
||||
sourceItem.feedbackSc["NormalBlock"]?.Play();
|
||||
sourceItem.blockData.InstantiateBlockEffect(normalEffectName, blockEffectPosition, Quaternion.identity);
|
||||
sourceItem.blockData.InstantiateBlockEffect(normalEffectName, sourceCharacter, blockEffectPosition, Quaternion.identity);
|
||||
}
|
||||
|
||||
onNormalBlock?.Invoke(attackArea);
|
||||
|
||||
@@ -142,23 +142,23 @@ namespace Cielonos.MainGame.Characters
|
||||
|
||||
public void PerfectDodge()
|
||||
{
|
||||
onPerfectDodge?.Invoke();
|
||||
|
||||
if (sourceItem == null)
|
||||
{
|
||||
sourceCharacter.feedbackSc["PerfectDodge"].Play();
|
||||
Debug.Log("Perfect Dodge!");
|
||||
}
|
||||
|
||||
onPerfectDodge?.Invoke();
|
||||
}
|
||||
|
||||
public void NormalDodge()
|
||||
{
|
||||
onNormalDodge?.Invoke();
|
||||
|
||||
if (sourceItem == null)
|
||||
{
|
||||
sourceCharacter.feedbackSc["NormalDodge"].Play();
|
||||
}
|
||||
|
||||
onNormalDodge?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,11 @@ namespace Cielonos.MainGame.Characters
|
||||
|
||||
foreach (Material mat in baseRenderMaterials)
|
||||
{
|
||||
if (!mat.HasProperty("_RimParams"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Tweener rimTween = mat.DOVector(new Vector4(1, 1, 4, 1), "_RimParams", 0.5f)
|
||||
.From(new Vector4(0, 1, 4, 1))
|
||||
.OnPlay(() =>
|
||||
@@ -152,33 +157,6 @@ namespace Cielonos.MainGame.Characters
|
||||
}
|
||||
|
||||
getHitBlinkTween.Play();
|
||||
|
||||
/*getHitBlinkTween.OnPlay(() =>
|
||||
{
|
||||
effectContainers["GetHitBlink"].SetActive(true);
|
||||
});
|
||||
|
||||
foreach (Material mat in effectRenderMaterials["GetHitBlink"])
|
||||
{
|
||||
TweenerCore<Color, Color, ColorOptions> matTween = mat.DOColor(Color.white * 0.5f, "_EmissionColor", 0.05f)
|
||||
.OnStart(() => mat.EnableKeyword("_EMISSION"))
|
||||
.From(Color.black)
|
||||
.SetEase(Ease.OutQuad)
|
||||
.OnComplete(() =>
|
||||
{
|
||||
mat.SetColor("_EmissionColor", Color.black);
|
||||
mat.DisableKeyword("_EMISSION");
|
||||
});
|
||||
getHitBlinkTween.Join(matTween);
|
||||
}
|
||||
|
||||
getHitBlinkTween.SetLoops(2, LoopType.Yoyo);
|
||||
getHitBlinkTween.OnComplete(() =>
|
||||
{
|
||||
effectContainers["GetHitBlink"].SetActive(false);
|
||||
});*/
|
||||
|
||||
getHitBlinkTween.Play();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,107 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
using SLSFramework.General;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
public partial class SelfTimeSubmodule : SubmoduleBase<CharacterBase>
|
||||
{
|
||||
public FloatReactiveProperty timeScaleCoefficient;
|
||||
public float TimeScale => timeScaleCoefficient.Value * Time.timeScale;
|
||||
public float DeltaTime => timeScaleCoefficient.Value * Time.deltaTime;
|
||||
private TimeManager timeManager => TimeManager.Instance;
|
||||
private IObservable<float> timeScaleObservable;
|
||||
|
||||
public FloatReactiveProperty localTimeScale;
|
||||
private float globalTimeScale => timeManager.globalTimeScale.Value;
|
||||
private float playerTimeScale => timeManager.playerTimeScale.Value;
|
||||
private float alliedMinionTimeScale => timeManager.alliedMinionTimeScale.Value;
|
||||
private float enemyTimeScale => timeManager.enemyTimeScale.Value;
|
||||
private float nonPlayerTimeScale => timeManager.nonPlayerTimeScale.Value;
|
||||
|
||||
|
||||
public float TimeScale => owner.fraction switch
|
||||
{
|
||||
Fraction.Player => localTimeScale.Value * globalTimeScale * playerTimeScale,
|
||||
Fraction.AlliedMinion => localTimeScale.Value * globalTimeScale * alliedMinionTimeScale * nonPlayerTimeScale,
|
||||
Fraction.Enemy => localTimeScale.Value * globalTimeScale * enemyTimeScale * nonPlayerTimeScale,
|
||||
Fraction.Neutral => localTimeScale.Value * globalTimeScale * nonPlayerTimeScale,
|
||||
_ => localTimeScale.Value * globalTimeScale
|
||||
};
|
||||
|
||||
public float DeltaTime => owner.fraction switch
|
||||
{
|
||||
Fraction.Player => Time.deltaTime * localTimeScale.Value * globalTimeScale * playerTimeScale,
|
||||
Fraction.AlliedMinion => Time.deltaTime * localTimeScale.Value * globalTimeScale * alliedMinionTimeScale * nonPlayerTimeScale,
|
||||
Fraction.Enemy => Time.deltaTime * localTimeScale.Value * globalTimeScale * enemyTimeScale * nonPlayerTimeScale,
|
||||
Fraction.Neutral => Time.deltaTime * localTimeScale.Value * globalTimeScale * nonPlayerTimeScale,
|
||||
_ => Time.deltaTime * localTimeScale.Value * globalTimeScale
|
||||
};
|
||||
|
||||
public SelfTimeSubmodule(CharacterBase entity) : base(entity)
|
||||
{
|
||||
timeScaleCoefficient = new FloatReactiveProperty(1);
|
||||
localTimeScale = new FloatReactiveProperty(1);
|
||||
|
||||
switch (owner.fraction)
|
||||
{
|
||||
case Fraction.Player:
|
||||
// 依赖: local, global, player
|
||||
timeScaleObservable =
|
||||
localTimeScale.CombineLatest(
|
||||
timeManager.globalTimeScale,
|
||||
timeManager.playerTimeScale,
|
||||
(local, global, player) => local * global * player
|
||||
);
|
||||
break;
|
||||
|
||||
case Fraction.AlliedMinion:
|
||||
// 依赖: local, global, alliedMinion, nonPlayer
|
||||
timeScaleObservable =
|
||||
localTimeScale.CombineLatest(
|
||||
timeManager.globalTimeScale,
|
||||
timeManager.alliedMinionTimeScale,
|
||||
timeManager.nonPlayerTimeScale,
|
||||
(local, global, minion, nonPlayer) => local * global * minion * nonPlayer
|
||||
);
|
||||
break;
|
||||
|
||||
case Fraction.Enemy:
|
||||
// 依赖: local, global, enemy, nonPlayer
|
||||
timeScaleObservable =
|
||||
localTimeScale.CombineLatest(
|
||||
timeManager.globalTimeScale,
|
||||
timeManager.enemyTimeScale,
|
||||
timeManager.nonPlayerTimeScale,
|
||||
(local, global, enemy, nonPlayer) => local * global * enemy * nonPlayer
|
||||
);
|
||||
break;
|
||||
|
||||
case Fraction.Neutral:
|
||||
// 依赖: local, global, nonPlayer
|
||||
timeScaleObservable =
|
||||
localTimeScale.CombineLatest(
|
||||
timeManager.globalTimeScale,
|
||||
timeManager.nonPlayerTimeScale,
|
||||
(local, global, nonPlayer) => local * global * nonPlayer
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
|
||||
if (entity.animationSc != null)
|
||||
{
|
||||
timeScaleCoefficient.Subscribe(x =>
|
||||
timeScaleObservable.Subscribe(timeScale =>
|
||||
{
|
||||
entity.animationSc.fullBodyFuncAnimSm.currentPlaySpeedMultiplier = x;
|
||||
entity.animationSc.fullBodyFuncAnimSm.currentPlaySpeedMultiplier = timeScale;
|
||||
});
|
||||
}
|
||||
|
||||
if (entity.animationSc.animator != null)
|
||||
{
|
||||
timeScaleCoefficient.Subscribe(x =>
|
||||
timeScaleObservable.Subscribe(timeScale =>
|
||||
{
|
||||
entity.animationSc.animator.speed = x;
|
||||
entity.animationSc.animator.speed = timeScale;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -59,6 +131,26 @@ namespace Cielonos.MainGame.Characters
|
||||
() => onComplete?.Invoke() // 4. 流结束时(TakeWhile 返回 false)执行 Action
|
||||
).AddTo(owner); // 5. 绑定生命周期到角色,防止内存泄漏
|
||||
}
|
||||
|
||||
public IDisposable AddGlobalTimer(float duration, Action onComplete, Action onUpdate = null)
|
||||
{
|
||||
// 用于记录累积时间
|
||||
float accumulatedTime = 0f;
|
||||
|
||||
return Observable.EveryUpdate()
|
||||
.Select(_ => Time.deltaTime) // 1. 获取每帧的全局 DeltaTime
|
||||
.TakeWhile(dt =>
|
||||
{
|
||||
// 2. 累加时间
|
||||
accumulatedTime += dt;
|
||||
// 3. 如果累积时间小于总时长,继续流;否则停止流并触发 OnCompleted
|
||||
return accumulatedTime < duration;
|
||||
})
|
||||
.Subscribe(
|
||||
_ => onUpdate?.Invoke(), // 每帧更新时执行 Action
|
||||
() => onComplete?.Invoke() // 4. 流结束时(TakeWhile 返回 false)执行 Action
|
||||
).AddTo(owner); // 5. 绑定生命周期到角色,防止内存泄漏
|
||||
}
|
||||
}
|
||||
|
||||
public partial class SelfTimeSubmodule
|
||||
@@ -84,7 +176,7 @@ namespace Cielonos.MainGame.Characters
|
||||
hitStopDisposable?.Dispose();
|
||||
|
||||
// 2. 设置当前的缩放倍率
|
||||
timeScaleCoefficient.Value = targetScale;
|
||||
localTimeScale.Value = targetScale;
|
||||
|
||||
// 3. 开启计时器
|
||||
// 注意:这里使用 Scheduler.MainThread,它是基于 Time.time (全局时间) 的。
|
||||
@@ -95,7 +187,7 @@ namespace Cielonos.MainGame.Characters
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
// 计时结束,恢复为 1
|
||||
timeScaleCoefficient.Value = 1f;
|
||||
localTimeScale.Value = 1f;
|
||||
hitStopDisposable = null;
|
||||
})
|
||||
.AddTo(owner); // 安全性:如果角色在顿帧期间死亡/销毁,自动取消计时器
|
||||
@@ -105,17 +197,16 @@ namespace Cielonos.MainGame.Characters
|
||||
/// 使用曲线动态修改本地时间流速
|
||||
/// </summary>
|
||||
/// <param name="duration">持续时间(秒)</param>
|
||||
/// <param name="start">曲线值为0时对应的时间倍率(通常是初始值)</param>
|
||||
/// <param name="peak">曲线值为1时对应的时间倍率(通常是极值)</param>
|
||||
/// <param name="curve">时间变化曲线(归一化:X轴0~1,Y轴通常0~1)。如果为null,则使用默认的“先升后降”抛物线。</param>
|
||||
public void ModifyTimeScale(float duration, float start, float peak, AnimationCurve curve = null)
|
||||
/// <param name="zeroValue">曲线起点值</param>
|
||||
/// <param name="oneValue">曲线终点值</param>
|
||||
/// <param name="easeType">插值曲线(null 则使用默认的 EaseInOut (从0到1) 曲线)</param>
|
||||
public void ModifyTimeScale(float duration, EaseType easeType, float zeroValue = 0, float oneValue = 1)
|
||||
{
|
||||
// 1. 清理旧的计时器
|
||||
hitStopDisposable?.Dispose();
|
||||
|
||||
// 2. 处理默认曲线逻辑
|
||||
curve ??= DefaultParabola;
|
||||
|
||||
|
||||
AnimationCurve curve = Ease.GetCurve(easeType);
|
||||
|
||||
// 3. 记录开始时的累计时间
|
||||
float timer = 0f;
|
||||
|
||||
@@ -125,30 +216,27 @@ namespace Cielonos.MainGame.Characters
|
||||
.Subscribe(
|
||||
_ =>
|
||||
{
|
||||
// 累加时间 (使用 Time.deltaTime 以响应全局暂停)
|
||||
timer += Time.deltaTime;
|
||||
// 累加时间
|
||||
timer += DeltaTime;
|
||||
|
||||
// 计算归一化进度 (0.0 ~ 1.0)
|
||||
float progress = Mathf.Clamp01(timer / duration);
|
||||
// 计算归一化时间(0 到 1)
|
||||
float normalizedTime = Mathf.Clamp01(timer / duration);
|
||||
|
||||
// 核心逻辑:
|
||||
// A. 从曲线获取当前的“强度” (Y轴值)
|
||||
float curveValue = curve.Evaluate(progress);
|
||||
// 根据曲线获取当前的插值系数
|
||||
float curveValue = curve.Evaluate(normalizedTime);
|
||||
|
||||
// B. 在 start 和 peak 之间根据强度进行插值
|
||||
// 当 curveValue = 0 时,结果为 start
|
||||
// 当 curveValue = 1 时,结果为 peak
|
||||
float currentScale = Mathf.Lerp(start, peak, curveValue);
|
||||
// 计算当前的时间缩放值
|
||||
float currentScale = curveValue * (oneValue - zeroValue) + zeroValue;
|
||||
|
||||
// C. 应用到响应式属性
|
||||
timeScaleCoefficient.Value = currentScale;
|
||||
// 应用到 timeScaleCoefficient
|
||||
localTimeScale.Value = currentScale;
|
||||
},
|
||||
() =>
|
||||
{
|
||||
// 5. 计时结束后的收尾工作
|
||||
// 通常为了安全,结束后我们会强制恢复到 1.0 (正常速度)
|
||||
// 或者你可以恢复到 start,视具体需求而定
|
||||
timeScaleCoefficient.Value = 1f;
|
||||
localTimeScale.Value = 1f;
|
||||
hitStopDisposable = null;
|
||||
}
|
||||
)
|
||||
@@ -159,7 +247,7 @@ namespace Cielonos.MainGame.Characters
|
||||
public void ResetTimeScale()
|
||||
{
|
||||
hitStopDisposable?.Dispose();
|
||||
timeScaleCoefficient.Value = 1f;
|
||||
localTimeScale.Value = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,9 +99,9 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
if (IsMoving)
|
||||
{
|
||||
operation.Dash();
|
||||
player.landMovementSc.TurnToDirection(new Vector3(Move.x, 0, Move.y));
|
||||
preinputSubmodule.RegisterPreinputAction(() => operation.Dash(), 10);
|
||||
Vector3 direction = new Vector3(Move.x, 0, Move.y);
|
||||
operation.Dash(direction);
|
||||
preinputSubmodule.RegisterPreinputAction(() => operation.Dash(direction), 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Linq;
|
||||
using Cielonos.UI;
|
||||
using FIMSpace.FProceduralAnimation;
|
||||
using MoreMountains.FeedbacksForThirdParty;
|
||||
using RootMotion.FinalIK;
|
||||
using SLSFramework.General;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
@@ -20,8 +21,24 @@ namespace Cielonos.MainGame.Characters
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
player.operationSc.OnDash += delegate { fullBodyFuncAnimSm.Play("Dash"); };
|
||||
player.operationSc.OnDodge += delegate { fullBodyFuncAnimSm.Play("Dodge"); };
|
||||
player.operationSc.OnDash += delegate(Vector3 dashDirection)
|
||||
{
|
||||
player.landMovementSc.TurnToDirection(dashDirection);
|
||||
Vector3 cameraForward = player.viewSc.playerCamera.transform.forward.Flatten();
|
||||
Vector3 dashCameraRotation = CalculateDashAngles(dashDirection, cameraForward);
|
||||
player.feedbackSc["Dash"].feedback.GetFeedbackOfType<MMF_CinemachineRotation>().RotationAmplitude = dashCameraRotation;
|
||||
player.feedbackSc["Dash"].feedback.GetFeedbackOfType<MMF_RadialBlur>().TargetCenter = player.GetNormalizedScreenPosition();
|
||||
fullBodyFuncAnimSm.Play("Dash");
|
||||
};
|
||||
player.operationSc.OnDodge += delegate
|
||||
{
|
||||
Vector3 dodgeDirection = Vector3.back;
|
||||
Vector3 cameraForward = player.viewSc.playerCamera.transform.forward.Flatten();
|
||||
Vector3 dodgeCameraRotation = CalculateDashAngles(dodgeDirection, cameraForward);
|
||||
player.feedbackSc["Dodge"].feedback.GetFeedbackOfType<MMF_CinemachineRotation>().RotationAmplitude = dodgeCameraRotation;
|
||||
player.feedbackSc["Dodge"].feedback.GetFeedbackOfType<MMF_RadialBlur>().TargetCenter = player.GetNormalizedScreenPosition();
|
||||
fullBodyFuncAnimSm.Play("Dodge");
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
@@ -44,7 +61,7 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
player.landMovementSc.isDashing = true;
|
||||
player.landMovementSc.dashMoveMultiplier = anim.funcAnimData.variableCollection.GetVariable<float>("DashMoveMultiplier");
|
||||
PostProcessingManager.Instance.radialBlurSm.ModifyBlurRadius(0.2f);
|
||||
player.selfTimeSm.ModifyTimeScale(0.1f, 1.25f);
|
||||
player.audioSc.PlayDashSound();
|
||||
player.feedbackSc["Dash"]?.Play();
|
||||
//player.renderSc.dashTrails.ForEach(ds => ds.active = true);
|
||||
@@ -53,14 +70,8 @@ namespace Cielonos.MainGame.Characters
|
||||
DodgeSource defaultDodge = new DodgeSource(owner, null, "DefaultDodge", 0, "NormalDodge", "PerfectDodge", Mathf.Infinity, 0.2f);
|
||||
defaultDodge.onPerfectDodge = () =>
|
||||
{
|
||||
PostProcessingManager.Instance.chromaticAberrationSm.SetIntensity(0.5f);
|
||||
PostProcessingManager.Instance.radialBlurSm.ModifyBlurRadius(0.2f);
|
||||
PostProcessingManager.Instance.tonemappingSm.SetContrast(1.35f);
|
||||
PostProcessingManager.Instance.tonemappingSm.SetSaturate(-2f);
|
||||
|
||||
player.attributeSm["Energy"] += 25;
|
||||
player.attributeSm["Energy"] = Mathf.Min(player.attributeSm["Energy"], player.attributeSm["MaximumEnergy"]);
|
||||
PlayerCanvas.Instance.playerInfoUIArea.UpdateEnergy();
|
||||
player.feedbackSc["PerfectDodge"].feedback.GetFeedbackOfType<MMF_RadialBlur>().TargetCenter = player.GetNormalizedScreenPosition();
|
||||
player.feedbackSc["PerfectDodge"].feedback.GetFeedbackOfType<MMF_AdvancedVignette>().Center = player.GetNormalizedScreenPosition();
|
||||
};
|
||||
player.reactionSc.dodgeSm.ApplyDodge(defaultDodge);
|
||||
});
|
||||
@@ -79,7 +90,6 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
player.landMovementSc.isDashing = true;
|
||||
player.landMovementSc.dashMoveMultiplier = anim.funcAnimData.variableCollection.GetVariable<float>("DashMoveMultiplier");
|
||||
PostProcessingManager.Instance.radialBlurSm.ModifyBlurRadius(-0.2f);
|
||||
player.audioSc.PlayDashSound();
|
||||
player.feedbackSc["Dodge"]?.Play();
|
||||
//player.renderSc.dashTrails.ForEach(ds => ds.active = true);
|
||||
@@ -88,14 +98,8 @@ namespace Cielonos.MainGame.Characters
|
||||
DodgeSource defaultDodge = new DodgeSource(owner, null, "DefaultDodge", 0, "NormalDodge", "PerfectDodge", Mathf.Infinity, 0.2f);
|
||||
defaultDodge.onPerfectDodge = () =>
|
||||
{
|
||||
PostProcessingManager.Instance.chromaticAberrationSm.SetIntensity(0.5f);
|
||||
PostProcessingManager.Instance.radialBlurSm.ModifyBlurRadius(-0.2f);
|
||||
PostProcessingManager.Instance.tonemappingSm.SetContrast(1.35f);
|
||||
PostProcessingManager.Instance.tonemappingSm.SetSaturate(-2.2f);
|
||||
|
||||
player.attributeSm["Energy"] += 25;
|
||||
player.attributeSm["Energy"] = Mathf.Min(player.attributeSm["Energy"], player.attributeSm["MaximumEnergy"]);
|
||||
PlayerCanvas.Instance.playerInfoUIArea.UpdateEnergy();
|
||||
player.feedbackSc["PerfectDodge"].feedback.GetFeedbackOfType<MMF_RadialBlur>().TargetCenter = player.GetNormalizedScreenPosition();
|
||||
player.feedbackSc["PerfectDodge"].feedback.GetFeedbackOfType<MMF_AdvancedVignette>().Center = player.GetNormalizedScreenPosition();
|
||||
};
|
||||
player.reactionSc.dodgeSm.ApplyDodge(defaultDodge);
|
||||
});
|
||||
@@ -124,4 +128,31 @@ namespace Cielonos.MainGame.Characters
|
||||
isAtActionDisruption = lastFrameIntervals.SwitchOut(currentIntervals, (interval) => interval.intervalType == IntervalType.Preinput);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class PlayerAnimationSubcontroller
|
||||
{
|
||||
/// <summary>
|
||||
/// 计算冲刺时的相机倾斜和俯仰
|
||||
/// </summary>
|
||||
/// <param name="dashDir">世界空间的冲刺向量 (如 Vector3.forward)</param>
|
||||
/// <param name="camForwardNoY">相机的前方 (y被设为0并归一化)</param>
|
||||
/// <returns>x为Pitch(俯仰), z为Dutch(侧倾)</returns>
|
||||
public Vector3 CalculateDashAngles(Vector3 dashDir, Vector3 camForwardNoY)
|
||||
{
|
||||
// 1. 获取相机的右方
|
||||
Vector3 camRight = Vector3.Cross(Vector3.up, camForwardNoY);
|
||||
|
||||
// 2. 将冲刺方向投影到相机的 前/后 和 左/右 轴上
|
||||
float forwardDot = Vector3.Dot(dashDir, camForwardNoY); // 1为前,-1为后
|
||||
float rightDot = Vector3.Dot(dashDir, camRight); // 1为右,-1为左
|
||||
|
||||
// 3. 计算目标侧倾值
|
||||
float targetDutch = forwardDot * 1f;
|
||||
|
||||
// 4. 计算目标俯仰值(注意取反,使得向前冲刺时相机向下俯仰)
|
||||
float targetPitch = -rightDot * 2.0f;
|
||||
|
||||
return new Vector3(targetPitch, 0, targetDutch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
public event Action OnInteract;
|
||||
|
||||
public event Action OnDash;
|
||||
public event Action<Vector3> OnDash;
|
||||
public event Action OnDodge;
|
||||
|
||||
public event Action OnLockOnTarget;
|
||||
@@ -63,7 +63,7 @@ namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
public void Interact() => OnInteract?.Invoke();
|
||||
|
||||
public void Dash() => OnDash?.Invoke();
|
||||
public void Dash(Vector3 direction) => OnDash?.Invoke(direction);
|
||||
|
||||
public void Dodge() => OnDodge?.Invoke();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.Serialization;
|
||||
using Ease = DG.Tweening.Ease;
|
||||
|
||||
namespace Cielonos.MainGame.Characters
|
||||
{
|
||||
@@ -25,14 +26,11 @@ namespace Cielonos.MainGame.Characters
|
||||
public CameraRotationSubmodule cameraRotationSm;
|
||||
public OcclusionFadeSubmodule occlusionFadeSm;
|
||||
|
||||
public LerpFloat cameraDistance;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
cameraRotationSm = new CameraRotationSubmodule(this, player.transform.eulerAngles.y);
|
||||
occlusionFadeSm = new OcclusionFadeSubmodule(this);
|
||||
cameraDistance = new LerpFloat(10f, 1f);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
@@ -54,10 +52,6 @@ namespace Cielonos.MainGame.Characters
|
||||
SwitchToFreeLook();
|
||||
}
|
||||
}
|
||||
|
||||
cameraDistance.Update(player.selfTimeSm.DeltaTime);
|
||||
freeLookCamera.GetComponent<CinemachineThirdPersonFollow>().CameraDistance = cameraDistance.currentValue;
|
||||
lockOnCamera.GetComponent<CinemachinePositionComposer>().CameraDistance = cameraDistance.currentValue;
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
|
||||
19
Assets/Scripts/MainGame/Effects/DamageNumberText.cs
Normal file
19
Assets/Scripts/MainGame/Effects/DamageNumberText.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using DamageNumbersPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public class DamageNumberText : MonoBehaviour
|
||||
{
|
||||
public DamageNumber main;
|
||||
}
|
||||
|
||||
public static class DamageNumberTextExtensions
|
||||
{
|
||||
public static DamageNumberText Spawn(this DamageNumberText prefab)
|
||||
{
|
||||
prefab.main.Spawn();
|
||||
return prefab;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/MainGame/Effects/DamageNumberText.cs.meta
Normal file
2
Assets/Scripts/MainGame/Effects/DamageNumberText.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39efce2b6a5b2b74e9f95573a238547c
|
||||
@@ -1,30 +0,0 @@
|
||||
using SLSFramework.General;
|
||||
using Beautify.Universal;
|
||||
|
||||
namespace Cielonos.MainGame.Effects
|
||||
{
|
||||
public partial class ChromaticAberrationSubmodule : PostProcessingSubmoduleBase
|
||||
{
|
||||
public LerpFloat intensity;
|
||||
|
||||
public ChromaticAberrationSubmodule(PostProcessingManager owner) : base(owner)
|
||||
{
|
||||
this.intensity = new LerpFloat(0, 0.05f);
|
||||
}
|
||||
|
||||
public override void Update(float factor)
|
||||
{
|
||||
intensity.Update(factor);
|
||||
if (owner.GetVolumeComponent<Beautify.Universal.Beautify>(out var beautify))
|
||||
{
|
||||
beautify.chromaticAberrationIntensity.value = intensity.currentValue * 0.1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ChromaticAberrationSubmodule
|
||||
{
|
||||
public void ModifyIntensity(float value) => ModifyCurrentValue(intensity, value);
|
||||
public void SetIntensity(float value) => SetCurrentValue(intensity, value);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c4d822e0b008874595c833896ced6b8
|
||||
@@ -1,51 +0,0 @@
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Effects
|
||||
{
|
||||
public partial class TonemappingSubmodule : PostProcessingSubmoduleBase
|
||||
{
|
||||
public LerpFloat saturate;
|
||||
public LerpFloat contrast;
|
||||
public LerpFloat brightness;
|
||||
public LerpColor tintColor;
|
||||
|
||||
public TonemappingSubmodule(PostProcessingManager owner) : base(owner)
|
||||
{
|
||||
this.saturate = new LerpFloat(1.2f, 0.05f);
|
||||
this.brightness = new LerpFloat(1f, 0.05f);
|
||||
this.contrast = new LerpFloat(1.15f, 0.05f);
|
||||
this.tintColor = new LerpColor(new Color(0.9411765f, 1, 1), 0.05f);
|
||||
}
|
||||
|
||||
public override void Update(float factor)
|
||||
{
|
||||
saturate.Update(factor);
|
||||
brightness.Update(factor);
|
||||
contrast.Update(factor);
|
||||
tintColor.Update(factor);
|
||||
if(owner.GetVolumeComponent<Beautify.Universal.Beautify>(out var beautify))
|
||||
{
|
||||
beautify.saturate.value = saturate.currentValue;
|
||||
beautify.brightness.value = brightness.currentValue;
|
||||
beautify.contrast.value = contrast.currentValue;
|
||||
beautify.tintColor.value = tintColor.currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class TonemappingSubmodule
|
||||
{
|
||||
public void ModifySaturate(float value) => ModifyCurrentValue(saturate, value);
|
||||
public void SetSaturate(float value) => SetCurrentValue(saturate, value);
|
||||
|
||||
public void ModifyBrightness(float value) => ModifyCurrentValue(brightness, value);
|
||||
public void SetBrightness(float value) => SetCurrentValue(brightness, value);
|
||||
|
||||
public void ModifyContrast(float value) => ModifyCurrentValue(contrast, value);
|
||||
public void SetContrast(float value) => SetCurrentValue(contrast, value);
|
||||
|
||||
public void ModifyTintColor(Color value) => ModifyCurrentValue(tintColor, value);
|
||||
public void SetTintColor(Color value) => SetCurrentValue(tintColor, value);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b40b17602d6f8fe4f86ca42ae86514e4
|
||||
@@ -15,9 +15,7 @@ namespace Cielonos
|
||||
|
||||
public RadialBlurSubmodule radialBlurSm;
|
||||
public SpeedLinesSubmodule speedLinesSm;
|
||||
public ChromaticAberrationSubmodule chromaticAberrationSm;
|
||||
public RGBSplitGlitchSubmodule rgbSplitGlitchSm;
|
||||
public TonemappingSubmodule tonemappingSm;
|
||||
|
||||
[Tooltip("主要的后处理 Volume")]
|
||||
[SerializeField]
|
||||
@@ -32,9 +30,7 @@ namespace Cielonos
|
||||
base.Awake();
|
||||
radialBlurSm = new RadialBlurSubmodule(this);
|
||||
speedLinesSm = new SpeedLinesSubmodule(this);
|
||||
chromaticAberrationSm = new ChromaticAberrationSubmodule(this);
|
||||
rgbSplitGlitchSm = new RGBSplitGlitchSubmodule(this);
|
||||
tonemappingSm = new TonemappingSubmodule(this);
|
||||
if (volume != null)
|
||||
{
|
||||
profile = volume.profile;
|
||||
@@ -48,11 +44,11 @@ namespace Cielonos
|
||||
|
||||
private void Update()
|
||||
{
|
||||
radialBlurSm.Update(MainGameManager.PlayerTimeScale);
|
||||
speedLinesSm.Update(MainGameManager.PlayerTimeScale);
|
||||
rgbSplitGlitchSm.Update(MainGameManager.PlayerTimeScale);
|
||||
chromaticAberrationSm.Update(MainGameManager.PlayerTimeScale);
|
||||
tonemappingSm.Update(MainGameManager.PlayerTimeScale);
|
||||
//radialBlurSm.Update(MainGameManager.PlayerTimeScale);
|
||||
speedLinesSm.Update(MainGameManager.Player.selfTimeSm.TimeScale);
|
||||
//rgbSplitGlitchSm.Update(MainGameManager.PlayerTimeScale);
|
||||
//chromaticAberrationSm.Update(MainGameManager.PlayerTimeScale);
|
||||
//tonemappingSm.Update(MainGameManager.PlayerTimeScale);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -13,10 +13,11 @@ namespace Cielonos.MainGame
|
||||
[NonSerialized]
|
||||
public CharacterBase creator;
|
||||
|
||||
public bool affectedByCreatorTimeScale = true;
|
||||
|
||||
public List<ParticleSystem> particles = new List<ParticleSystem>();
|
||||
|
||||
[NonSerialized]
|
||||
public List<ParticleSystem.MainModule> particleMainModules = new List<ParticleSystem.MainModule>();
|
||||
[NonSerialized] private List<ParticleSystem.MainModule> particleMainModules;
|
||||
|
||||
public static GameObject Spawn(GameObject vfxPrefab, CharacterBase creator, Transform parent = null)
|
||||
{
|
||||
@@ -45,10 +46,14 @@ namespace Cielonos.MainGame
|
||||
}
|
||||
|
||||
base.OnSpawn();
|
||||
particleMainModules = new List<ParticleSystem.MainModule>();
|
||||
foreach (var ps in particles)
|
||||
|
||||
if (particleMainModules == null)
|
||||
{
|
||||
particleMainModules.Add(ps.main);
|
||||
particleMainModules = new List<ParticleSystem.MainModule>();
|
||||
foreach (var ps in particles)
|
||||
{
|
||||
particleMainModules.Add(ps.main);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,22 +68,25 @@ namespace Cielonos.MainGame
|
||||
particles.Add(ps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
float deltaTime = Time.deltaTime;
|
||||
float timeScale = 1f;
|
||||
|
||||
|
||||
if (creator != null)
|
||||
{
|
||||
deltaTime = creator.selfTimeSm.DeltaTime;
|
||||
timeScale = creator.selfTimeSm.timeScaleCoefficient.Value;
|
||||
timeScale = creator.selfTimeSm.TimeScale;
|
||||
}
|
||||
|
||||
|
||||
UpdateTimer(deltaTime);
|
||||
particleMainModules.ForEach(main => main.simulationSpeed = timeScale);
|
||||
if (affectedByCreatorTimeScale)
|
||||
{
|
||||
particleMainModules.ForEach(main => main.simulationSpeed = timeScale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetCreator(CharacterBase character)
|
||||
{
|
||||
creator = character;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Cielonos.MainGame.Characters;
|
||||
using MoreMountains.Feedbacks;
|
||||
using MoreMountains.FeedbacksForThirdParty;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -98,18 +99,36 @@ namespace Cielonos.MainGame.Inventory
|
||||
|
||||
public partial class MainWeaponBase
|
||||
{
|
||||
protected void Swing(string swingAudio = "", string feedBackName = "", Vector3 force = default)
|
||||
protected void Swing(string swingAudio, string feedBackName)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(swingAudio))
|
||||
{
|
||||
audioContainer.PlaySoundFX(swingAudio, null, true);
|
||||
}
|
||||
|
||||
if (force != default)
|
||||
feedbackSc[feedBackName].Play();
|
||||
}
|
||||
|
||||
protected void Swing(string swingAudio, string feedBackName, Vector3 swingRotation, Vector3 swingVelocity = default)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(swingAudio))
|
||||
{
|
||||
feedbackSc[feedBackName].feedback.GetFeedbackOfType<MMF_CinemachineImpulse>().Velocity = force;
|
||||
feedbackSc[feedBackName].Play();
|
||||
audioContainer.PlaySoundFX(swingAudio, null, true);
|
||||
}
|
||||
|
||||
MMF_CinemachineRotation cinemachineRotation = feedbackSc[feedBackName].feedback.GetFeedbackOfType<MMF_CinemachineRotation>();
|
||||
if (cinemachineRotation != null)
|
||||
{
|
||||
cinemachineRotation.RotationAmplitude = swingRotation != default ? swingRotation : Vector3.zero;
|
||||
}
|
||||
|
||||
MMF_CinemachineImpulse cinemachineImpulse = feedbackSc[feedBackName].feedback.GetFeedbackOfType<MMF_CinemachineImpulse>();
|
||||
if (cinemachineImpulse != null)
|
||||
{
|
||||
cinemachineImpulse.Velocity = swingVelocity != default ? swingVelocity : Vector3.zero;
|
||||
}
|
||||
|
||||
feedbackSc[feedBackName].Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,11 +43,12 @@ namespace Cielonos.MainGame.Inventory
|
||||
"NormalBlock", "PerfectBlock", defaultBlockTime, perfectTime);
|
||||
}
|
||||
|
||||
public GameObject InstantiateBlockEffect(string effectName, Vector3 position, Quaternion rotation)
|
||||
public GameObject InstantiateBlockEffect(string effectName, CharacterBase creator, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
if (blockEffects.TryGetValue(effectName, out GameObject effect))
|
||||
{
|
||||
return LeanPool.Spawn(effect, position, rotation);
|
||||
GameObject obj = VFXObject.Spawn(effect, creator, position, rotation);
|
||||
return obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Cielonos.MainGame.Characters;
|
||||
using Cielonos.MainGame.Characters.Buffs;
|
||||
using SLSFramework.General;
|
||||
using SLSUtilities.FunctionalAnimation;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame.Inventory
|
||||
@@ -110,7 +110,7 @@ namespace Cielonos.MainGame.Inventory
|
||||
fullBodyFuncAnimSm.Stop(DisruptionType.ForcedAction);
|
||||
}
|
||||
|
||||
RemoveBlock();
|
||||
player.selfTimeSm.AddLocalTimer(0.1f, RemoveBlock);
|
||||
player.movementSc.canMove.Modify(true);
|
||||
player.movementSc.canRotate.Modify(true);
|
||||
}
|
||||
@@ -118,22 +118,22 @@ namespace Cielonos.MainGame.Inventory
|
||||
|
||||
public partial class Polychrome
|
||||
{
|
||||
private void LightAttack0() => GenerateNormalSlash("LightAttack0", new Vector3(1f, 0.6f, 0).normalized * 0.1f);
|
||||
private void LightAttack1() => GenerateNormalSlash("LightAttack1", new Vector3(-1f, -0.6f, 0).normalized * 0.1f);
|
||||
private void LightAttack2() => GenerateNormalSlash("LightAttack2", new Vector3(-1f, 0.6f, 0).normalized * 0.1f);
|
||||
private void LightAttack3() => GenerateNormalSlash("LightAttack3", Vector3.right * 0.1f);
|
||||
private void TripleAttack_0() => GenerateFastSlash("TripleAttack_0", new Vector3(1f, 0.6f, 0).normalized * 0.2f);
|
||||
private void TripleAttack_1() => GenerateFastSlash("TripleAttack_1", new Vector3(-1f, -0.6f, 0).normalized * 0.2f);
|
||||
private void TripleAttack_2() => GenerateFastSlash("TripleAttack_2", Vector3.right * 0.2f);
|
||||
private void HeavyAttack() => GenerateHeavySlash("HeavyAttack", new Vector3(1f, 0.6f, 0).normalized * 0.4f);
|
||||
private void RunAttack() => GenerateMoveSlash("RunAttack", new Vector3(1f, 0.6f, 0).normalized * 0.1f, player.transform.forward * 10f);
|
||||
private void ParryAttack() => GenerateParrySlash("ParryAttack", new Vector3(-1f, -0.6f, 0).normalized * 0.4f);
|
||||
private void LightAttack0() => GenerateNormalSlash("LightAttack0", new Vector3(0.5f, 1f, 0));
|
||||
private void LightAttack1() => GenerateNormalSlash("LightAttack1", new Vector3(-0.5f, -1f, 0));
|
||||
private void LightAttack2() => GenerateNormalSlash("LightAttack2", new Vector3(0.8f, -1.2f, 0));
|
||||
private void LightAttack3() => GenerateNormalSlash("LightAttack3", new Vector3(0.5f, 1.5f, 0));
|
||||
private void TripleAttack_0() => GenerateFastSlash("TripleAttack_0", new Vector3(1f, 0.6f, 0));
|
||||
private void TripleAttack_1() => GenerateFastSlash("TripleAttack_1", new Vector3(-1f, -0.6f, 0));
|
||||
private void TripleAttack_2() => GenerateFastSlash("TripleAttack_2", Vector3.right);
|
||||
private void HeavyAttack() => GenerateHeavySlash("HeavyAttack", new Vector3(3, -2, -5));
|
||||
private void RunAttack() => GenerateMoveSlash("RunAttack", new Vector3(1f, 0.6f, 0), player.transform.forward * 10f);
|
||||
private void ParryAttack() => GenerateParrySlash("ParryAttack", new Vector3(5, 3, -8));
|
||||
private void DisruptAttack() => GenerateDisruptSlash("DisruptAttack", new Vector3(1f, 0, 0).normalized * 0.4f);
|
||||
}
|
||||
|
||||
public partial class Polychrome
|
||||
{
|
||||
private NormalArea GenerateNormalSlash(string vfxName, Vector3 swingForce)
|
||||
private NormalArea GenerateNormalSlash(string vfxName, Vector3 swingRotation)
|
||||
{
|
||||
NormalArea slash = vfxData.SpawnVFX(vfxName).GetComponentInChildren<NormalArea>();
|
||||
|
||||
@@ -148,12 +148,10 @@ namespace Cielonos.MainGame.Inventory
|
||||
.AddHitEvent((enemy, hitPosition) =>
|
||||
{
|
||||
feedbackSc["NormalHit"].Play();
|
||||
player.selfTimeSm.ModifyTimeScale(0.06f);
|
||||
enemy.selfTimeSm.ModifyTimeScale(0.06f);
|
||||
new ElectronicDisturbance(2).Apply(enemy);
|
||||
});
|
||||
|
||||
Swing("Swing", "Swing", swingForce);
|
||||
Swing("NormalSwing", "NormalSwing", swingRotation);
|
||||
|
||||
return slash;
|
||||
}
|
||||
@@ -168,13 +166,14 @@ namespace Cielonos.MainGame.Inventory
|
||||
.SetHitSubmodule<NormalArea>()
|
||||
.SetForceSubmodule<NormalArea>(3f, true);
|
||||
|
||||
|
||||
string hitFeedbackName = vfxName != "TripleAttack_2" ? "FastHitFirsts" : "FastHitFinal";
|
||||
|
||||
slash.hitSm
|
||||
.AddHitSound("NormalHit")
|
||||
.AddHitEvent((enemy, hitPosition) =>
|
||||
{
|
||||
feedbackSc["NormalHit"].Play();
|
||||
player.selfTimeSm.ModifyTimeScale(0.06f);
|
||||
enemy.selfTimeSm.ModifyTimeScale(0.06f);
|
||||
feedbackSc[hitFeedbackName].Play();
|
||||
new ElectronicDisturbance(2).Apply(enemy);
|
||||
|
||||
if (enemy.statusSm.HasStatus(StatusType.Incapacitation))
|
||||
@@ -183,33 +182,35 @@ namespace Cielonos.MainGame.Inventory
|
||||
}
|
||||
});
|
||||
|
||||
Swing("Swing", "Swing", swingForce);
|
||||
Swing("NormalSwing", "NormalSwing", swingForce);
|
||||
|
||||
return slash;
|
||||
}
|
||||
|
||||
private NormalArea GenerateHeavySlash(string vfxName, Vector3 swingForce)
|
||||
private NormalArea GenerateHeavySlash(string vfxName, Vector3 swingRotation)
|
||||
{
|
||||
NormalArea slash = vfxData.SpawnVFX(vfxName).GetComponentInChildren<NormalArea>();
|
||||
|
||||
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
|
||||
.SetAttackSubmodule<NormalArea>(attackData["HeavyAttack"])
|
||||
.SetTimeSubmodule<NormalArea>(1f, 0.04f, 0.16f)
|
||||
.SetHitSubmodule<NormalArea>()
|
||||
.SetTimeSubmodule<NormalArea>(1f, 0.04f, 0.2f)
|
||||
.SetHitSubmodule<NormalArea>(0.04f, 4)
|
||||
.SetForceSubmodule<NormalArea>(3f, true);
|
||||
|
||||
|
||||
slash.hitSm
|
||||
.AddHitSound("HeavyHit")
|
||||
.AddHitEvent((enemy, hitPosition) =>
|
||||
{
|
||||
feedbackSc["HeavyHit"].Play();
|
||||
player.selfTimeSm.ModifyTimeScale(0.12f);
|
||||
enemy.selfTimeSm.ModifyTimeScale(0.12f);
|
||||
player.viewSc.cameraDistance.currentValue -= 2f;
|
||||
feedbackSc["HeavyHitFirst"].Play();
|
||||
new ElectronicDisturbance(5).Apply(enemy);
|
||||
});
|
||||
}, 0)
|
||||
.AddHitEvent((enemy, hitPosition) =>
|
||||
{
|
||||
feedbackSc["HeavyHitFollows"].Play();
|
||||
new ElectronicDisturbance(5).Apply(enemy);
|
||||
}, 1, 2, 3);
|
||||
|
||||
Swing("Swing", "Swing", swingForce);
|
||||
Swing("HeavySwing", "HeavySwing", swingRotation);
|
||||
|
||||
return slash;
|
||||
}
|
||||
@@ -228,13 +229,18 @@ namespace Cielonos.MainGame.Inventory
|
||||
.AddHitSound("HeavyHit")
|
||||
.AddHitEvent((enemy, hitPosition) =>
|
||||
{
|
||||
feedbackSc["HeavyHit"].Play();
|
||||
feedbackSc["ParryHit"].Play();
|
||||
player.selfTimeSm.ModifyTimeScale(0.12f);
|
||||
enemy.selfTimeSm.ModifyTimeScale(0.12f);
|
||||
player.selfTimeSm.AddGlobalTimer(0.12f, () =>
|
||||
{
|
||||
player.selfTimeSm.ModifyTimeScale(0.2f, 0.3f);
|
||||
enemy.selfTimeSm.ModifyTimeScale(0.2f, 0.3f);
|
||||
});
|
||||
new ElectronicDisturbance(5).Apply(enemy);
|
||||
});
|
||||
|
||||
Swing("Swing", "Swing", swingForce);
|
||||
Swing("HeavySwing", "HeavySwing", swingForce);
|
||||
|
||||
return slash;
|
||||
}
|
||||
@@ -253,13 +259,11 @@ namespace Cielonos.MainGame.Inventory
|
||||
.AddHitSound("HeavyHit")
|
||||
.AddHitEvent((enemy, hitPosition) =>
|
||||
{
|
||||
feedbackSc["HeavyHit"].Play();
|
||||
player.selfTimeSm.ModifyTimeScale(0.12f);
|
||||
enemy.selfTimeSm.ModifyTimeScale(0.12f);
|
||||
feedbackSc["DisruptHit"].Play();
|
||||
new ElectronicDisturbance(5).Apply(enemy);
|
||||
});
|
||||
|
||||
Swing("Swing", "Swing", swingForce);
|
||||
Swing("HeavySwing", "HeavySwing", swingForce);
|
||||
|
||||
return slash;
|
||||
}
|
||||
@@ -280,12 +284,10 @@ namespace Cielonos.MainGame.Inventory
|
||||
.AddHitEvent((enemy, hitPosition) =>
|
||||
{
|
||||
feedbackSc["NormalHit"].Play();
|
||||
player.selfTimeSm.ModifyTimeScale(0.06f);
|
||||
enemy.selfTimeSm.ModifyTimeScale(0.06f);
|
||||
new ElectronicDisturbance(2).Apply(enemy);
|
||||
});
|
||||
|
||||
Swing("Swing", "Swing", swingForce);
|
||||
Swing("NormalSwing", "NormalSwing", swingForce);
|
||||
}
|
||||
|
||||
string parryAnimName = "ParryL";
|
||||
@@ -295,10 +297,20 @@ namespace Cielonos.MainGame.Inventory
|
||||
BlockSource blockSource = blockData.CreateBlockSource(player, this);
|
||||
blockSource.onNormalBlock = (attackArea) =>
|
||||
{
|
||||
PostProcessingManager.Instance.chromaticAberrationSm.ModifyIntensity(0.2f);
|
||||
PostProcessingManager.Instance.radialBlurSm.ModifyBlurRadius(0.2f);
|
||||
parryAnimName = parryAnimName == "ParryL" ? "ParryR" : "ParryL";
|
||||
animationSc.fullBodyFuncAnimSm.Play(parryAnimName, 1, 0);
|
||||
player.selfTimeSm.ModifyTimeScale(0.06f, 0.4f);
|
||||
attackArea.creator.selfTimeSm.ModifyTimeScale(0.06f, 0.4f);
|
||||
|
||||
if (parryAnimName == "ParryL")
|
||||
{
|
||||
feedbackSc["NormalBlockLeft"].Play();
|
||||
}
|
||||
else
|
||||
{
|
||||
feedbackSc["NormalBlockRight"].Play();
|
||||
}
|
||||
|
||||
if (attackArea is NormalArea)
|
||||
{
|
||||
new ElectronicDisturbance(2).Apply(attackArea.creator);
|
||||
@@ -306,15 +318,27 @@ namespace Cielonos.MainGame.Inventory
|
||||
};
|
||||
blockSource.onPerfectBlock = (attackArea) =>
|
||||
{
|
||||
PostProcessingManager.Instance.chromaticAberrationSm.ModifyIntensity(0.5f);
|
||||
PostProcessingManager.Instance.radialBlurSm.ModifyBlurRadius(0.5f);
|
||||
parryAnimName = parryAnimName == "ParryL" ? "ParryR" : "ParryL";
|
||||
animationSc.fullBodyFuncAnimSm.Play(parryAnimName, 1, 0);
|
||||
player.selfTimeSm.ModifyTimeScale(0.12f, EaseType.InQuint, 0.2f);
|
||||
attackArea.creator.selfTimeSm.ModifyTimeScale(0.12f, EaseType.InQuint, 0.2f);
|
||||
|
||||
if (parryAnimName == "ParryL")
|
||||
{
|
||||
feedbackSc["PerfectBlockLeft"].Play();
|
||||
}
|
||||
else
|
||||
{
|
||||
feedbackSc["PerfectBlockRight"].Play();
|
||||
}
|
||||
|
||||
perfectBlockedTimer = 0.5f;
|
||||
if (attackArea is NormalArea)
|
||||
{
|
||||
new ElectronicDisturbance(10).Apply(attackArea.creator);
|
||||
}
|
||||
|
||||
//Debug.Break();
|
||||
};
|
||||
player.reactionSc.blockSm.ApplyBlock(blockSource);
|
||||
//blockDisposable?.Dispose();
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Cielonos.MainGame.Inventory
|
||||
{
|
||||
foreach (var feedbackUnit in feedbacks.Values)
|
||||
{
|
||||
float timeScaleMultiplier = owner.player.selfTimeSm.TimeScale;
|
||||
feedbackUnit.feedback.ExternalTimeScale = timeScaleMultiplier;
|
||||
feedbackUnit.Update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using DamageNumbersPro;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -8,7 +9,7 @@ namespace Cielonos.MainGame
|
||||
public class BasePrefabsCollection : SerializedScriptableObject
|
||||
{
|
||||
public GameObject audioPoint;
|
||||
public Dictionary<string, GameObject> hudTextCollection;
|
||||
public Dictionary<string, DamageNumber> hudTextCollection;
|
||||
|
||||
public Dictionary<BreakthroughType, Color> outlineColorCollection;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Cielonos.MainGame.Characters;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
@@ -14,15 +15,17 @@ namespace Cielonos.MainGame
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
Application.targetFrameRate = 120;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Application.targetFrameRate = 60;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class MainGameManager
|
||||
{
|
||||
public static Player Player => Instance.player;
|
||||
public static float PlayerTimeScale => Instance.player.selfTimeSm.TimeScale;
|
||||
public static float PlayerDeltaTime => Instance.player.selfTimeSm.DeltaTime;
|
||||
public static BasePrefabsCollection BasePrefabs => Instance.basePrefabs;
|
||||
}
|
||||
}
|
||||
|
||||
15
Assets/Scripts/MainGame/Managers/TimeManager.cs
Normal file
15
Assets/Scripts/MainGame/Managers/TimeManager.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using SLSFramework.General;
|
||||
using UniRx;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cielonos.MainGame
|
||||
{
|
||||
public class TimeManager : Singleton<TimeManager>
|
||||
{
|
||||
public FloatReactiveProperty globalTimeScale = new FloatReactiveProperty(1f);
|
||||
public FloatReactiveProperty playerTimeScale = new FloatReactiveProperty(1f);
|
||||
public FloatReactiveProperty alliedMinionTimeScale = new FloatReactiveProperty(1f);
|
||||
public FloatReactiveProperty nonPlayerTimeScale = new FloatReactiveProperty(1f);
|
||||
public FloatReactiveProperty enemyTimeScale = new FloatReactiveProperty(1f);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/MainGame/Managers/TimeManager.cs.meta
Normal file
2
Assets/Scripts/MainGame/Managers/TimeManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 588340523f272b040ac2333d06c0443b
|
||||
Reference in New Issue
Block a user