Static math helper for a football goal net's impact response. Computes the per-frame displacement scale of the net fabric from the impact point, ball speed and time since the goal, with a contact delay, distance falloff, overshoot and decay.
using System;
namespace Socer;
// In-place net response evaluated from impact, independent of render rate.
public static class FootballNetMotion
{
public const float Duration=3.2f;
public static float ContactDelay(float speed)=>Math.Clamp(1.8f/Math.Max(6,speed*.58f),.06f,.30f);
public static float Displacement(float y,float z,float impactY,float impactZ,float age,float speed)
{
if(age<=0 || age>=Duration)return 0;
const float left=PitchPerspective.PostLeft,width=PitchPerspective.PostRight-PitchPerspective.PostLeft,height=PitchPerspective.CrossbarCentre;
float u=Math.Clamp((y-left)/width,0,1),v=Math.Clamp(z/height,0,1);
float edge=MathF.Sin(u*MathF.PI)*MathF.Sin(v*MathF.PI);
float dy=y-Math.Clamp(impactY,left,left+width);
float dz=z-Math.Clamp(impactZ,.12f,height-.08f);
float distance=MathF.Sqrt(dy*dy+dz*dz);
// The goal event is the line crossing. The ball still has to travel
// into the back of the net before the fabric takes its impulse.
float local=age-ContactDelay(speed)-distance/8.5f;
if(local<=0)return 0;
float strength=Math.Clamp(speed/22,.55f,1.25f);
float attack=1-MathF.Exp(-local*24);
float decay=MathF.Exp(-local*2.0f);
float spread=MathF.Exp(-distance*.57f);
float tail=Math.Clamp((Duration-age)/.45f,0,1);
tail=tail*tail*(3-2*tail);
return .66f*strength*edge*spread*attack*decay*MathF.Sin(local*9.2f)*tail;
}
}