menu/MenuEnemy.cs
using SpriteTools;

public class MenuEnemy : Component
{
	[Property] public SpriteRendererLayer Sprite { get; set; }


	public Vector3 Velocity { get; set; }

	public bool IsAttacking { get; set; }

	public bool IsFlipped { get; set; }

	public float SpeedModifier { get; set; }

	float _heightMod;
	float _widthMod;

	public virtual float HeightVariance => 0f;
	public virtual float WidthVariance => 0f;

	private TimeSince _timeSinceSpawn;

	private float _angerThreshold;
	private float _angerChangeSpeed;

	public float AnimSpeedOffset = Game.Random.Float( 0f, 99f );

	protected override void OnAwake()
	{
		base.OnAwake();

		AnimSpeedOffset = Game.Random.Float( 0f, 99f );

		_heightMod = Game.Random.Float( 1f - HeightVariance, 1f + HeightVariance );
		_widthMod = Game.Random.Float( 1f - WidthVariance, 1f + WidthVariance );

		//Sprite.Tint = Color.White.WithAlpha( 0f );

		_timeSinceSpawn = 0f;

		_angerThreshold = Utils.Map( Game.Random.Float( 0f, 1f ), 0f, 1f, 0f, 1f, EasingType.QuadIn );
		_angerChangeSpeed = Game.Random.Float( 0.2f, 0.8f );

		LocalScale = Vector3.Zero;
	}

	protected override void OnStart()
	{
		base.OnStart();

		LocalRotation = new Angles( 0f, -90f, 0f );
	}

	protected override void OnUpdate()
	{
		base.OnUpdate();

		//Sprite.Tint = Color.White.WithAlpha( Utils.Map( _timeSinceSpawn, 0f, 1f, 0f, 1f ) );

		WorldPosition = WorldPosition.WithZ( Utils.Map( WorldPosition.y, MenuManager.Y_MIN, MenuManager.Y_MAX, MenuManager.Z_NEAR, MenuManager.Z_FAR ) );

		var shouldAttack = _timeSinceSpawn > 0.5f && (0.5f + Utils.FastSin( AnimSpeedOffset + Time.Now * _angerChangeSpeed )) > _angerThreshold;

		//if ( !IsAttacking && shouldAttack )
		//{
		//	var sfx = Sound.Play( "zombie.spawn0", WorldPosition.WithZ(100f) );
		//	if ( sfx != null )
		//	{
		//		sfx.Volume = Utils.Map( WorldPosition.y, MenuManager.Y_MIN, MenuManager.Y_MAX, 0.9f, 0.25f) * Utils.Map(MenuManager.Instance.ElapsedTime, 0f, 1.2f, 0f, 1f);
		//		sfx.Pitch = Game.Random.Float( 0.9f, 1.1f );
		//	}
		//}

		IsAttacking = shouldAttack;
		Sprite.PlayAnimation( IsAttacking ? "attack" : "walk" );

		var scale = Utils.Map( WorldPosition.z, MenuManager.Z_NEAR, MenuManager.Z_FAR, 0.6f, 0.1f );
		LocalScale = new Vector3( scale * _heightMod, scale * _widthMod, scale * _heightMod );

		Sprite.FlashTint = Color.Black.WithAlpha( Utils.Map( WorldPosition.z, MenuManager.Z_NEAR, MenuManager.Z_FAR, 0f, 0.2f, EasingType.QuadIn ) );
		Sprite.SpriteFlags = IsFlipped ? SpriteFlags.HorizontalFlip : SpriteFlags.None;
	}
}