things/EnemyBullet.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Manager;
public class EnemyBullet : Thing
{
public TimeSince TimeSinceSpawn { get; private set; }
public float Damage { get; set; }
public float Lifetime { get; set; }
public Vector2 Direction { get; set; }
public float Speed { get; set; }
public bool IsHoming { get; set; }
public Thing Target { get; set; }
private float _homingDeceleration;
public bool IsCharmed { get; private set; }
public Enemy Creator { get; set; }
private float _startingSpriteY;
protected override void OnAwake()
{
base.OnAwake();
//OffsetY = -0.4f;
Sprite.LocalPosition = new Vector3( 0f, 0.55f, 0f );
Radius = 0.066f;
Scale = 0.35f;
Sprite.LocalScale *= Scale * Globals.SPRITE_SCALE;
//Sprite.Size = new Vector2( 1f, 1f ) * Scale;
Sprite.PlaybackSpeed = 2f;
//Sprite.Tint = Color.Yellow;
ShadowOpacity = 0.8f;
ShadowScale = 0.6f;
SpawnShadow( ShadowScale, ShadowOpacity );
//Speed = 2f;
Lifetime = 6f;
if ( Manager.Instance.Difficulty == -1f )
Lifetime *= 0.66f;
Damage = 9f;
TimeSinceSpawn = 0f;
if ( IsProxy )
return;
CollideWith.Add( typeof( Player ) );
CollideWith.Add( typeof( Enemy ) );
_startingSpriteY = Sprite.LocalPosition.y;
}
public void SetColor(Color color)
{
Sprite.Tint = color;
}
protected override void OnUpdate()
{
base.OnUpdate();
//Gizmo.Draw.Color = Color.White;
//Gizmo.Draw.Text( $"Sprite.Tint: {Sprite.Tint}", new global::Transform( (Vector3)Position2D + new Vector3( 0f, -0.7f, 0f ) ) );
//Gizmo.Draw.Color = Color.White.WithAlpha( 0.05f );
//Gizmo.Draw.LineSphere( (Vector3)Position2D, Radius );
//if ( !Manager.Instance.ShouldUpdateThings )
// return;
float dt = Time.Delta;
// todo: flip horizontal if moving left
if(IsHoming)
{
if(Target.IsValid())
{
float speed = 7f;
float leadingSpeed = Utils.Map( (Target.Position2D - Position2D).LengthSquared, 0f, 7f * 7f, 0f, 5f, EasingType.Linear );
var dir = Vector2.Lerp( ((Target.Position2D + Target.Velocity * leadingSpeed) - Position2D).Normal, Velocity.Normal, Utils.Map( (Target.Position2D - Position2D).LengthSquared, 0f, 1.2f, 1f, 0f, EasingType.QuadOut ) );
Velocity += dir * speed * dt;
Velocity *= (1f - _homingDeceleration * dt);
}
Sprite.Tint = Color.Lerp( Color.Magenta, Color.Yellow, 0.5f + Utils.FastSin( TimeSinceSpawn + Time.Now * 28f ) * 0.5f );
Position2D += Velocity * dt;
}
else
{
var speed = Speed * Utils.Map( TimeSinceSpawn, 0f, 0.5f, 0f, 1f, EasingType.QuadInOut ) * (Manager.Instance.Difficulty < 0 ? 0.75f : (Manager.Instance.Difficulty >= 1 ? 1.1f : 1f));
Position2D += Direction * speed * dt;
}
WorldPosition = WorldPosition.WithZ( Globals.GetZPos( Position2D.y ) );
if ( TimeSinceSpawn > Lifetime )
{
var cloud = Manager.Instance.SpawnCloud( Position2D );
cloud.Lifetime = Game.Random.Float( 0.15f, 0.3f );
cloud.Velocity = Velocity * Game.Random.Float( 0f, 1f );
cloud.Deceleration = Game.Random.Float( 10f, 12f );
cloud.LocalScale *= Game.Random.Float( 0.4f, 0.75f );
Remove();
return;
}
float progress = Utils.Map( TimeSinceSpawn, 0f, Lifetime, 0f, 1f, EasingType.QuadIn );
Sprite.LocalPosition = Sprite.LocalPosition.WithY( Utils.Map( progress, 0f, 1f, _startingSpriteY, Radius * 0.8f ) );
float shadowSize = Utils.Map( progress, 0f, 1f, ShadowScale, ShadowScale * 1.25f );
ShadowSprite.LocalScale = new Vector3( shadowSize * Globals.SPRITE_SCALE, shadowSize * Globals.SPRITE_SCALE, 1f );
ShadowSprite.Tint = Color.Black.WithAlpha( Utils.Map( progress, 0f, 1f, 0.5f, 1f ) );
for ( int dx = -1; dx <= 1; dx++ )
{
for ( int dy = -1; dy <= 1; dy++ )
{
Manager.Instance.HandleThingCollisionForGridSquare( this, new GridSquare( GridPos.x + dx, GridPos.y + dy ), dt );
if ( IsRemoved )
return;
}
}
}
public override void Colliding( Thing other, float percent, float dt )
{
base.Colliding( other, percent, dt );
if ( other is Player player && !player.IsDead && !IsCharmed )
{
float dmg = player.CheckDamageAmount( Damage, DamageType.Ranged );
if ( !player.IsInvulnerable && !player.IsTimePausedForChoosing )
{
Manager.Instance.PlaySfxNearby( "splash", Position2D, pitch: Game.Random.Float( 0.95f, 1.05f ), volume: 1f, maxDist: 4f );
player.Damage( dmg );
player.AddVelocity( Direction * 2f );
}
if( !player.IsDead && ( !player.IsInvulnerable || Manager.Instance.Difficulty <= 0 ) )
Remove();
}
else if( other is Enemy enemy && (IsCharmed != enemy.IsCharmed) )
{
enemy.Damage( Damage, null, addVel: Direction * Game.Random.Float(0.75f, 1.5f), addTempWeight: 0f, isCrit: false, DamageType.Ranged );
if(Creator.IsValid())
enemy.Target = Creator;
Manager.Instance.PlaySfxNearby( "splash", Position2D, pitch: Game.Random.Float( 1.1f, 1.15f ), volume: 0.6f, maxDist: 3f );
Remove();
}
}
public void BecomeCharmed(bool elite = false)
{
IsCharmed = true;
Sprite.Tint = elite ? new Color( 1f, 0.2f, 1f, 0.3f ) : new Color(1f, 0f, 1f, 0.6f);
CollideWith.Remove( typeof( Player ) );
Damage = 9f * Manager.Instance.Player.Stats[PlayerStat.CharmedEnemyDmgDealtMultiplier];
}
public void BecomeHoming(Vector2 velocity, Thing target)
{
IsHoming = true;
Velocity = velocity;
Target = target;
Radius = 0.08f;
Scale = 0.45f;
Sprite.LocalScale = Scale * Globals.SPRITE_SCALE;
Lifetime = Game.Random.Float(4f, 7f);
_homingDeceleration = Game.Random.Float( 1f, 1.25f );
}
}