This commit is contained in:
SoulliesOfficial
2025-12-17 04:19:38 -05:00
parent 7c1cb7e8e1
commit d15957c719
4315 changed files with 8260710 additions and 2940 deletions

View File

@@ -5,6 +5,7 @@ using SLSFramework.General;
using SLSUtilities.FunctionalAnimation;
using UnityEngine;
using UnityEngine.Serialization;
using Random = UnityEngine.Random;
namespace Cielonos.MainGame.Characters
{
@@ -57,6 +58,7 @@ namespace Cielonos.MainGame.Characters
protected virtual void LateUpdate()
{
fullBodyFuncAnimSm?.UpdateEvents();
BoneShakeLateUpdate();
}
}
@@ -79,6 +81,90 @@ namespace Cielonos.MainGame.Characters
}
}
public partial class AnimationSubcontrollerBase
{
private class BoneShakeState
{
public Transform bone;
public Vector3 shakeAxis; // 震动轴
// 物理变量
public float currentAngle = 0f; // 当前偏离角度 (位移 x)
public float velocity = 0f; // 当前震动速度 (速度 v)
}
[Header("Bone Shake Settings")]
// 刚度:越大越硬,回弹越快。对于重型机甲,建议 150-300轻型无人机建议 80-150。
public float stiffness = 200f;
// 阻尼:越大停得越快。建议 10-20。如果太小机器人会像果冻一样晃。
public float damping = 15f;
// 冲击力倍率:将受击力度转化为弹簧的初始速度
public float impactForceMultiplier = 500f;
public List<Transform> testShakeBones; // 用于测试的骨骼列表
private List<BoneShakeState> activeShakes = new List<BoneShakeState>();
private void BoneShakeLateUpdate()
{
float dt = Time.deltaTime;
for (int i = activeShakes.Count - 1; i >= 0; i--)
{
var state = activeShakes[i];
if (state.bone == null) {
activeShakes.RemoveAt(i);
continue;
}
// --- 核心:阻尼弹簧物理公式 (Hooke's Law + Damping) ---
// F = -k * x - d * v
// force = -stiffness * displacement - damping * velocity
float force = -stiffness * state.currentAngle - damping * state.velocity;
// a = F / m (假设质量为1简化计算)
// v += a * dt
state.velocity += force * dt;
// x += v * dt
state.currentAngle += state.velocity * dt;
// --- 应用旋转 ---
// 将计算出的角度应用到轴向上
Quaternion shakeRot = Quaternion.AngleAxis(state.currentAngle, state.shakeAxis);
state.bone.localRotation = state.bone.localRotation * shakeRot;
// --- 移除条件 ---
// 当能量非常小速度和位移都接近0时移除节省性能
if (Mathf.Abs(state.currentAngle) < 0.1f && Mathf.Abs(state.velocity) < 0.1f)
{
activeShakes.RemoveAt(i);
}
}
}
public void ApplyBoneShake(Transform hitBone, Vector3 hitDirection, float intensity)
{
var state = activeShakes.Find(x => x.bone == hitBone);
if (state == null)
{
state = new BoneShakeState();
state.bone = hitBone;
activeShakes.Add(state);
}
// 机械特质:受击瞬间不是直接设置位移,而是给予一个巨大的“初速度” (Impulse)
// 这会让骨骼瞬间弹出去,然后被弹簧拉回来,非常有力量感
state.velocity += intensity * impactForceMultiplier;
// 计算震动轴:依旧是垂直于攻击方向
Vector3 axis = Vector3.Cross(hitDirection, Vector3.up).normalized;
if (axis == Vector3.zero) axis = Vector3.right;
state.shakeAxis = axis;
}
}
public partial class AnimationSubcontrollerBase
{
public virtual void RegisterDefaultFunctions()
@@ -116,47 +202,68 @@ namespace Cielonos.MainGame.Characters
return false;
}
public virtual void PlayGetHitMediumAnimation(Vector3 direction = default)
public virtual void PlayGetHitBoneShake(float intensity, Vector3 direction = default)
{
if (direction == default)
{
direction = owner.transform.right;
}
else
{
direction = Quaternion.Euler(0, 90, 0) * direction;
}
foreach (Transform bone in testShakeBones)
{
ApplyBoneShake(bone, direction, intensity);
}
}
protected virtual void PlayGetHitAnimation(string getHitAnimPrefix, out float animDuration, Vector3 direction = default)
{
int fullBodyActionIndex = animator.GetLayerIndex("FullBodyAction");
if (animator.HasState(fullBodyActionIndex, Animator.StringToHash("GetHitMediumFront")))
string getHitFrontAnim = getHitAnimPrefix + "Front";
string getHitAnim = getHitAnimPrefix + "Front";
float normalizedTransitionDuration = 0.1f / animator.GetCurrentAnimatorStateInfo(fullBodyActionIndex).length;
animDuration = 0f;
if (animator.HasState(fullBodyActionIndex, Animator.StringToHash(getHitAnim)))
{
float normalizedTransitionDuration = 0.1f / animator.GetCurrentAnimatorStateInfo(fullBodyActionIndex).length;
if (direction == default)
{
animator.CrossFade("GetHitMediumFront", normalizedTransitionDuration, fullBodyActionIndex, 0);
return;
}
direction.y = 0;
direction = direction.normalized;
float angle = Vector3.SignedAngle(transform.forward, direction, Vector3.up);
if (angle > -45f && angle <= 45f)
string directionStr = angle switch
{
animator.CrossFade("GetHitMediumBack", normalizedTransitionDuration, fullBodyActionIndex, 0);
}
else if (angle > 45f && angle <= 135f)
> -45f and <= 45f => "Back",
> 45f and <= 135f => "Left",
> -135f and <= -45f => "Right",
_ => "Front"
};
getHitAnim = getHitAnimPrefix + directionStr;
if (direction == default || !animator.HasState(fullBodyActionIndex, Animator.StringToHash(getHitAnim)))
{
animator.CrossFade("GetHitMediumLeft", normalizedTransitionDuration, fullBodyActionIndex, 0);
}
else if (angle > -135f && angle <= -45f)
{
animator.CrossFade("GetHitMediumRight", normalizedTransitionDuration, fullBodyActionIndex, 0);
animator.CrossFade(getHitFrontAnim, normalizedTransitionDuration, fullBodyActionIndex, 0);
}
else
{
animator.CrossFade("GetHitMediumFront", normalizedTransitionDuration, fullBodyActionIndex, 0);
animator.CrossFade(getHitAnim, normalizedTransitionDuration, fullBodyActionIndex, 0);
}
animDuration = animator.GetCurrentAnimatorStateInfo(fullBodyActionIndex).length;
}
else if (animator.HasState(fullBodyActionIndex, Animator.StringToHash(getHitAnimPrefix)))
{
getHitAnim = getHitAnimPrefix;
animator.CrossFade(getHitAnim, normalizedTransitionDuration, fullBodyActionIndex, 0);
animDuration = animator.GetCurrentAnimatorStateInfo(fullBodyActionIndex).length;
}
else
{
if (animator.HasState(fullBodyActionIndex, Animator.StringToHash("GetHit")))
{
animator.CrossFade("GetHit", 0.1f, fullBodyActionIndex, 0);
animator.CrossFade("GetHit", normalizedTransitionDuration, fullBodyActionIndex, 0);
animDuration = animator.GetCurrentAnimatorStateInfo(fullBodyActionIndex).length;
}
else
{
@@ -164,5 +271,20 @@ namespace Cielonos.MainGame.Characters
}
}
}
public virtual void PlayGetHitMediumAnimation(out float animDuration, Vector3 direction = default)
{
PlayGetHitAnimation("GetHitMedium", out animDuration, direction);
}
public virtual void PlayGetHitHeavyAnimation(out float animDuration, Vector3 direction = default)
{
PlayGetHitAnimation("GetHitHeavy", out animDuration, direction);
}
public virtual void PlayGetHitDisruptionAnimation(out float animDuration, Vector3 direction = default)
{
PlayGetHitAnimation("GetHitDisruption", out animDuration, direction);
}
}
}

View File

@@ -1,13 +1,15 @@
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Serialization;
namespace Cielonos.MainGame.Characters
{
public class BodyPartsSubcontroller : SubcontrollerBase<CharacterBase>
{
[Title("Main Parts")]
public Transform centerPoint;
[FormerlySerializedAs("centerPoint")] [Title("Main Parts")]
public Transform flexibleCenterPoint;
public Transform staticCenterPoint;
public Transform footPoint;
public Transform head;
public Transform leftHand;

View File

@@ -48,6 +48,32 @@ namespace Cielonos.MainGame.Characters
{
characterTransform.DOLookAt(target.transform.position, duration, AxisConstraint.Y);
}
public void TurnToDirection(Vector3 direction, float duration = 0f)
{
Vector3 dashRotation = Vector3.zero;
float angle = Vector3.SignedAngle(Vector3.forward, direction, Vector3.up);
if (owner is Player player)
{
dashRotation.y = player.viewSc.isLockedOn
? player.viewSc.cameraRotationSm.cinemachineEndLockYaw + angle
: player.viewSc.cameraRotationSm.cinemachineTargetYaw + angle;
}
else
{
dashRotation = new Vector3(0, angle, 0);
}
if (duration > 0)
{
characterTransform.DORotateQuaternion(Quaternion.Euler(dashRotation), duration);
}
else
{
characterTransform.rotation = Quaternion.Euler(dashRotation);
}
}
}
public partial class MovementSubcontrollerBase

View File

@@ -133,8 +133,27 @@ namespace Cielonos.MainGame.Characters
{
getHitBlinkTween?.Kill(true);
getHitBlinkTween = DOTween.Sequence();
getHitBlinkTween.OnPlay(() =>
foreach (Material mat in baseRenderMaterials)
{
Tweener rimTween = mat.DOVector(new Vector4(1, 1, 4, 1), "_RimParams", 0.5f)
.From(new Vector4(0, 1, 4, 1))
.OnPlay(() =>
{
mat.EnableKeyword("_RIM");
})
.SetEase(Ease.OutQuad)
.OnComplete(() =>
{
mat.DisableKeyword("_RIM");
});
getHitBlinkTween.Join(rimTween);
}
getHitBlinkTween.Play();
/*getHitBlinkTween.OnPlay(() =>
{
effectContainers["GetHitBlink"].SetActive(true);
});
@@ -157,7 +176,7 @@ namespace Cielonos.MainGame.Characters
getHitBlinkTween.OnComplete(() =>
{
effectContainers["GetHitBlink"].SetActive(false);
});
});*/
getHitBlinkTween.Play();
}