Park/StartingArea.cs
using System;
using HC3.Terrain;
namespace HC3;
/// <summary>
/// Defines a starting area for the park -- including park entrance, and paths along the entranceway.
/// </summary>
class StartingArea : Component, Component.ExecuteInEditor, ITerrainEvent
{
[Property] public GameObject ParkEntrance { get; set; }
[Property] public GameObject Fence { get; set; }
public int AreaSize { get; set; } = 64;
void ITerrainEvent.Generated( ParkTerrain terrain, int seed )
{
// Only the host can spawn the entrance path
if ( !Networking.IsHost )
return;
var entrancePos = SpawnEntrance( terrain );
SpawnPath( terrain, entrancePos, seed );
}
void ITerrainEvent.Loaded( ParkTerrain terrain )
{
SpawnEntrance( terrain );
}
private Vector2Int SpawnEntrance( ParkTerrain terrain )
{
// Kill any old procedural
foreach ( var obj in GameObject.Children.Where( x => (x.Flags & GameObjectFlags.NotSaved) == GameObjectFlags.NotSaved ).ToArray() )
{
obj.DestroyImmediate();
}
var entranceGridPos = new Vector2Int( terrain.Bounds.Left + 16, 0 );
var entranceHeight = terrain[entranceGridPos].MaxHeight;
// Spawn park entrance
var entrance = ParkEntrance.Clone( new CloneConfig() { Name = "Park Entrance", Parent = GameObject } );
entrance.WorldPosition = terrain.GridToWorld( new Vector3( entranceGridPos + 0.5f, entranceHeight ) );
entrance.Flags |= GameObjectFlags.NotSaved;
entrance.Enabled = true;
terrain.SetTiles( new RectInt( entranceGridPos - new Vector2Int( 1, 3 ), new Vector2Int( 3, 7 ) ), entranceHeight );
ITerrainEvent.Post( x => x.EntranceMoved( new Vector3Int( entranceGridPos.x, entranceGridPos.y, entranceHeight ) ) );
return entranceGridPos;
}
private void SpawnPath( ParkTerrain terrain, Vector2Int entranceGridPos, int seed )
{
// Spawn entrance path
var random = new Random( seed );
// Clear all existing paths
PathBuilder.Instance?.Clear();
SpawnPath( terrain, PathBuilder.Instance, entranceGridPos, terrain.Bounds.Position.x - entranceGridPos.x - 1, random );
SpawnPath( terrain, PathBuilder.Instance, entranceGridPos, random.Next( 6, 12 ), random );
}
private void ClearCell( Vector2Int pos )
{
var scenery = GridManager.Instance?
.GetCell( pos )?
.GetComponents<TerrainScenery>()
.ToArray();
if ( scenery is null ) return;
foreach ( var terrainScenery in scenery )
{
terrainScenery.GameObject.DestroyImmediate();
}
}
private void SpawnPath( ParkTerrain terrain, PathBuilder pathBuilder, Vector2Int start, int xLength, Random random )
{
var height = terrain[start].MaxHeight;
var pathY = start.y;
var sinceTurn = 0;
for ( var i = 0; i < Math.Abs( xLength ); ++i )
{
var pos = new Vector2Int( start.x + i * Math.Sign( xLength ), pathY );
terrain[pos] = TerrainTile.LevelGround( height );
ClearCell( pos );
pathBuilder.AddPath( pos );
if ( sinceTurn > 3 && random.NextSingle() < 0.25f )
{
var length = random.Next( 1, 5 );
var sign = random.Next( 0, 2 ) * 2 - 1;
for ( var j = 0; j < length; ++j )
{
pathY += sign;
pos = pos with { y = pathY };
ClearCell( pos );
terrain[pos] = TerrainTile.LevelGround( height );
pathBuilder.AddPath( pos );
}
sinceTurn = 0;
}
else
{
sinceTurn++;
}
}
}
}