feat(dream): 实现风筝镜头补偿与虚焦驱动
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: KiteFocusSprite
|
||||
m_Shader: {fileID: 4800000, guid: fb0a8d34c65ffb540b0e1f9538285d18, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _BlurAmount: 0
|
||||
- _BlurSize: 0.004
|
||||
- _ChromaticFringe: 0.14
|
||||
- _ColorMask: 15
|
||||
- _DefocusBloom: 0.32
|
||||
- _DefocusVeil: 0.055
|
||||
- _HaloStrength: 0.22
|
||||
- _Stencil: 0
|
||||
- _StencilComp: 8
|
||||
- _StencilOp: 0
|
||||
- _StencilReadMask: 255
|
||||
- _StencilWriteMask: 255
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 78265ded39f017d45a2afc117effab89
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,195 @@
|
||||
Shader "AIBIS/KiteFocusSprite"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
|
||||
_Color ("Tint", Color) = (1, 1, 1, 1)
|
||||
|
||||
[Header(Focus Blur)]
|
||||
_BlurAmount ("Blur Amount", Range(0, 1)) = 0
|
||||
_BlurSize ("Blur Size", Range(0, 0.05)) = 0.012
|
||||
_DefocusBloom ("Defocus Highlight Bloom", Range(0, 1)) = 0.32
|
||||
_HaloStrength ("Large Circle Halo", Range(0, 0.6)) = 0.22
|
||||
_ChromaticFringe ("Lens Color Fringe", Range(0, 0.6)) = 0.14
|
||||
_DefocusVeil ("Defocus White Veil", Range(0, 0.3)) = 0.055
|
||||
|
||||
// Required for SpriteMask (same contract as Sprites-Default / UI.Mask)
|
||||
[HideInInspector][PerRendererData] _StencilComp ("Stencil Comparison", Float) = 8
|
||||
[HideInInspector][PerRendererData] _Stencil ("Stencil ID", Float) = 0
|
||||
[HideInInspector][PerRendererData] _StencilOp ("Stencil Operation", Float) = 0
|
||||
[HideInInspector][PerRendererData] _StencilWriteMask ("Stencil Write Mask", Float) = 255
|
||||
[HideInInspector][PerRendererData] _StencilReadMask ("Stencil Read Mask", Float) = 255
|
||||
[HideInInspector] _ColorMask ("Color Mask", Float) = 15
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"Queue" = "Transparent"
|
||||
"IgnoreProjector" = "True"
|
||||
"RenderType" = "Transparent"
|
||||
"PreviewType" = "Plane"
|
||||
"CanUseSpriteAtlas" = "True"
|
||||
}
|
||||
|
||||
Cull Off
|
||||
Lighting Off
|
||||
ZWrite Off
|
||||
Blend One OneMinusSrcAlpha
|
||||
ColorMask [_ColorMask]
|
||||
|
||||
Stencil
|
||||
{
|
||||
Ref [_Stencil]
|
||||
Comp [_StencilComp]
|
||||
Pass [_StencilOp]
|
||||
ReadMask [_StencilReadMask]
|
||||
WriteMask [_StencilWriteMask]
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma target 3.0
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float4 color : COLOR;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 vertex : SV_POSITION;
|
||||
fixed4 color : COLOR;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_TexelSize;
|
||||
fixed4 _Color;
|
||||
float _BlurAmount;
|
||||
float _BlurSize;
|
||||
float _DefocusBloom;
|
||||
float _HaloStrength;
|
||||
float _ChromaticFringe;
|
||||
float _DefocusVeil;
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.color = v.color * _Color;
|
||||
o.uv = v.uv;
|
||||
return o;
|
||||
}
|
||||
|
||||
half4 sampleTex(float2 uv)
|
||||
{
|
||||
// 边界外按透明,避免 saturate 夹边造成硬切
|
||||
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)
|
||||
return half4(0, 0, 0, 0);
|
||||
return tex2D(_MainTex, uv);
|
||||
}
|
||||
|
||||
half4 samplePremultiplied(float2 uv)
|
||||
{
|
||||
half4 color = sampleTex(uv);
|
||||
color.rgb *= color.a;
|
||||
return color;
|
||||
}
|
||||
|
||||
// 圆形光圈核:比高斯更接近真实镜头的弥散圆,且不会出现十字形拖影。
|
||||
half4 ApertureDisc(float2 uv, float radius)
|
||||
{
|
||||
half4 result = samplePremultiplied(uv) * 0.12;
|
||||
const half w = 0.044;
|
||||
|
||||
// 内圈
|
||||
result += samplePremultiplied(uv + float2( 0.38, 0.00) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.38, 0.00) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.00, 0.38) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.00, -0.38) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.27, 0.27) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.27, 0.27) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.27, -0.27) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.27, -0.27) * radius) * w;
|
||||
|
||||
// 外圈使用不规则角度,避免规则采样形成振铃或星芒。
|
||||
result += samplePremultiplied(uv + float2( 0.98, 0.05) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.82, 0.55) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.43, 0.90) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.16, 0.98) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.69, 0.72) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.99, 0.10) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.80, -0.58) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.36, -0.92) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.22, -0.97) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.72, -0.68) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2( 0.94, -0.31) * radius) * w;
|
||||
result += samplePremultiplied(uv + float2(-0.48, 0.86) * radius) * w;
|
||||
return result;
|
||||
}
|
||||
|
||||
half4 WideHalo(float2 uv, float radius)
|
||||
{
|
||||
half4 result = 0;
|
||||
result += samplePremultiplied(uv + float2( 1.00, 0.00) * radius);
|
||||
result += samplePremultiplied(uv + float2( 0.71, 0.71) * radius);
|
||||
result += samplePremultiplied(uv + float2( 0.00, 1.00) * radius);
|
||||
result += samplePremultiplied(uv + float2(-0.71, 0.71) * radius);
|
||||
result += samplePremultiplied(uv + float2(-1.00, 0.00) * radius);
|
||||
result += samplePremultiplied(uv + float2(-0.71, -0.71) * radius);
|
||||
result += samplePremultiplied(uv + float2( 0.00, -1.00) * radius);
|
||||
result += samplePremultiplied(uv + float2( 0.71, -0.71) * radius);
|
||||
return result * 0.125;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f i) : SV_Target
|
||||
{
|
||||
float blurAmt = saturate(_BlurAmount);
|
||||
half4 sharp = sampleTex(i.uv);
|
||||
|
||||
if (blurAmt < 0.001)
|
||||
{
|
||||
half4 col = sharp * i.color;
|
||||
col.rgb *= col.a;
|
||||
return col;
|
||||
}
|
||||
|
||||
float2 texel = max(abs(_MainTex_TexelSize.xy), float2(1e-5, 1e-5));
|
||||
float radius = (length(texel) * 0.5 + _BlurSize) * (0.28 + blurAmt * 1.72);
|
||||
half4 disc = ApertureDisc(i.uv, radius);
|
||||
half4 halo = WideHalo(i.uv, radius * 1.85);
|
||||
half4 blurred = lerp(disc, halo, saturate(_HaloStrength * blurAmt));
|
||||
|
||||
// 很轻的 RGB 焦平面差异,避免单纯软件模糊的塑料感。
|
||||
float2 fringe = float2(0.73, 0.41) * radius * _ChromaticFringe * blurAmt;
|
||||
half4 fringeR = samplePremultiplied(i.uv + fringe);
|
||||
half4 fringeB = samplePremultiplied(i.uv - fringe);
|
||||
blurred.r = lerp(blurred.r, fringeR.r, _ChromaticFringe * blurAmt);
|
||||
blurred.b = lerp(blurred.b, fringeB.b, _ChromaticFringe * blurAmt);
|
||||
|
||||
// 参考片中的失焦会让亮部扩散并稍微泛白,但保留在物体 alpha 内。
|
||||
half luminance = dot(blurred.rgb, half3(0.2126, 0.7152, 0.0722));
|
||||
half highlight = saturate(luminance - blurred.a * 0.42);
|
||||
blurred.rgb += highlight * _DefocusBloom * blurAmt;
|
||||
blurred.rgb += blurred.a * _DefocusVeil * blurAmt;
|
||||
|
||||
half4 sharpPremul = sharp;
|
||||
sharpPremul.rgb *= sharpPremul.a;
|
||||
float mixT = smoothstep(0.0, 1.0, blurAmt);
|
||||
half4 col = lerp(sharpPremul, blurred, mixT);
|
||||
col.rgb *= i.color.rgb * i.color.a;
|
||||
col.a *= i.color.a;
|
||||
return col;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb0a8d34c65ffb540b0e1f9538285d18
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+65
-1
@@ -1143,6 +1143,71 @@ MonoBehaviour:
|
||||
_spriteRenderer: {fileID: 218986884}
|
||||
_backgroundSpriteRenderer: {fileID: 969796818}
|
||||
_largeSpriteRenderer: {fileID: 762853994}
|
||||
_kiteFocusMaterial: {fileID: 2100000, guid: 78265ded39f017d45a2afc117effab89, type: 2}
|
||||
_kiteWindSettings:
|
||||
calmFloatAmp: 0.53
|
||||
calmFloatFreq: 0.065
|
||||
steadyWindOffset: 0.45
|
||||
weakWindDrop: 0.32
|
||||
edgeWindThreshold: 0.48
|
||||
edgeTravel: 3.3
|
||||
edgeTravelY: 1.35
|
||||
calmMotionSmoothTime: 1.2
|
||||
stormMotionSmoothTime: 0.68
|
||||
maxTravelSpeed: 3.2
|
||||
maxTetherAngle: 62
|
||||
tetherAngularStiffness: 2.4
|
||||
tetherAngularDamping: 3.35
|
||||
maxAngularAcceleration: 68
|
||||
maxAngularSpeed: 48
|
||||
tetherArcDrop: 1.15
|
||||
verticalGustSmoothTime: 0.85
|
||||
superWindThreshold: 0.86
|
||||
bigWindHoldMin: 2.6
|
||||
bigWindHoldMax: 4.5
|
||||
superWindHoldMin: 1.7
|
||||
superWindHoldMax: 3
|
||||
doubleEscapeGapMin: 0.28
|
||||
doubleEscapeGapMax: 0.6
|
||||
windPressureAmp: 0.36
|
||||
windPressureFrequency: 0.11
|
||||
windPressureVerticalRatio: 0.48
|
||||
windPressurePoseGain: 3.2
|
||||
heightDurationScale: 1.3
|
||||
heightArcPerLevel: 0.055
|
||||
heightArcMax: 0.42
|
||||
heightArcSmoothTime: 0.62
|
||||
leanAmp: 3.2
|
||||
bankFromVel: 1.5
|
||||
pitchFromHeightVel: 1.6
|
||||
yawFromLateralVel: 1.15
|
||||
flutterAmp: 0.7
|
||||
poseSmoothTime: 0.34
|
||||
maxPoseAngle: 7
|
||||
maxPerspectiveTilt: 5.5
|
||||
windSmoothTime: 0.45
|
||||
altitudeWindGain: 0.18
|
||||
tailLagPhase: 0.9
|
||||
tailGain: 1.2
|
||||
_kiteCameraSettings:
|
||||
reactionLatency: 0.34
|
||||
smoothTimePos: 0.92
|
||||
stormFollowMultiplier: 0.63
|
||||
smoothTimeZoom: 1.18
|
||||
maxZoom: 3.2
|
||||
maxPan: 4.5
|
||||
_kiteFocusSettings:
|
||||
maxBlur: 0.68
|
||||
blurSize: 0.011
|
||||
posErrorRef: 0.7
|
||||
zoomErrorRef: 0.2
|
||||
blurDeadZone: 0.3
|
||||
blurInSpeed: 3.5
|
||||
blurOutSpeed: 0.95
|
||||
settleEnterThreshold: 0.48
|
||||
settleDuration: 0.46
|
||||
settleBump: 0.08
|
||||
settlePhaseRatios: {x: 0.5, y: 0.2, z: 0.3}
|
||||
--- !u!1 &969796816
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -2288,7 +2353,6 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 0e1a1832f60f72e449b07f1298eefa53, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
bubbleSlotGroup: {fileID: 676277672}
|
||||
--- !u!1 &1847534532
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1290ba4dc7b8bfa40b61dd3bb1372cf0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -569,43 +569,47 @@ namespace AibisDream
|
||||
|
||||
#region 风筝 Rig
|
||||
|
||||
// 风筝段落弃用切图(D2S风筝1/2/3),改为单张风筝图 + 三层 Transform 连续驱动:
|
||||
// Kite Rig(高度补间:缩放+位移)→ Sway(常驻风况循环)→ Accent(一次性顿挫 + Renderer)
|
||||
// 三层各持有独立 Tween,互不覆盖。白色底图挂在独立的静态 renderer 上,不随高度缩放。
|
||||
// Kite Camera(虚拟镜头完全补偿)→ Rig(高度+漂移)→ Sway(鱼式流体摆动)→ Accent(DOTween 顿挫)
|
||||
// 底图 / Mask 保持静态,不进镜头节点。
|
||||
private const string KiteSpritePicName = "D2S风筝1_风筝层";
|
||||
private const string KiteBasePicName = "D2S风筝1_底图";
|
||||
private const float KiteMaxHeight = 13f;
|
||||
/// <summary>每升高 1 点高度,缩放乘以该系数。</summary>
|
||||
private const float KiteScalePerHeight = 0.84f;
|
||||
/// <summary>缩放下限:最远处的风筝也不小于该比例。</summary>
|
||||
private const float KiteMinScaleFactor = 0.12f;
|
||||
/// <summary>高度最大时风筝相对基准位置的漂移量(向上飘 + 少量横移)。</summary>
|
||||
private static readonly Vector3 KiteTopDrift = new Vector3(0.5f, 1.2f, 0f);
|
||||
|
||||
[Header("风筝 / 对焦材质")]
|
||||
[SerializeField] private Material _kiteFocusMaterial;
|
||||
[SerializeField] private KiteWindSettings _kiteWindSettings = new KiteWindSettings();
|
||||
[SerializeField] private KiteCameraSettings _kiteCameraSettings = new KiteCameraSettings();
|
||||
[SerializeField] private KiteFocusSettings _kiteFocusSettings = new KiteFocusSettings();
|
||||
|
||||
private Transform _kiteCameraNode;
|
||||
private Transform _kiteRootPivot;
|
||||
private Transform _kiteSwayPivot;
|
||||
private SpriteRenderer _kiteRenderer;
|
||||
private SpriteRenderer _kiteBaseRenderer;
|
||||
private SpriteMask _kiteMask;
|
||||
private DG.Tweening.Sequence _kiteHeightSequence;
|
||||
private DG.Tweening.Sequence _kiteSwaySequence;
|
||||
private KiteRigDriver _kiteDriver;
|
||||
private DG.Tweening.Sequence _kiteAccentSequence;
|
||||
private Tween _kiteFadeTween;
|
||||
private float _kiteHeight;
|
||||
/// <summary>当前乱度 0~1,由 kite_wind 显式设定;kite_state 沿用上次的值(粘滞)。</summary>
|
||||
private float _kiteTurbulence;
|
||||
private bool _kiteSpriteLoaded;
|
||||
private bool _kiteBaseSpriteLoaded;
|
||||
|
||||
private bool IsKiteShowing => _kiteRootPivot != null && _kiteRootPivot.gameObject.activeSelf;
|
||||
private bool IsKiteShowing =>
|
||||
_kiteCameraNode != null && _kiteCameraNode.gameObject.activeSelf;
|
||||
|
||||
private void EnsureKiteRig()
|
||||
{
|
||||
if (_kiteRootPivot != null || _spriteRenderer == null) return;
|
||||
|
||||
var parent = _spriteRenderer.transform.parent;
|
||||
|
||||
var cameraObject = new GameObject("Kite Camera");
|
||||
cameraObject.transform.SetParent(parent);
|
||||
cameraObject.transform.localPosition = _smallBaseLocalPosition;
|
||||
cameraObject.transform.localRotation = Quaternion.identity;
|
||||
cameraObject.transform.localScale = Vector3.one;
|
||||
|
||||
var root = new GameObject("Kite Rig");
|
||||
root.transform.SetParent(_spriteRenderer.transform.parent);
|
||||
root.transform.localPosition = _smallBaseLocalPosition;
|
||||
root.transform.SetParent(cameraObject.transform, false);
|
||||
root.transform.localPosition = Vector3.zero;
|
||||
root.transform.localRotation = _smallBaseLocalRotation;
|
||||
root.transform.localScale = _smallBaseLocalScale;
|
||||
|
||||
@@ -615,20 +619,21 @@ namespace AibisDream
|
||||
var accent = new GameObject("Kite Accent");
|
||||
accent.transform.SetParent(sway.transform, false);
|
||||
|
||||
// 白色底图:独立静态节点,不随高度层缩放
|
||||
// 白色底图:独立静态节点,不随镜头/高度缩放
|
||||
var baseObject = new GameObject("Kite Base");
|
||||
baseObject.transform.SetParent(_spriteRenderer.transform.parent);
|
||||
baseObject.transform.SetParent(parent);
|
||||
baseObject.transform.localPosition = _smallBaseLocalPosition;
|
||||
baseObject.transform.localRotation = _smallBaseLocalRotation;
|
||||
baseObject.transform.localScale = _smallBaseLocalScale;
|
||||
|
||||
// 遮罩:把风筝层限制在底图(天空)范围内,不会飘出画框
|
||||
// 遮罩:把风筝层限制在底图(天空)范围内
|
||||
var maskObject = new GameObject("Kite Mask");
|
||||
maskObject.transform.SetParent(_spriteRenderer.transform.parent);
|
||||
maskObject.transform.SetParent(parent);
|
||||
maskObject.transform.localPosition = _smallBaseLocalPosition;
|
||||
maskObject.transform.localRotation = _smallBaseLocalRotation;
|
||||
maskObject.transform.localScale = _smallBaseLocalScale;
|
||||
|
||||
_kiteCameraNode = cameraObject.transform;
|
||||
_kiteRootPivot = root.transform;
|
||||
_kiteSwayPivot = sway.transform;
|
||||
_kiteRenderer = accent.AddComponent<SpriteRenderer>();
|
||||
@@ -640,53 +645,52 @@ namespace AibisDream
|
||||
_kiteMask.isCustomRangeActive = true;
|
||||
_kiteMask.enabled = false;
|
||||
|
||||
root.SetActive(false);
|
||||
EnsureKiteFocusMaterial();
|
||||
_kiteDriver = cameraObject.AddComponent<KiteRigDriver>();
|
||||
_kiteDriver.Configure(
|
||||
_kiteCameraNode,
|
||||
_kiteRootPivot,
|
||||
_kiteSwayPivot,
|
||||
_kiteRenderer,
|
||||
_smallBaseLocalPosition,
|
||||
_smallBaseLocalRotation,
|
||||
_smallBaseLocalScale,
|
||||
_kiteWindSettings,
|
||||
_kiteCameraSettings,
|
||||
_kiteFocusSettings,
|
||||
_kiteFocusMaterial);
|
||||
_kiteDriver.enabled = false;
|
||||
|
||||
cameraObject.SetActive(false);
|
||||
baseObject.SetActive(false);
|
||||
_kiteRenderer.SetAlpha(0);
|
||||
_kiteBaseRenderer.SetAlpha(0);
|
||||
}
|
||||
|
||||
private static float KiteScaleFactor(float height) =>
|
||||
Mathf.Max(Mathf.Pow(KiteScalePerHeight, height), KiteMinScaleFactor);
|
||||
private void EnsureKiteFocusMaterial()
|
||||
{
|
||||
if (_kiteFocusMaterial != null) return;
|
||||
|
||||
private Vector3 KitePosition(float height) =>
|
||||
_smallBaseLocalPosition + KiteTopDrift * (height / KiteMaxHeight);
|
||||
var shader = Shader.Find("AIBIS/KiteFocusSprite");
|
||||
if (shader == null)
|
||||
{
|
||||
Debug.LogWarning("[SpriteShowcase] 找不到 AIBIS/KiteFocusSprite,风筝虚焦不可用。", this);
|
||||
return;
|
||||
}
|
||||
|
||||
private Vector3 KiteScale(float height) => _smallBaseLocalScale * KiteScaleFactor(height);
|
||||
|
||||
/// <summary>极高处降低不透明度,配合“几乎看不见”的文本。</summary>
|
||||
private static float KiteAlpha(float height) =>
|
||||
height <= 8f ? 1f : Mathf.Lerp(1f, 0.75f, (height - 8f) / (KiteMaxHeight - 8f));
|
||||
_kiteFocusMaterial = new Material(shader) { name = "KiteFocusSprite (Runtime)" };
|
||||
}
|
||||
|
||||
private void KillKiteTweens()
|
||||
{
|
||||
_kiteHeightSequence?.Kill();
|
||||
_kiteHeightSequence = null;
|
||||
_kiteSwaySequence?.Kill();
|
||||
_kiteSwaySequence = null;
|
||||
_kiteAccentSequence?.Kill();
|
||||
_kiteAccentSequence = null;
|
||||
_kiteFadeTween?.Kill();
|
||||
_kiteFadeTween = null;
|
||||
}
|
||||
|
||||
private void ApplyKiteStateImmediate(float height)
|
||||
{
|
||||
_kiteRootPivot.localPosition = KitePosition(height);
|
||||
_kiteRootPivot.localRotation = _smallBaseLocalRotation;
|
||||
_kiteRootPivot.localScale = KiteScale(height);
|
||||
_kiteSwayPivot.localPosition = Vector3.zero;
|
||||
_kiteSwayPivot.localRotation = Quaternion.identity;
|
||||
_kiteRenderer.transform.localPosition = Vector3.zero;
|
||||
_kiteRenderer.transform.localRotation = Quaternion.identity;
|
||||
_kiteDriver?.ResetAndSleep();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示风筝 Rig。已显示时等价于 <see cref="SetKiteState"/>(幂等)。
|
||||
/// </summary>
|
||||
/// <param name="height">风筝高度(对应 Yarn 变量 $h)</param>
|
||||
/// <param name="wind">风向(对应 Yarn 变量 $wind:1 强 / 0 无 / -1 弱)</param>
|
||||
/// <param name="duration">保留参数以兼容既有调用;出现不再淡入,仅用于互斥隐藏其它图</param>
|
||||
public IEnumerator ShowKite(float height, int wind, float duration = 0.35f)
|
||||
{
|
||||
if (IsLargeShowing)
|
||||
@@ -700,7 +704,7 @@ namespace AibisDream
|
||||
}
|
||||
|
||||
EnsureKiteRig();
|
||||
if (_kiteRenderer == null) yield break;
|
||||
if (_kiteRenderer == null || _kiteDriver == null) yield break;
|
||||
|
||||
height = Mathf.Clamp(height, 0f, KiteMaxHeight);
|
||||
|
||||
@@ -711,15 +715,19 @@ namespace AibisDream
|
||||
}
|
||||
|
||||
KillKiteTweens();
|
||||
ApplyKiteStateImmediate(height);
|
||||
_kiteHeight = height;
|
||||
_kiteRootPivot.gameObject.SetActive(true);
|
||||
_kiteCameraNode.gameObject.SetActive(true);
|
||||
_kiteBaseRenderer.gameObject.SetActive(true);
|
||||
|
||||
if (!_kiteSpriteLoaded)
|
||||
{
|
||||
yield return LoadDreamSpriteInto(_kiteRenderer, KiteSpritePicName);
|
||||
_kiteSpriteLoaded = _kiteRenderer.sprite != null;
|
||||
// 贴图加载后重新赋 focus 材质(Load 可能换过 material)
|
||||
EnsureKiteFocusMaterial();
|
||||
if (_kiteFocusMaterial != null)
|
||||
{
|
||||
_kiteRenderer.material = _kiteFocusMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_kiteBaseSpriteLoaded)
|
||||
@@ -738,189 +746,36 @@ namespace AibisDream
|
||||
_kiteMask.enabled = true;
|
||||
}
|
||||
|
||||
_kiteTurbulence = 0f;
|
||||
PlayKiteSway(wind);
|
||||
// 不做淡入:背景是硬切的,风筝单独 fade 反而突兀,直接以目标透明度出现
|
||||
_kiteDriver.Wake(height, wind);
|
||||
_kiteBaseRenderer.SetAlpha(1f);
|
||||
_kiteRenderer.SetAlpha(KiteAlpha(height));
|
||||
_kiteRenderer.SetAlpha(KiteRigDriver.Alpha(height));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 高度补间(每次选择的主反馈)+ 切换风况循环。
|
||||
/// 高度 SmoothDamp + 切换风向。乱度粘滞由 driver 保留。
|
||||
/// </summary>
|
||||
public void SetKiteState(float height, int wind, float duration = 0.9f)
|
||||
{
|
||||
if (!IsKiteShowing) return;
|
||||
if (!IsKiteShowing || _kiteDriver == null) return;
|
||||
|
||||
height = Mathf.Clamp(height, 0f, KiteMaxHeight);
|
||||
_kiteHeight = height;
|
||||
|
||||
_kiteHeightSequence?.Kill();
|
||||
var seq = DOTween.Sequence();
|
||||
seq.Append(_kiteRootPivot.DOLocalMove(KitePosition(height), duration).SetEase(Ease.InOutSine));
|
||||
seq.Join(_kiteRootPivot.DOScale(KiteScale(height), duration).SetEase(Ease.InOutSine));
|
||||
_kiteHeightSequence = seq;
|
||||
|
||||
_kiteFadeTween?.Kill();
|
||||
_kiteFadeTween = _kiteRenderer.DOFade(KiteAlpha(height), duration);
|
||||
|
||||
PlayKiteSway(wind);
|
||||
_kiteDriver.SetHeight(height, duration);
|
||||
_kiteDriver.SetWind(wind);
|
||||
}
|
||||
|
||||
/// <summary>仅切换风况循环(选择前 telegraph 风向)。</summary>
|
||||
/// <param name="wind">风向:1 强 / 0 无 / -1 弱</param>
|
||||
/// <param name="turbulence">乱度 0~1;负数或省略表示平稳。设定后粘滞,kite_state 沿用。</param>
|
||||
/// <summary>仅切换风况(选择前 telegraph 风向)。</summary>
|
||||
/// <param name="turbulence">乱度 0~1;负数或省略表示平稳(清零)。设定后粘滞,kite_state 沿用。</param>
|
||||
public void SetKiteWind(int wind, float turbulence = -1f)
|
||||
{
|
||||
if (!IsKiteShowing) return;
|
||||
_kiteTurbulence = turbulence >= 0f ? Mathf.Clamp01(turbulence) : 0f;
|
||||
PlayKiteSway(wind);
|
||||
}
|
||||
|
||||
/// <summary>屏幕可读性补偿:高度层缩小时适度放大局部位移(开方衰减),避免远处几乎不动。</summary>
|
||||
private float KiteSwayComp() =>
|
||||
Mathf.Clamp(1f / Mathf.Sqrt(KiteScaleFactor(_kiteHeight)), 1f, 3f);
|
||||
|
||||
/// <summary>
|
||||
/// 常驻风况循环。位移在高度层的子空间里会随缩放变小,用 comp 做部分补偿保证远处仍有可读的移动。
|
||||
/// 平稳(乱度 0):沿 CatmullRom 曲线大而缓地漫游,绝不抖。
|
||||
/// 乱流(乱度 >0):转交 <see cref="PlayKiteGust"/>,每一阵的方向、力度、间隔都随机。
|
||||
/// </summary>
|
||||
private void PlayKiteSway(int wind)
|
||||
{
|
||||
_kiteSwaySequence?.Kill();
|
||||
_kiteSwaySequence = null;
|
||||
|
||||
if (wind > 0 && _kiteTurbulence > 0.01f)
|
||||
{
|
||||
PlayKiteGust();
|
||||
return;
|
||||
}
|
||||
|
||||
var tr = _kiteSwayPivot;
|
||||
var comp = KiteSwayComp();
|
||||
// 幅度随高度补偿放大后,周期也同步拉长:漂移更明显,但速度不变快,保持轻松
|
||||
var drift = 1f + (comp - 1f) * 0.4f;
|
||||
var seq = DOTween.Sequence();
|
||||
|
||||
if (wind > 0)
|
||||
{
|
||||
// 稳定的风:顶着风侧倾,沿弧线缓慢巡游(位移为主,平稳无抖)
|
||||
var path = new[]
|
||||
{
|
||||
new Vector3(0.26f, 0.15f, 0f) * comp,
|
||||
new Vector3(0.46f, 0.05f, 0f) * comp,
|
||||
new Vector3(0.33f, 0.24f, 0f) * comp,
|
||||
new Vector3(0.11f, 0.11f, 0f) * comp,
|
||||
};
|
||||
var dur = 9.2f * drift;
|
||||
seq.Append(tr.DOLocalPath(path, dur, PathType.CatmullRom).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -7.5f), dur / 4f).SetEase(Ease.InOutSine)
|
||||
.SetLoops(4, LoopType.Yoyo));
|
||||
}
|
||||
else if (wind == 0)
|
||||
{
|
||||
// 平稳无风:自由自在地沿曲线漫游,幅度加大、节奏放缓
|
||||
var path = new[]
|
||||
{
|
||||
new Vector3(0.3f, 0.16f, 0f) * comp,
|
||||
new Vector3(0.08f, 0.36f, 0f) * comp,
|
||||
new Vector3(-0.28f, 0.24f, 0f) * comp,
|
||||
new Vector3(-0.38f, 0.03f, 0f) * comp,
|
||||
};
|
||||
var dur = 12f * drift;
|
||||
seq.Append(tr.DOLocalPath(path, dur, PathType.CatmullRom).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, 4f), dur / 4f).SetEase(Ease.InOutSine)
|
||||
.SetLoops(4, LoopType.Yoyo));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 风弱:沿弧线缓缓向下飘
|
||||
var path = new[]
|
||||
{
|
||||
new Vector3(0.12f, -0.14f, 0f) * comp,
|
||||
new Vector3(0.03f, -0.28f, 0f) * comp,
|
||||
new Vector3(-0.17f, -0.21f, 0f) * comp,
|
||||
};
|
||||
var dur = 7.8f * drift;
|
||||
seq.Append(tr.DOLocalPath(path, dur, PathType.CatmullRom).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, 3f), dur / 3f).SetEase(Ease.InOutSine)
|
||||
.SetLoops(3, LoopType.Yoyo));
|
||||
}
|
||||
|
||||
seq.SetLoops(-1, LoopType.Yoyo);
|
||||
_kiteSwaySequence = seq;
|
||||
if (!IsKiteShowing || _kiteDriver == null) return;
|
||||
// 与旧语义对齐:省略/负数 → 平稳(乱度归零);显式传入 ≥0 则设定并粘滞
|
||||
float t = turbulence >= 0f ? Mathf.Clamp01(turbulence) : 0f;
|
||||
_kiteDriver.SetWind(wind, t);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单次阵风,播完通过 OnComplete 用一组新的随机参数接下一阵——节奏永不重复。
|
||||
/// 猛拽段 X 快、Y 慢半拍(不同时长+缓动),走出弧线而不是直线。
|
||||
/// 乱度越高越狂:间隔与荡回时间大幅压缩、拽得更快更斜,
|
||||
/// 甩过头弹回之外,还有概率来不及回稳就被反向再抽一鞭。
|
||||
/// </summary>
|
||||
private void PlayKiteGust()
|
||||
{
|
||||
if (!IsKiteShowing) return;
|
||||
|
||||
_kiteSwaySequence?.Kill();
|
||||
|
||||
var tr = _kiteSwayPivot;
|
||||
var storm = _kiteTurbulence;
|
||||
var amp = KiteSwayComp() * (1f + storm * 1.15f);
|
||||
// 高乱度整体提速:猛拽更快、几乎没有喘息
|
||||
var frantic = Mathf.Lerp(1f, 0.7f, storm);
|
||||
|
||||
// 阵风方向:多数顺着主风向,偶尔反向兜一下;上下随机
|
||||
var side = UnityEngine.Random.value < 0.72f ? 1f : -1f;
|
||||
var jerk = new Vector3(
|
||||
UnityEngine.Random.Range(0.34f, 0.58f) * side,
|
||||
UnityEngine.Random.Range(-0.1f, 0.3f),
|
||||
0f) * amp;
|
||||
var jerkDur = UnityEngine.Random.Range(0.14f, 0.26f) * frantic;
|
||||
var rot = (14f + storm * 18f) * UnityEngine.Random.Range(0.7f, 1.15f) * -side;
|
||||
var settle = jerk * UnityEngine.Random.Range(0.15f, 0.4f);
|
||||
var settleDur = UnityEngine.Random.Range(0.7f, 1.2f) * Mathf.Lerp(1f, 0.45f, storm);
|
||||
var rest = Mathf.Lerp(
|
||||
UnityEngine.Random.Range(0.35f, 0.75f),
|
||||
UnityEngine.Random.Range(0.02f, 0.1f),
|
||||
storm);
|
||||
|
||||
var seq = DOTween.Sequence();
|
||||
seq.AppendInterval(rest);
|
||||
// 猛地被拽走:X 快 Y 慢,轨迹成弧
|
||||
seq.Append(tr.DOLocalMoveX(jerk.x, jerkDur).SetEase(Ease.OutCubic));
|
||||
seq.Join(tr.DOLocalMoveY(jerk.y, jerkDur * UnityEngine.Random.Range(1.4f, 1.9f)).SetEase(Ease.OutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, rot), jerkDur * 1.2f).SetEase(Ease.OutCubic));
|
||||
// 失控:甩过头再弹回来一下
|
||||
if (storm > 0.7f && UnityEngine.Random.value < 0.6f)
|
||||
{
|
||||
seq.Append(tr.DOLocalRotate(new Vector3(0f, 0f, -rot * 0.65f), 0.22f).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalMoveX(jerk.x * 0.7f, 0.22f).SetEase(Ease.InOutSine));
|
||||
}
|
||||
// 更失控:来不及回稳,就被反方向再抽一鞭
|
||||
if (storm > 0.6f && UnityEngine.Random.value < 0.5f)
|
||||
{
|
||||
var whipDur = UnityEngine.Random.Range(0.12f, 0.2f);
|
||||
seq.Append(tr.DOLocalMoveX(-jerk.x * UnityEngine.Random.Range(0.5f, 0.9f), whipDur)
|
||||
.SetEase(Ease.OutCubic));
|
||||
seq.Join(tr.DOLocalMoveY(UnityEngine.Random.Range(-0.16f, 0.2f) * amp, whipDur * 1.5f)
|
||||
.SetEase(Ease.OutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -rot * UnityEngine.Random.Range(0.7f, 1.1f)), whipDur * 1.3f)
|
||||
.SetEase(Ease.OutCubic));
|
||||
}
|
||||
// 荡回来(X/Y 不同步 → 回程也是弧线;高乱度下这一步也短促)
|
||||
seq.Append(tr.DOLocalMoveX(settle.x, settleDur).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalMoveY(settle.y, settleDur * UnityEngine.Random.Range(0.7f, 0.95f)).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, rot * UnityEngine.Random.Range(-0.3f, 0.15f)), settleDur)
|
||||
.SetEase(Ease.InOutSine));
|
||||
seq.OnComplete(PlayKiteGust);
|
||||
_kiteSwaySequence = seq;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一次性顿挫动效,叠加在 Accent 层上,结束回到原位,不打断高度/风况补间。
|
||||
/// 支持:lift(上冲回落)/ sink(下坠沉降)/ taut(前扯抖动)/ drop(猛地下坠)/ flutter(原地挣扎扑腾)
|
||||
/// / wrench(侧面兜住猛甩,最强档)。
|
||||
/// 一次性顿挫动效,叠加在 Accent 层上,结束回到原位。
|
||||
/// 镜头采样合成位姿,会自然追着 accent 跑。
|
||||
/// </summary>
|
||||
public void PlayKiteAccent(string profile)
|
||||
{
|
||||
@@ -930,74 +785,91 @@ namespace AibisDream
|
||||
_kiteAccentSequence = null;
|
||||
|
||||
var tr = _kiteRenderer.transform;
|
||||
// 位移在高度层的子空间里,随缩放自动变小,无需额外乘缩放系数
|
||||
var seq = DOTween.Sequence();
|
||||
|
||||
switch (NormalizeMotionProfile(profile))
|
||||
{
|
||||
case "lift":
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.14f, 0.3f, 0f), 0.35f).SetEase(Ease.OutQuad));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -6f), 0.35f).SetEase(Ease.OutQuad));
|
||||
seq.Append(tr.DOLocalPath(new[]
|
||||
{
|
||||
new Vector3(0.03f, 0.07f, 0f),
|
||||
new Vector3(0.11f, 0.17f, 0f),
|
||||
new Vector3(0.12f, 0.24f, 0f),
|
||||
}, 0.75f, PathType.CatmullRom).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(2f, -1.5f, -2f), 0.62f).SetEase(Ease.InOutSine));
|
||||
break;
|
||||
|
||||
case "sink":
|
||||
seq.Append(tr.DOLocalMove(new Vector3(-0.06f, -0.28f, 0f), 0.4f).SetEase(Ease.OutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, 5f), 0.4f).SetEase(Ease.OutSine));
|
||||
seq.Append(tr.DOLocalPath(new[]
|
||||
{
|
||||
new Vector3(0.03f, -0.06f, 0f),
|
||||
new Vector3(-0.02f, -0.17f, 0f),
|
||||
new Vector3(-0.08f, -0.24f, 0f),
|
||||
}, 0.82f, PathType.CatmullRom).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(-2f, 1.5f, 2f), 0.68f).SetEase(Ease.InOutSine));
|
||||
break;
|
||||
|
||||
// 绷紧:猛地被扯直,然后绷住缓慢微颤(小幅慢速拉锯,不是震动)
|
||||
case "taut":
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.3f, 0.06f, 0f), 0.2f).SetEase(Ease.OutCubic));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -9f), 0.2f).SetEase(Ease.OutCubic));
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.26f, 0.03f, 0f), 0.3f).SetEase(Ease.InOutSine));
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.31f, 0.07f, 0f), 0.26f).SetEase(Ease.InOutSine));
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.27f, 0.04f, 0f), 0.3f).SetEase(Ease.InOutSine));
|
||||
seq.Append(tr.DOLocalPath(new[]
|
||||
{
|
||||
new Vector3(0.08f, 0.01f, 0f),
|
||||
new Vector3(0.2f, 0.07f, 0f),
|
||||
new Vector3(0.26f, 0.05f, 0f),
|
||||
}, 0.62f, PathType.CatmullRom).SetEase(Ease.OutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, -2f, -3f), 0.62f).SetEase(Ease.OutSine));
|
||||
seq.AppendInterval(0.32f);
|
||||
break;
|
||||
|
||||
case "drop":
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.04f, -0.42f, 0f), 0.55f).SetEase(Ease.InQuad));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, 7f), 0.55f).SetEase(Ease.InQuad));
|
||||
seq.Append(tr.DOLocalPath(new[]
|
||||
{
|
||||
new Vector3(0.06f, -0.08f, 0f),
|
||||
new Vector3(0.08f, -0.24f, 0f),
|
||||
new Vector3(0.01f, -0.36f, 0f),
|
||||
}, 0.92f, PathType.CatmullRom).SetEase(Ease.InSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(-2.5f, 1f, 3f), 0.86f).SetEase(Ease.InOutSine));
|
||||
break;
|
||||
|
||||
// 侧面兜住(最强档,切轱辘前用):先被回带半拍蓄力,随即狠狠横甩出去,
|
||||
// 挣了一下没挣回来,又被兜得更远、倾得更狠——位移远超其它档位
|
||||
case "wrench":
|
||||
seq.Append(tr.DOLocalMove(new Vector3(-0.11f, 0.04f, 0f), 0.09f).SetEase(Ease.OutQuad));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, 4f), 0.09f).SetEase(Ease.OutQuad));
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.7f, 0.2f, 0f), 0.16f).SetEase(Ease.OutCubic));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -24f), 0.16f).SetEase(Ease.OutCubic));
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.45f, 0.09f, 0f), 0.2f).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -10f), 0.2f).SetEase(Ease.InOutSine));
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.92f, 0.3f, 0f), 0.15f).SetEase(Ease.OutCubic));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -30f), 0.15f).SetEase(Ease.OutCubic));
|
||||
seq.AppendInterval(0.25f);
|
||||
seq.Append(tr.DOLocalPath(new[]
|
||||
{
|
||||
new Vector3(-0.06f, 0.03f, 0f),
|
||||
new Vector3(0.3f, 0.18f, 0f),
|
||||
new Vector3(0.64f, 0.12f, 0f),
|
||||
new Vector3(0.78f, 0.24f, 0f),
|
||||
}, 1.15f, PathType.CatmullRom).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(1.5f, -3f, -6f), 0.92f).SetEase(Ease.InOutSine));
|
||||
seq.AppendInterval(0.42f);
|
||||
break;
|
||||
|
||||
// 挣扎:左右交替的几下小拉扯,力度递减
|
||||
case "flutter":
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.1f, 0.14f, 0f), 0.2f).SetEase(Ease.OutCubic));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -5f), 0.2f).SetEase(Ease.OutCubic));
|
||||
seq.Append(tr.DOLocalMove(new Vector3(-0.08f, 0.06f, 0f), 0.26f).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, 4.5f), 0.26f).SetEase(Ease.InOutSine));
|
||||
seq.Append(tr.DOLocalMove(new Vector3(0.06f, 0.1f, 0f), 0.22f).SetEase(Ease.OutCubic));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(0f, 0f, -3.5f), 0.22f).SetEase(Ease.OutCubic));
|
||||
{
|
||||
float side = UnityEngine.Random.value < 0.5f ? -1f : 1f;
|
||||
seq.Append(tr.DOLocalPath(new[]
|
||||
{
|
||||
new Vector3(0.05f * side, 0.04f, 0f),
|
||||
new Vector3(0.16f * side, 0.11f, 0f),
|
||||
new Vector3(0.24f * side, 0.07f, 0f),
|
||||
}, 1.05f, PathType.CatmullRom).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(new Vector3(1.5f, -2.5f * side, -3f * side), 0.9f)
|
||||
.SetEase(Ease.InOutSine));
|
||||
seq.AppendInterval(0.22f);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
seq.Kill();
|
||||
return;
|
||||
}
|
||||
|
||||
// 回到原位,保证可与高度/风况补间叠加
|
||||
seq.Append(tr.DOLocalMove(Vector3.zero, 0.5f).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(Vector3.zero, 0.5f).SetEase(Ease.InOutSine));
|
||||
seq.Append(tr.DOLocalMove(Vector3.zero, 0.82f).SetEase(Ease.InOutSine));
|
||||
seq.Join(tr.DOLocalRotate(Vector3.zero, 0.82f).SetEase(Ease.InOutSine));
|
||||
_kiteAccentSequence = seq;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏风筝 Rig。与显示一致不做淡出,直接消失(过渡由外层屏幕 fade 承担)。
|
||||
/// 隐藏风筝 Rig。与显示一致不做淡出,直接消失。
|
||||
/// </summary>
|
||||
/// <param name="duration">保留参数以兼容既有调用,实际忽略</param>
|
||||
public IEnumerator HideKite(float duration = 1)
|
||||
{
|
||||
if (!IsKiteShowing) yield break;
|
||||
@@ -1007,7 +879,7 @@ namespace AibisDream
|
||||
_kiteRenderer.SetAlpha(0);
|
||||
_kiteBaseRenderer.SetAlpha(0);
|
||||
|
||||
_kiteRootPivot.gameObject.SetActive(false);
|
||||
_kiteCameraNode.gameObject.SetActive(false);
|
||||
_kiteBaseRenderer.gameObject.SetActive(false);
|
||||
if (_kiteMask != null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user