feat(subway): 添加车厢加速度驱动与扶手摆动

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-13 22:54:43 +08:00
co-authored by Cursor
parent df6f8c6ec4
commit 4f59e41b03
6 changed files with 675 additions and 2 deletions
+318
View File
@@ -291,6 +291,7 @@ GameObject:
m_Component:
- component: {fileID: 88656235}
- component: {fileID: 88656236}
- component: {fileID: 9100002001}
m_Layer: 0
m_Name: "\u6276\u624BA (3)"
m_TagString: Untagged
@@ -571,6 +572,7 @@ MonoBehaviour:
tvSlots: {fileID: 494482151}
newsSpriteRenderer: {fileID: 5352226562362177808}
arriveStation: {fileID: 969974277}
carMotion: {fileID: 9100001001}
--- !u!1 &226184625
GameObject:
m_ObjectHideFlags: 0
@@ -924,6 +926,7 @@ GameObject:
m_Component:
- component: {fileID: 325261252}
- component: {fileID: 325261253}
- component: {fileID: 9100002002}
m_Layer: 0
m_Name: "\u6276\u624BB (3)"
m_TagString: Untagged
@@ -1008,6 +1011,7 @@ GameObject:
m_Component:
- component: {fileID: 347095461}
- component: {fileID: 347095462}
- component: {fileID: 9100002003}
m_Layer: 0
m_Name: "\u6276\u624BB (2)"
m_TagString: Untagged
@@ -1224,6 +1228,7 @@ GameObject:
m_Component:
- component: {fileID: 450826708}
- component: {fileID: 450826709}
- component: {fileID: 9100002004}
m_Layer: 0
m_Name: "\u6276\u624BB (1)"
m_TagString: Untagged
@@ -1602,6 +1607,7 @@ GameObject:
m_Component:
- component: {fileID: 497537573}
- component: {fileID: 497537574}
- component: {fileID: 9100002005}
m_Layer: 0
m_Name: "\u6276\u624BB (4)"
m_TagString: Untagged
@@ -1729,6 +1735,7 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 546256082}
- component: {fileID: 9100001001}
m_Layer: 0
m_Name: "\u628A\u624B\u7EC4"
m_TagString: Untagged
@@ -3153,6 +3160,7 @@ GameObject:
m_Component:
- component: {fileID: 1702647399}
- component: {fileID: 1702647400}
- component: {fileID: 9100002006}
m_Layer: 0
m_Name: "\u6276\u624BA (4)"
m_TagString: Untagged
@@ -3471,6 +3479,7 @@ GameObject:
m_Component:
- component: {fileID: 1901117876}
- component: {fileID: 1901117877}
- component: {fileID: 9100002007}
m_Layer: 0
m_Name: "\u6276\u624BA (1)"
m_TagString: Untagged
@@ -3555,6 +3564,7 @@ GameObject:
m_Component:
- component: {fileID: 1926948638}
- component: {fileID: 1926948639}
- component: {fileID: 9100002008}
m_Layer: 0
m_Name: "\u6276\u624BA (2)"
m_TagString: Untagged
@@ -4395,6 +4405,7 @@ GameObject:
m_Component:
- component: {fileID: 4103782223475585769}
- component: {fileID: 8967103020905652160}
- component: {fileID: 9100002009}
m_Layer: 0
m_Name: "\u6276\u624BB"
m_TagString: Untagged
@@ -4460,6 +4471,7 @@ GameObject:
m_Component:
- component: {fileID: 2050361239654858494}
- component: {fileID: 8861695100661960901}
- component: {fileID: 9100002010}
m_Layer: 0
m_Name: "\u6276\u624BA"
m_TagString: Untagged
@@ -5535,3 +5547,309 @@ SceneRoots:
- {fileID: 163812961}
- {fileID: 1929645612}
- {fileID: 1767040865}
--- !u!114 &9100001001
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 546256081}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 22b2f701b86b458fae30ddb4a612c419, type: 3}
m_Name:
m_EditorClassIdentifier:
calmIntervalMin: 0.7
calmIntervalMax: 2.2
joltPeakMin: 0.6
joltPeakMax: 1.4
joltDurationMin: 0.18
joltDurationMax: 0.32
joltBurstCount: {x: 1, y: 3}
joltBurstGapMin: 0.12
joltBurstGapMax: 0.28
calmNoiseAmplitude: 0.03
brakePeakAccel: 1.6
brakeAccelCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 4
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.12
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.5
value: 0.65
inSlope: -0.5
outSlope: -0.5
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: -1.5
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
accelSmoothTime: 0.025
--- !u!114 &9100002001
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 88656234}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002002
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 325261251}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002003
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 347095460}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002004
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 450826707}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002005
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 497537572}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002006
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1702647398}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002007
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1901117875}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002008
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1926948637}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002009
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4324682127354924289}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
--- !u!114 &9100002010
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4847544086954038309}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 982dbdad2132464f978518ffdf1737ee, type: 3}
m_Name:
m_EditorClassIdentifier:
carMotion: {fileID: 9100001001}
length: 0.42
gravity: 9.81
dampingRatio: 0.16
maxAngle: 25
maxAngularSpeed: 180
maxIntegrationStep: 0.008333334
randomizeOnAwake: 1
lengthVariation: 0.03
dampingRatioRange: {x: 0.14, y: 0.18}
initialAngleRange: 0.5
hangPointLocalOffset: {x: 0, y: 0, z: 0}
@@ -18,6 +18,9 @@ namespace AibisDream
public PlayableDirector arriveStation;
[Tooltip("车厢加速度驱动;到站时触发把手制动摆动")]
public SubwayCarMotion carMotion;
public static StateMachine<OutSideState> StateMachine { get; private set; }
public bool IsDialogueReady { get; private set; }
@@ -60,8 +63,26 @@ namespace AibisDream
public IEnumerator ArriveAtStation()
{
arriveStation.Play();
yield return new WaitForSeconds((float) arriveStation.playableAsset.duration);
float duration = arriveStation != null && arriveStation.playableAsset != null
? (float)arriveStation.playableAsset.duration
: 8.5f;
if (carMotion == null)
{
carMotion = FindFirstObjectByType<SubwayCarMotion>();
}
if (carMotion != null)
{
carMotion.BeginBraking(duration);
}
if (arriveStation != null)
{
arriveStation.Play();
}
yield return new WaitForSeconds(duration);
}
public IEnumerator SwitchNews(string spriteId)
@@ -0,0 +1,184 @@
using UnityEngine;
namespace AibisDream
{
public enum SubwayCarMotionPhase
{
Stopped,
Cruise,
Braking
}
public sealed class SubwayCarMotion : MonoBehaviour
{
[Header("Cruise Jolts")]
[SerializeField] private float calmIntervalMin = 0.7f;
[SerializeField] private float calmIntervalMax = 2.2f;
[SerializeField] private float joltPeakMin = 0.6f;
[SerializeField] private float joltPeakMax = 1.4f;
[SerializeField] private float joltDurationMin = 0.18f;
[SerializeField] private float joltDurationMax = 0.32f;
[SerializeField] private Vector2Int joltBurstCount = new Vector2Int(1, 3);
[SerializeField] private float joltBurstGapMin = 0.12f;
[SerializeField] private float joltBurstGapMax = 0.28f;
[SerializeField] private float calmNoiseAmplitude = 0.03f;
[Header("Braking")]
[SerializeField] private float brakePeakAccel = 1.6f;
[SerializeField] private AnimationCurve brakeAccelCurve = new AnimationCurve(
new Keyframe(0f, 0f, 0f, 4f),
new Keyframe(0.12f, 1f),
new Keyframe(0.5f, 0.65f, -0.5f, -0.5f),
new Keyframe(1f, 0f, -1.5f, 0f));
[Header("Signal Filtering")]
[SerializeField] private float accelSmoothTime = 0.025f;
private float targetAccelX;
private float accelVelocity;
private float brakeDuration = 1f;
private float brakeTimer;
private float nextCruiseEventTime;
private int burstRemaining;
private float joltTimer;
private float joltDuration = 0.2f;
private float joltPeak = 1f;
private float joltSign = 1f;
private float noiseSeed;
public float AccelX { get; private set; }
public SubwayCarMotionPhase Phase { get; private set; } = SubwayCarMotionPhase.Cruise;
private void Awake()
{
noiseSeed = Random.value * 1000f;
ScheduleNextCruiseEvent();
}
private void Update()
{
switch (Phase)
{
case SubwayCarMotionPhase.Cruise:
UpdateCruise();
break;
case SubwayCarMotionPhase.Braking:
UpdateBraking();
break;
default:
targetAccelX = 0f;
break;
}
AccelX = Mathf.SmoothDamp(AccelX, targetAccelX, ref accelVelocity, accelSmoothTime);
}
public void BeginBraking(float duration)
{
ClearCruiseJolt();
Phase = SubwayCarMotionPhase.Braking;
brakeDuration = Mathf.Max(0.01f, duration);
brakeTimer = 0f;
}
public void SetCruise()
{
ClearCruiseJolt();
Phase = SubwayCarMotionPhase.Cruise;
ScheduleNextCruiseEvent();
}
public void SetStopped()
{
ClearCruiseJolt();
Phase = SubwayCarMotionPhase.Stopped;
targetAccelX = 0f;
AccelX = 0f;
accelVelocity = 0f;
brakeTimer = 0f;
}
private void UpdateCruise()
{
if (joltTimer > 0f)
{
joltTimer -= Time.deltaTime;
float normalizedTime = Mathf.Clamp01(1f - joltTimer / joltDuration);
targetAccelX = EvaluateBiphasicPulse(normalizedTime) * joltPeak * joltSign;
if (joltTimer <= 0f)
{
if (burstRemaining > 0)
{
nextCruiseEventTime = Time.time + Random.Range(joltBurstGapMin, joltBurstGapMax);
}
else
{
ScheduleNextCruiseEvent();
}
}
return;
}
float noise = (Mathf.PerlinNoise(noiseSeed, Time.time * 0.45f) - 0.5f) * 2f;
targetAccelX = noise * calmNoiseAmplitude;
if (Time.time >= nextCruiseEventTime)
{
StartJolt();
}
}
private void UpdateBraking()
{
brakeTimer += Time.deltaTime;
float t = Mathf.Clamp01(brakeTimer / brakeDuration);
targetAccelX = -brakePeakAccel * brakeAccelCurve.Evaluate(t);
if (brakeTimer >= brakeDuration)
{
SetStopped();
}
}
private static float EvaluateBiphasicPulse(float t)
{
if (t < 0.5f)
{
return Mathf.Sin(t * Mathf.PI * 2f);
}
return -Mathf.Sin((t - 0.5f) * Mathf.PI * 2f);
}
private void StartJolt()
{
if (burstRemaining <= 0)
{
int maxExclusive = Mathf.Max(joltBurstCount.x + 1, joltBurstCount.y + 1);
burstRemaining = Random.Range(joltBurstCount.x, maxExclusive);
}
burstRemaining--;
joltTimer = Random.Range(joltDurationMin, joltDurationMax);
joltDuration = Mathf.Max(0.01f, joltTimer);
joltPeak = Random.Range(joltPeakMin, joltPeakMax);
joltSign = Random.value < 0.5f ? -1f : 1f;
}
private void ScheduleNextCruiseEvent()
{
burstRemaining = 0;
nextCruiseEventTime = Time.time + Random.Range(calmIntervalMin, calmIntervalMax);
}
private void ClearCruiseJolt()
{
burstRemaining = 0;
joltTimer = 0f;
targetAccelX = 0f;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 22b2f701b86b458fae30ddb4a612c419
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,128 @@
using UnityEngine;
namespace AibisDream
{
[RequireComponent(typeof(SpriteRenderer))]
public sealed class SubwayHandStrap : MonoBehaviour
{
[SerializeField] private SubwayCarMotion carMotion;
[SerializeField] private float length = 0.42f;
[SerializeField] private float gravity = 9.81f;
[SerializeField] private float dampingRatio = 0.16f;
[SerializeField] private float maxAngle = 25f;
[SerializeField] private float maxAngularSpeed = 180f;
[SerializeField] private float maxIntegrationStep = 1f / 120f;
[Header("Instance Variation")]
[SerializeField] private bool randomizeOnAwake = true;
[SerializeField] private float lengthVariation = 0.03f;
[SerializeField] private Vector2 dampingRatioRange = new Vector2(0.14f, 0.18f);
[SerializeField] private float initialAngleRange = 0.5f;
[Header("Pivot")]
[SerializeField] private Vector3 hangPointLocalOffset;
private SpriteRenderer spriteRenderer;
private Vector3 restLocalPosition;
private float angle;
private float angularVelocity;
private float baseLength;
public float Angle => angle;
public float Length => length;
private void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
restLocalPosition = transform.localPosition;
baseLength = length;
if (hangPointLocalOffset == Vector3.zero && spriteRenderer.sprite != null)
{
hangPointLocalOffset = new Vector3(0f, spriteRenderer.sprite.bounds.max.y, 0f);
}
if (carMotion == null)
{
carMotion = GetComponentInParent<SubwayCarMotion>();
}
if (randomizeOnAwake)
{
RandomizeInstance();
}
ApplyPose();
}
private void Update()
{
float remainingTime = Time.deltaTime;
while (remainingTime > 0f)
{
float step = Mathf.Min(remainingTime, maxIntegrationStep);
Simulate(step);
remainingTime -= step;
}
ApplyPose();
}
private void RandomizeInstance()
{
Random.State previousState = Random.state;
Random.InitState(GetInstanceID());
length = baseLength * Random.Range(1f - lengthVariation, 1f + lengthVariation);
dampingRatio = Random.Range(dampingRatioRange.x, dampingRatioRange.y);
angle = Random.Range(-initialAngleRange, initialAngleRange);
angularVelocity = 0f;
Random.state = previousState;
}
private void Simulate(float deltaTime)
{
float safeLength = Mathf.Max(0.01f, length);
float angleRadians = angle * Mathf.Deg2Rad;
float angularVelocityRadians = angularVelocity * Mathf.Deg2Rad;
float naturalFrequency = Mathf.Sqrt(gravity / safeLength);
float accelX = carMotion != null ? carMotion.AccelX : 0f;
float angularAcceleration =
-(gravity / safeLength) * Mathf.Sin(angleRadians)
- (accelX / safeLength) * Mathf.Cos(angleRadians)
- 2f * dampingRatio * naturalFrequency * angularVelocityRadians;
angularVelocityRadians += angularAcceleration * deltaTime;
angularVelocity = Mathf.Clamp(angularVelocityRadians * Mathf.Rad2Deg, -maxAngularSpeed, maxAngularSpeed);
angle += angularVelocity * deltaTime;
ClampAngleLimit();
}
private void ClampAngleLimit()
{
if (Mathf.Abs(angle) <= maxAngle)
{
return;
}
float limitSign = Mathf.Sign(angle);
angle = limitSign * maxAngle;
if (Mathf.Sign(angularVelocity) == limitSign)
{
angularVelocity = 0f;
}
}
private void ApplyPose()
{
Quaternion rotation = Quaternion.Euler(0f, 0f, angle);
transform.localRotation = rotation;
transform.localPosition = restLocalPosition + hangPointLocalOffset - rotation * hangPointLocalOffset;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 982dbdad2132464f978518ffdf1737ee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: