Entities/GrindPathEntity.cs
using System;
namespace Skateboard.Entities;
[EditorHandle( "moving" )]
[Title( "Grind Path" )]
[Category( "Gameplay" )]
[Icon( "moving" )]
public sealed class GrindPathEntity : Component
{
[Property] public bool Looped { get; set; }
[Property] public List<GameObject> PathNodes { get; set; } = new();
[Property, TextArea, WideMode, ReadOnly] public string PathNodesJson { get; set; }
private sealed class PathNodeJson
{
public Vector3 Position { get; set; }
public Vector3 TangentIn { get; set; }
public Vector3 TangentOut { get; set; }
public string hammerUniqueId { get; set; }
public string classname { get; set; }
}
protected override void OnValidate()
{
base.OnValidate();
RefreshPathNodes();
}
protected override void OnStart()
{
base.OnStart();
if ( PathNodes.Count == 0 && !string.IsNullOrWhiteSpace( PathNodesJson ) )
BuildPathNodesFromJson( PathNodesJson );
}
public void SetPathNodesJson( string json )
{
PathNodesJson = json;
if ( PathNodes.Count == 0 )
BuildPathNodesFromJson( json );
}
public void RefreshPathNodes()
{
if ( PathNodes is null )
PathNodes = new List<GameObject>();
if ( PathNodes.Count > 0 )
return;
foreach ( var child in GameObject.Children )
{
if ( !child.IsValid() )
continue;
if ( child.Components.Get<GrindPathNodeEntity>() is not null )
PathNodes.Add( child );
}
}
private void BuildPathNodesFromJson( string json )
{
if ( string.IsNullOrWhiteSpace( json ) )
return;
List<PathNodeJson> nodes;
try
{
nodes = System.Text.Json.JsonSerializer.Deserialize<List<PathNodeJson>>(
json,
new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true }
);
}
catch ( Exception ex )
{
Log.Warning( $"GrindPathEntity failed to parse pathNodesJSON: {ex.Message}" );
return;
}
if ( nodes is null || nodes.Count == 0 )
return;
PathNodes.Clear();
for ( int i = 0; i < nodes.Count; i++ )
{
var node = nodes[i];
var nodeObj = new GameObject( GameObject, true, $"GrindPathNode_{i}" )
{
LocalPosition = node.Position
};
nodeObj.Components.GetOrCreate<GrindPathNodeEntity>();
PathNodes.Add( nodeObj );
}
}
protected override void DrawGizmos()
{
base.DrawGizmos();
if ( PathNodes is null || PathNodes.Count < 2 )
return;
for ( int i = 0; i < PathNodes.Count - 1; i++ )
{
var a = PathNodes[i];
var b = PathNodes[i + 1];
if ( !a.IsValid() || !b.IsValid() )
continue;
Gizmo.Draw.Color = Color.Green.Darken( 0.5f );
Gizmo.Draw.LineThickness = 4;
Gizmo.Draw.Line( a.LocalPosition, b.LocalPosition );
}
if ( Looped )
{
var start = PathNodes[0];
var end = PathNodes[^1];
if ( start.IsValid() && end.IsValid() )
{
Gizmo.Draw.Color = Color.Green.Darken( 0.5f );
Gizmo.Draw.Line( end.LocalPosition, start.LocalPosition );
}
}
}
}