A Block subclass that implements a marksman-style bullet attack. It starts a windup when the block is moving fast and in phase 1 or 2, spawns a led projectile at windup completion, plays an animation and sound, then goes into a recovery period.
namespace BlockParty;
/// <summary>
/// Dragon-derived marksman block. Hard impacts wind up aimed shots which pass through authored
/// obstacles and arena walls; phase 1 is slower and phase 2 uses the original fast bullet.
/// </summary>
public class BlockBullet : Block
{
enum ShootState { Idle, Windup, Recover }
private const float SHOOT_WINDUP = 0.35f;
private const float SHOOT_RECOVER = 0.65f;
private ShootState _shootState;
private float _shootTimer;
private BlockBulletVariant _shootVariant;
protected override bool CanActivateTimedAbility => _shootState == ShootState.Idle;
protected virtual BlockBulletVariant ProjectileVariantForPhase( int phase )
=> phase == 1 ? BlockBulletVariant.BulletPhase1 : BlockBulletVariant.BulletPhase2;
public override void Impact( Block otherBlock )
{
base.Impact( otherBlock );
if ( IsDead ) return;
if ( _moveSpeed > 40f && (Phase == 1 || Phase == 2) && _shootState == ShootState.Idle )
StartShoot();
}
private void StartShoot()
{
_shootVariant = ProjectileVariantForPhase( Phase );
_shootState = ShootState.Windup;
_shootTimer = SHOOT_WINDUP;
_mouth.PlayAnimation( $"mouth_shooting_{Phase}" );
}
public override void Tick( float dt )
{
base.Tick( dt );
if ( IsDead || _shootState == ShootState.Idle ) return;
_shootTimer -= dt;
if ( _shootTimer > 0f ) return;
if ( _shootState == ShootState.Windup )
{
if ( !TrySpawnBullet() )
{
FinishShoot();
return;
}
Audio.PlaySfx( SfxType.FireballShoot, Position, 0.9f, 1.15f );
_shootState = ShootState.Recover;
_shootTimer = SHOOT_RECOVER;
return;
}
FinishShoot();
}
private void FinishShoot()
{
RestoreFaceAndMouth();
_shootState = ShootState.Idle;
}
private bool TrySpawnBullet()
{
Player player = Stage.ClosestTargetablePlayer( Position );
if ( player is null ) return false;
Vector2 spawnPosition = Position + new Vector2( 0f, -Height * 0.2f );
Vector2 direction = BlockBulletProjectile.LeadDirection(
spawnPosition, player, BlockBulletProjectile.FullSpeed( _shootVariant ) );
Stage.AddBlockBullet( spawnPosition, direction, _shootVariant );
return true;
}
}