我说次元斩

This commit is contained in:
SoulliesOfficial
2026-06-13 18:43:40 -04:00
parent 6d7ebc5825
commit a024305799
95 changed files with 138226 additions and 5191 deletions

View File

@@ -144,8 +144,8 @@ namespace Cielonos.MainGame
if (attackUnit.useVFXDataHit)
{
hitVFX ??= itemSource != null
? itemSource.vfxData.Get(attackUnit.vfxUnitName).hitVFX
: creator.vfxData.Get(attackUnit.vfxUnitName).hitVFX;
? itemSource.vfxData.Get(attackUnit.vfxUnitName)?.hitVFX
: creator.vfxData.Get(attackUnit.vfxUnitName)?.hitVFX;
}
else
{

View File

@@ -56,6 +56,7 @@ namespace Cielonos.MainGame
public GameObject hitVFX;
[ShowIf("useVFXDataHit")]
public string vfxUnitName;
public bool randomizeVfxRotation;
[Title("Extra Modules")]
[ListDrawerSettings(ShowFoldout = true)]

View File

@@ -68,8 +68,15 @@ namespace Cielonos.MainGame
{
GameObject hitEffect = base.GenerateHitEffect(target, hitCollider, hitPosition);
if(hitEffect == null) return null;
Vector3 hitEffectDirection = GetHitEffectDirection(hitCollider.ClosestPoint(transform.position));
hitEffect.transform.rotation = Quaternion.LookRotation(hitEffectDirection);
Quaternion rotation = Quaternion.LookRotation(hitEffectDirection);
if (attackSm.attackUnit.randomizeVfxRotation)
{
rotation *= Quaternion.Euler(Random.Range(0f, 360f), Random.Range(0f, 360f), 0);
}
hitEffect.transform.rotation = rotation;
return hitEffect;
}
}

View File

@@ -5,6 +5,7 @@ using DamageNumbersPro;
using Lean.Pool;
using UnityEngine;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
namespace Cielonos.MainGame
{
@@ -34,7 +35,12 @@ namespace Cielonos.MainGame
if (hitVFXPrefab != null)
{
direction = direction != default ? direction : Vector3.up;
GameObject hitEffect = VFXObject.Spawn(hitVFXPrefab, creator, position, Quaternion.LookRotation(direction));
Quaternion rotation = Quaternion.LookRotation(direction);
if (attackUnit.randomizeVfxRotation)
{
rotation *= Quaternion.Euler(Random.Range(0f, 360f), Random.Range(0f, 360f), 0);
}
GameObject hitEffect = VFXObject.Spawn(hitVFXPrefab, creator, position, rotation);
return hitEffect;
}

View File

@@ -46,6 +46,9 @@ namespace Cielonos.MainGame.Characters
{
if (data == null) return null;
if (!data.CanPlay()) return null;
data.RecordPlay();
if (stopPrevious)
{
StopFeedback(data);

View File

@@ -15,8 +15,12 @@ namespace Cielonos.MainGame
[DictionaryDrawerSettings(KeyLabel = "VFX Name", DisplayMode = DictionaryDisplayOptions.ExpandedFoldout)]
[Searchable]
public OrderedDictionary<string, VFXUnit> collection = new OrderedDictionary<string, VFXUnit>();
public VFXUnit Get(string effectName) => collection[effectName];
public VFXUnit Get(string effectName)
{
if (string.IsNullOrEmpty(effectName)) return null;
return collection.GetValueOrDefault(effectName);
}
}
public partial class VFXData

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e65114e63399ae04e99afc1d488d9a1a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -68,21 +68,26 @@ namespace Cielonos.MainGame.Inventory.Collections
{
List<Enemy> availableEnemies = CombatManager.EnemySm.GetEnemiesInRadius(player.transform.position, 4);
List<Enemy> disruptable = CombatManager.EnemySm.GetDisruptableEnemies(availableEnemies);
Enemy target = CombatManager.EnemySm.GetScoredEnemies(availableEnemies)
.ApplyScoreModifier(disruptable, 0f, 1f).BestEnemy();
Enemy target = CombatManager.EnemySm.GetScoredEnemies(availableEnemies).ApplyScoreModifier(disruptable, 0f, 1f).BestEnemy();
if (PlayTargetedAnimation("DisruptionAttackB", target))
if (target != null)
{
FeedbackClip timeScaleModifierClip = player.feedbackSc.GetFeedbackData("DisruptionStartup")
.Clip<TimeScaleModifierAction>("Time");
float duration = fullBodyFuncAnimSm.collection["DisruptionAttackB"]
.Interval(IntervalType.Startup).Duration * 2;
if (PlayTargetedAnimation("DisruptionAttackB", target))
{
FeedbackClip timeScaleModifierClip = player.feedbackSc.GetFeedbackData("DisruptionStartup")
.Clip<TimeScaleModifierAction>("Time");
float duration = fullBodyFuncAnimSm.collection["DisruptionAttackB"]
.Interval(IntervalType.Startup).Duration * 2;
timeScaleModifierClip.duration = duration;
player.feedbackSc.PlayFeedback("DisruptionStartup");
comboSm.main.Reset();
_passionSystem.DecreasePassion(100, false);
timeScaleModifierClip.duration = duration;
player.feedbackSc.PlayFeedback("DisruptionStartup");
comboSm.main.Reset();
_passionSystem.DecreasePassion(100, false);
}
}
SetBlock(equipBlockData, false);
player.selfTimeSm.AddLocalTimer(0.4f, () => RemoveBlock(equipBlockData));
}
else
{
@@ -231,8 +236,7 @@ namespace Cielonos.MainGame.Inventory.Collections
string suffix = isEnhanced ? "B" : "A";
List<Enemy> disruptable = CombatManager.EnemySm.GetDisruptableEnemies(availableEnemies);
Enemy target = CombatManager.EnemySm.GetScoredEnemies(availableEnemies)
.ApplyScoreModifier(disruptable, 0f, 1f).BestEnemy();
Enemy target = CombatManager.EnemySm.GetScoredEnemies(availableEnemies).ApplyScoreModifier(disruptable, 0f, 1f).BestEnemy();
if (PlayTargetedAnimation("DisruptionAttack" + suffix, target))
{
@@ -305,11 +309,7 @@ namespace Cielonos.MainGame.Inventory.Collections
public override void OnSpecialBPress()
{
player.operationSc.Dodge();
DodgeSource defaultDodge = DodgeSource.Default(player);
player.reactionSc.dodgeSm.ApplyDodge(defaultDodge);
player.reactionSc.dodgeSm.GetCurrentDodgeSource().PerfectDodge(null);
player.reactionSc.dodgeSm.RemoveDodge("DefaultDodge");
PlayTargetedAnimation("UltimateAttack");
}
}

View File

@@ -55,5 +55,18 @@ namespace Cielonos.MainGame.Inventory.Collections
CustomFunction.PC_StringString p = rtFuncAnim.GetParams<CustomFunction.PC_StringString>();
GenerateDisruptionSlash(p.str0, attackData[p.str1]);
}
private void FAPF_GenerateCutStar(RuntimeFuncAnim rtFuncAnim)
{
vfxData.SpawnVFX("CutStar", player);
for (int i = 0; i < 3; i++)
{
float timeInterval = 0.5f + 0.07f * i;
player.selfTimeSm.AddLocalTimer(timeInterval, () =>
{
AudioManager.Post(AK.EVENTS.POLYCHROME_LIGHTATTACKSWING, player.gameObject);
});
}
}
}
}

View File

@@ -10,6 +10,7 @@ using SLSUtilities.General;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.WwiseAssistance;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Cielonos.MainGame.Inventory.Collections
{
@@ -109,16 +110,21 @@ namespace Cielonos.MainGame.Inventory.Collections
private NormalArea GenerateUltimateSlash(string vfxName, AttackUnit attackUnit)
{
NormalArea slash = CreateBaseSlash(vfxName, attackUnit, 1f, 0.04f);
NormalArea slash = vfxData.SpawnVFX(vfxName, player).GetComponentInChildren<NormalArea>();
slash.Initialize<NormalArea>(player, this, Fraction.Enemy)
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(2f, 0f, 0.22f)
.SetHitSubmodule<NormalArea>(0.07f, 3);
slash.SetImpulseSubmodule(1f).WithRepulsion(5f);
slash.hitSm.AddHitSound(AK.EVENTS.POLYCHROME_HEAVYATTACKLHIT)
.AddHitEvent((enemy, hitPosition) =>
{
var positionShakeAction = feedbackSc.GetFeedbackData("HeavyHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = vfxData.Get(vfxName).slashScreenPosition.normalized * 0.18f;
feedbackSc.PlayFeedback("HeavyHit");
feedbackSc.PlayFeedback("Breakthrough");
var positionShakeAction = feedbackSc.GetFeedbackData("UltimateAttackHit").Action<CameraPositionShakeAction>("Camera");
positionShakeAction.amplitude = new Vector3(Random.value, Random.value, Random.value).normalized * 0.18f;
feedbackSc.PlayFeedback("UltimateAttackHit");
});
return slash;

View File

@@ -21,32 +21,32 @@ namespace Cielonos.MainGame.Inventory.Collections
feedbackSc.PlayFeedback(feedbackName);
}
private void SetBlock(BlockData blockData = null)
private void SetBlock(BlockData blockData = null, bool hasReaction = true)
{
blockData ??= this.blockData;
BlockSource blockSource = blockData.CreateBlockSource(player, this);
player.landMovementSc.canDash = false;
player.landMovementSc.canDodge = false;
blockSource.onNormalBlock = (attackArea) =>
if (hasReaction)
{
PlayBlockReaction("NormalBlock", 1f);
};
blockSource.onPerfectBlock = (attackArea) =>
{
PlayBlockReaction("PerfectBlock", 2f);
blockSource.onNormalBlock = (attackArea) => { PlayBlockReaction("NormalBlock", 1f); };
if (attackArea is NormalArea)
blockSource.onPerfectBlock = (attackArea) =>
{
if (HasExtender<PhotonPolarizer>()) // 如果有Photon Polarizer完美格挡会弹开并打断敌人
PlayBlockReaction("PerfectBlock", 2f);
if (attackArea is NormalArea)
{
attackArea.creator.GetHit(Breakthrough.Type.Forced, out _);
attackArea.creator.movementSc.impulseSm.ApplyKnockback(player.transform.forward, 6f);
if (HasExtender<PhotonPolarizer>()) // 如果有Photon Polarizer完美格挡会弹开并打断敌人
{
attackArea.creator.GetHit(Breakthrough.Type.Forced, out _);
attackArea.creator.movementSc.impulseSm.ApplyKnockback(player.transform.forward, 6f);
}
}
}
};
};
}
player.reactionSc.blockSm.ApplyBlock(blockSource);
}

View File

@@ -43,6 +43,9 @@ namespace Cielonos.MainGame.Inventory
{
if (data == null) return null;
if (!data.CanPlay()) return null;
data.RecordPlay();
if (stopPrevious)
{
StopFeedback(data);

View File

@@ -208,8 +208,6 @@ namespace Cielonos.MainGame
Breakthrough.Type.Forced => 4f,
_ => 0f
};
Debug.Log($"[PassionSystem] OnAttackHit 触发,打断类型: {breakthroughType},激情值基础增加量: {baseAmount}%");
IncreasePassion(baseAmount);
}

View File

@@ -26,6 +26,22 @@ namespace SLSUtilities.Feedback
[Title("Editor Settings")]
public string feedbackName;
[Title("Play Limits")]
[LabelText("限制播放频次")]
[Tooltip("如果勾选,将限制此 Feedback 的播放频次。默认每帧最多播放1次")]
public bool limitPlay = true;
[ShowIf("limitPlay")]
[LabelText("最低播放间隔 (秒)")]
[Tooltip("两次播放之间的最低时间间隔(以 unscaledTime 计算)。为 0 代表每帧最多播放 1 次。")]
public float minPlayInterval = 0f;
[System.NonSerialized]
private float _lastPlayTime = -9999f;
[System.NonSerialized]
private int _lastPlayFrame = -1;
/// <summary>
/// 全局默认的时间设置。Clip 可选择覆盖此设置。
/// </summary>
@@ -110,5 +126,34 @@ namespace SLSUtilities.Feedback
FeedbackClip clip = track?.clips.FirstOrDefault(c => c.action.GetType() == typeof(T));
return clip?.action as T;
}
public bool CanPlay()
{
if (!limitPlay) return true;
// 防御性检查:当在 Unity 编辑器中不重新加载域运行游戏,或者重开 Run 导致运行时间倒退时,重置记录
if (Time.unscaledTime < _lastPlayTime)
{
_lastPlayTime = -9999f;
_lastPlayFrame = -1;
}
if (minPlayInterval <= 0f)
{
return Time.frameCount != _lastPlayFrame;
}
else
{
return Time.unscaledTime - _lastPlayTime >= minPlayInterval;
}
}
public void RecordPlay()
{
if (!limitPlay) return;
_lastPlayFrame = Time.frameCount;
_lastPlayTime = Time.unscaledTime;
}
}
}

View File

@@ -40,6 +40,12 @@ namespace SLSUtilities.Feedback
return null;
}
if (!data.CanPlay())
{
return null;
}
data.RecordPlay();
var player = new FeedbackPlayer(data, timeProvider, owner);
player.Play();
_activePlayers.Add(player);