Jump/JumpPiece.cs
using System;
/// <summary>
/// 跳一跳的"棋子":球体模型,位置由 JumpGame 驱动(BasePosition = 模型底部中心),
/// 这里只负责蓄力压扁 / 起跳拉伸 / 落地回弹的形变表现。
/// </summary>
public sealed class JumpPiece : Component
{
const float PieceDiameter = 54f;
const float Stiffness = 170f;
const float Damping = 15f;
/// <summary> 棋子半径(世界单位) </summary>
public float Radius { get; private set; } = 27f;
ModelRenderer _renderer;
Vector3 _baseScale = Vector3.One;
float _charge;
float _squash;
float _squashVel;
/// <summary> 模型底部中心的世界坐标 </summary>
public Vector3 BasePosition => GameObject.WorldPosition - Vector3.Up * Radius;
public void SetBasePosition( Vector3 basePos ) => GameObject.WorldPosition = basePos + Vector3.Up * Radius;
/// <summary> 放到某个平台的中心(落地吸附用) </summary>
public void PlaceOn( JumpPlatform platform ) => SetBasePosition( new Vector3( platform.CenterX, platform.CenterY, platform.TopZ ) );
public void Init( JumpPlatform platform )
{
_renderer = GameObject.AddComponent<ModelRenderer>();
_renderer.Model = Model.Load( "models/dev/sphere.vmdl" );
_renderer.Tint = new Color( 0.16f, 0.17f, 0.20f );
var size = _renderer.Model.Bounds.Size;
var s = PieceDiameter / size.x;
_baseScale = new Vector3( s, s, s );
Radius = size.z * s * 0.5f;
GameObject.LocalScale = _baseScale;
PlaceOn( platform );
}
/// <summary> 每帧蓄力值(0~1),JumpGame 在蓄力时持续更新 </summary>
public void SetCharge( float power ) => _charge = power;
/// <summary> 形变冲量:正 = 拉伸(起跳),负 = 压扁(落地) </summary>
public void Impulse( float amount ) => _squashVel += amount;
protected override void OnUpdate()
{
// 形变弹簧:向自然状态回落
_squashVel += ( -Stiffness * _squash - Damping * _squashVel ) * Time.Delta;
_squash += _squashVel * Time.Delta;
var total = Math.Clamp( _squash - _charge * 0.42f, -0.55f, 0.6f );
var xz = 1f - total * 0.45f;
GameObject.LocalScale = new Vector3( _baseScale.x * xz, _baseScale.y * xz, _baseScale.z * ( 1f + total ) );
}
}