267 lines
6.0 KiB
C#
267 lines
6.0 KiB
C#
using Godot;
|
|
using Rokojori;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
[Tool, GlobalClass]
|
|
public partial class LevelGenerator : Action
|
|
{
|
|
[Export]
|
|
public int numWalls = -1;
|
|
|
|
[Export]
|
|
public int numRooms = 100;
|
|
|
|
[Export]
|
|
public int numRoomsEditor = 20;
|
|
|
|
[Export]
|
|
public float minRadius = 200;
|
|
|
|
[Export]
|
|
public float maxRadius = 4000;
|
|
|
|
[Export]
|
|
public Material roomCenterMaterial;
|
|
|
|
[Export]
|
|
public Material lowPolyMaterial;
|
|
|
|
[Export]
|
|
public int seed = -1;
|
|
|
|
[Export]
|
|
public float wallThickness = 2f;
|
|
|
|
[Export]
|
|
public float boundaryDensity = 10;
|
|
|
|
[Export]
|
|
public float boundarySize = 10;
|
|
|
|
[Export]
|
|
public PackedScene wall;
|
|
|
|
[Export]
|
|
public float wallSize = 1f;
|
|
|
|
[Export]
|
|
public PackedScene roomCenter;
|
|
|
|
[Export]
|
|
public RoomGeneratorEntry[] rooms;
|
|
|
|
[Export]
|
|
public TextureAttributes textureAttributes;
|
|
|
|
[Export]
|
|
public Node3D[] walls = [];
|
|
|
|
protected override void _OnTrigger()
|
|
{
|
|
numWalls = 0;
|
|
this.DestroyChildren();
|
|
|
|
var points = new List<Vector2>();
|
|
|
|
|
|
var boundaryPointSize = Circle.WithRadius( maxRadius ).circumference / boundaryDensity;
|
|
|
|
this.LogInfo( "Num Boundary Points", boundaryPointSize );
|
|
|
|
for ( int i = 0; i < boundaryPointSize; i++ )
|
|
{
|
|
var t = (float) i / ( float ) ( boundaryPointSize );
|
|
|
|
var angle = t * Mathf.Pi * 2f;
|
|
|
|
var boundaryPoint = Math2D.Circle( angle, maxRadius + boundarySize );
|
|
|
|
points.Add( boundaryPoint );
|
|
}
|
|
|
|
points.Add( Vector2.Zero );
|
|
|
|
var random = seed == -1 ? LCG.Randomized() : LCG.WithSeed( seed );
|
|
|
|
var rooms = Engine.IsEditorHint() ? numRoomsEditor : numRooms;
|
|
|
|
for ( int i = 0; i < rooms; i++ )
|
|
{
|
|
var p = random.InRectangle( Vector2.One * -maxRadius, Vector2.One * maxRadius );
|
|
|
|
if ( p.Length() < minRadius || p.Length() >= maxRadius )
|
|
{
|
|
p = random.InRectangle( Vector2.One * -maxRadius, Vector2.One * maxRadius );
|
|
}
|
|
|
|
if ( p.Length() < minRadius || p.Length() >= maxRadius )
|
|
{
|
|
p = random.InRectangle( Vector2.One * -maxRadius, Vector2.One * maxRadius );
|
|
}
|
|
|
|
if ( p.Length() < minRadius || p.Length() >= maxRadius )
|
|
{
|
|
if ( p.Length() == 0 )
|
|
{
|
|
p = Vector2.One;
|
|
}
|
|
|
|
p = p.Normalized() * random.Range( minRadius, maxRadius );
|
|
}
|
|
|
|
points.Add( p );
|
|
}
|
|
|
|
|
|
var voronoi = Voronoi2D.CreateFromCellPoints( points );
|
|
|
|
var lowMG = new MeshGeometry();
|
|
lowMG.colors = new List<Color>();
|
|
|
|
var wallIndex = 0;
|
|
var wallsList =new List<Node3D>();
|
|
voronoi.edges.ForEach(
|
|
( e )=>
|
|
{
|
|
var w = CreateWallsAtEdge( e, voronoi, lowMG, wallIndex );
|
|
wallsList.Add( w );
|
|
wallIndex ++;
|
|
|
|
}
|
|
);
|
|
|
|
walls = wallsList.ToArray();
|
|
|
|
// wallActi
|
|
|
|
var lowPolyMI = this.CreateChild<MeshInstance3D>( "LowPoly" );
|
|
|
|
lowPolyMI.Mesh = lowMG.GenerateMesh();
|
|
lowPolyMI.Mesh.SurfaceSetMaterial( 0, lowPolyMaterial );
|
|
|
|
voronoi.cells.ForEach(
|
|
( vc )=>
|
|
{
|
|
if ( vc.index < boundaryPointSize )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var rg = GetRoomGenerator( random );
|
|
rg.GenerateRoom( this, vc );
|
|
// var p = voronoi.cellPoints[ vc.index ];
|
|
// var center = p.To3DXZ();
|
|
|
|
// var room = this.CreateChild<Node3D>( roomCenter, "Center" + vc.index );
|
|
// room.GlobalPosition = center;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
RoomGenerator GetRoomGenerator( RandomEngine random )
|
|
{
|
|
var index = random.IndexFromUnnormalizedWeights( rooms.Map( r => r.probability ).ToList() );
|
|
|
|
return rooms[ index ].room;
|
|
}
|
|
public override void _Ready()
|
|
{
|
|
this.LogInfo( "Ready", this.walls.Length );
|
|
|
|
InitializeWalls();
|
|
}
|
|
|
|
async Task InitializeWalls()
|
|
{
|
|
var frames = 0;
|
|
|
|
await this.RequestNextFrame();
|
|
|
|
|
|
|
|
var index = 0;
|
|
|
|
this.ForEachDirectChild<Node3D>(
|
|
( n )=>
|
|
{
|
|
if ( ! n.Name.ToString().Contains( "Wall" ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var setAtt = n.GetAll<SetTextureAttributeChannel>();
|
|
|
|
setAtt.ForEach( s => s.index = index );
|
|
index ++;
|
|
|
|
// this.LogInfo( "SetAtt", HierarchyName.Of( n ), setAtt.index );
|
|
}
|
|
);
|
|
}
|
|
|
|
public Node3D CreateWallsAtEdge( Voronoi2D.Edge edge, Voronoi2D v, MeshGeometry output, int wallIndex )
|
|
{
|
|
var p0 = v.boundaryPoints[ edge.start ];
|
|
var p1 = v.boundaryPoints[ edge.end ];
|
|
var center = p0.Lerp( p1, 0.5f ).To3DXZ();
|
|
|
|
var yaw = Math3D.GlobalYaw( p0.To3DXZ() - p1.To3DXZ() );
|
|
|
|
var length = ( p1 - p0 ).Length();
|
|
|
|
var numWalls = length / wallSize;
|
|
|
|
var wallObject = this.CreateChild<Node3D>( wall, "Wall " + wallIndex );
|
|
wallObject.GlobalPosition = center;
|
|
wallObject.SetGlobalYaw( yaw + Mathf.Pi * 0.5f );
|
|
wallObject.Scale = new Vector3( numWalls, 1, 1 );
|
|
|
|
var setTexturesAttributes= wallObject.GetAll<SetTextureAttributeChannel>();
|
|
|
|
this.LogInfo( "Num walls:", setTexturesAttributes.Count );
|
|
|
|
setTexturesAttributes.ForEach(
|
|
( st )=>
|
|
{
|
|
st.index = wallIndex;
|
|
st.textureAttributes = textureAttributes;
|
|
|
|
this.LogInfo( "Set Index:", st.index, HierarchyName.Of( st ) );
|
|
}
|
|
);
|
|
|
|
|
|
var lowPolyWall = MeshGeometry.BillboardQuad();
|
|
var trsf = Math3D.TRS( center, Math3D.RotateY( yaw + Mathf.Pi * 0.5f ), new Vector3( length, 250, 1 ) );
|
|
lowPolyWall.ApplyTransform( trsf );
|
|
|
|
var colorIndex = MathX.FlatIndexToMultiIndex( wallIndex, new Vector2I( 255, 255 ) );
|
|
|
|
var color = new Color( colorIndex.X / 255f, colorIndex.Y / 255f, 0 );
|
|
|
|
// this.LogInfo( wallIndex, ">>", colorIndex.X, colorIndex.Y, color );
|
|
|
|
lowPolyWall.SetColor( color );
|
|
output.Add( lowPolyWall );
|
|
|
|
this.numWalls ++;
|
|
|
|
return wallObject;
|
|
|
|
// for ( int i = 0; i < numWalls; i++ )
|
|
// {
|
|
// var t = i / ( float )(numWalls );
|
|
// var p = p0.Lerp( p1, t );
|
|
|
|
// var wallObject = this.CreateChild<Node3D>( wall );
|
|
// wallObject.GlobalPosition = p.To3DXZ();
|
|
// wallObject.SetGlobalYaw( yaw );
|
|
// }
|
|
}
|
|
} |