BugSegment.cs
using System;
namespace Battlebugs;
public class BugSegment : Component
{
[Property] public GameObject Body { get; set; }
[Property] public ModelRenderer BodyRenderer { get; set; }
[Property] BugHealthbar Healthbar { get; set; }
[Property] bool Floating { get; set; }
[Property, Group( "Prefabs" )] public GameObject BugSplatParticle { get; set; }
[Sync] public int Index { get; set; } = 0;
[Sync] public string BugPath { get; set; }
[Sync] public float Health { get; set; } = 10f;
public BugResource Bug => ResourceLibrary.Get<BugResource>( BugPath );
public CellComponent Cell { get; set; }
bool _initialized { get; set; } = false;
float _targetAlpha { get; set; } = 1f;
TimeSince _timeSinceLastDamage { get; set; } = 0f;
public bool IsVisible => _targetAlpha > 0f;
public async void Init( BugResource bug, int index )
{
Index = index;
BugPath = bug.ResourcePath;
Health = bug.StartingHealth;
Body.LocalPosition = Vector3.Down * 250f;
Body.LocalRotation = new Angles( 0, Random.Shared.Float( -180f, 180f ), 0 );
await GameTask.DelaySeconds( index * 0.05f );
_initialized = true;
Sound.Play( "segment-drop" );
}
protected override void OnStart()
{
SetAlpha( (Network.OwnerId == Connection.Local.Id) ? 1f : 0f, true );
}
protected override void OnUpdate()
{
foreach ( var renderer in Components.GetAll<ModelRenderer>( FindMode.EverythingInSelfAndDescendants ) )
{
renderer.Tint = renderer.Tint.WithAlpha( renderer.Tint.a.LerpTo( _targetAlpha, Time.Delta * 5f ) );
}
Healthbar.Alpha = Healthbar.Alpha.LerpTo( (_targetAlpha == 1 && GameManager.Instance.State != GameState.Placing) ? 1 : 0, Time.Delta * 5f );
}
protected override void OnFixedUpdate()
{
if ( _initialized || IsProxy )
{
var targetPos = Vector3.Up * 2.5f;
if ( Floating ) targetPos += Vector3.Up * (MathF.Sin( (Time.Now + (WorldPosition.x + (WorldPosition.y * 10f)) / 32f) * 2f ) * 0.25f) * 8f;
Body.LocalPosition = Body.LocalPosition.LerpTo( targetPos, Time.Delta * 15f );
Body.LocalRotation = Rotation.Slerp( Body.LocalRotation, Rotation.Identity, Time.Delta * 15f );
}
if ( !IsProxy )
{
if ( _timeSinceLastDamage > 1f && Health <= 0 )
{
Clear( true );
}
}
}
public void SetAlpha( float alpha, bool instant = false )
{
if ( instant )
{
foreach ( var renderer in Components.GetAll<ModelRenderer>( FindMode.EverythingInSelfAndDescendants ) )
{
renderer.Tint = renderer.Tint.WithAlpha( alpha );
}
}
_targetAlpha = alpha;
}
public void Clear( bool dropCoin = false )
{
if ( IsProxy ) return;
var otherBoard = Scene.GetAllComponents<BoardManager>().FirstOrDefault( x => x.Network.OwnerId != Network.OwnerId );
otherBoard.GiveCoins( 20 );
otherBoard.IncrementBugsKilled();
if ( GameManager.Instance.State == GameState.Playing ) Cell.BroadcastClear();
BroadcastDestroyFX( dropCoin );
GameObject.Destroy();
}
public void AddHighlight( Color color = default )
{
var outline = Components.GetOrCreate<HighlightOutline>();
outline.Color = color;
outline.InsideColor = Color.Transparent;
outline.ObscuredColor = Color.Transparent;
outline.InsideObscuredColor = Color.Transparent;
}
public void RemoveHighlight()
{
if ( !IsValid ) return;
Components.Get<HighlightOutline>()?.Destroy();
}
CellComponent GetCell()
{
return Scene.GetAllComponents<CellComponent>().OrderBy( x => x.WorldPosition.DistanceSquared( WorldPosition ) ).FirstOrDefault();
}
[Rpc.Broadcast]
public void Damage( float damage )
{
if ( Health <= 0 ) return;
_targetAlpha = 1f;
GetCell()?.BroadcastHit();
var otherBoard = Scene.GetAllComponents<BoardManager>().FirstOrDefault( x => x.Network.OwnerId != Network.OwnerId );
if ( otherBoard == BoardManager.Local )
{
otherBoard.IncrementDamageDealt( damage );
}
if ( IsProxy ) return;
Health -= damage;
_timeSinceLastDamage = 0f;
}
[Rpc.Broadcast]
public void BroadcastDestroyFX( bool dropCoin = false )
{
Sound.Play( "impact-bullet-flesh", WorldPosition );
if ( dropCoin ) GameManager.Instance.SpawnCoins( WorldPosition, 3 );
if ( BugSplatParticle is not null )
{
var obj = BugSplatParticle.Clone( WorldPosition + Vector3.Up * 16f );
var part = obj.Components.Get<ParticleEffect>();
part.Tint = Bug.Color;
}
}
}