Component attached to a prefab that converts character Step events and landing events into a camera shake and optional landing sound. It computes distance attenuation and amplifies shake for landings.
namespace SBH;
using Sandbox;
/// <summary>
/// [SBHBase] PISADA DE GIGANTE (2026-08-10, para el Siren Head — y todo
/// coloso que venga). Colgado en el prefab, convierte cada evento Step del
/// personaje en un TEMBLOR de pantalla con caída por distancia, y el
/// ATERRIZAJE de un salto/caída en un pisotón más fuerte todavía (con su
/// sonido propio, porque el aterrizaje no es un evento pintado).
///
/// El sonido de las pisadas normales va como siempre: pintando los Step en
/// el editor con el Dato apuntando al .sound del personaje (p. ej.
/// sounds/sirenhead/pisada_gigante.sound).
/// </summary>
public sealed class PisadaGigante : Component
{
[Property, Description( "Trauma de temblor por pisada (0.1 apenas se siente, 0.5 sacude fuerte) — se atenúa con la distancia" )]
public float FuerzaTemblor { get; set; } = 0.35f;
[Property, Description( "Distancia a la que el temblor deja de sentirse (el sonido tiene su propia distancia en el .sound)" )]
public float RadioTemblor { get; set; } = 2500f;
[Property, Description( "Multiplicador del temblor al ATERRIZAR de un salto o caída" )]
public float MultAterrizaje { get; set; } = 2.5f;
[Property, Description( "Sonido del aterrizaje (opcional): suena al caer aunque no haya evento pintado" )]
public SoundEvent SonidoAterrizaje { get; set; }
/// <summary> Lo llama el despachador de eventos en cada Step del personaje. </summary>
public void AlPaso( Vector3 punto ) => Sacudir( punto, FuerzaTemblor );
/// <summary> Lo llaman SaltoNextbot y la posesión al tocar el piso tras un vuelo. </summary>
public void AlAterrizar()
{
if ( SonidoAterrizaje != null )
Sound.Play( SonidoAterrizaje, WorldPosition );
Sacudir( WorldPosition, FuerzaTemblor * MultAterrizaje );
}
void Sacudir( Vector3 punto, float fuerza )
{
var cam = Scene?.Camera;
if ( !cam.IsValid() ) return;
var distancia = cam.WorldPosition.Distance( punto );
if ( distancia >= RadioTemblor ) return;
// Atenuación cuadrática: de cerca sacude entero, de lejos un cosquilleo
var cerca = 1f - (distancia / RadioTemblor);
TemblorCamara.Sacudir( Scene, fuerza * cerca * cerca );
}
}