diff --git a/aplib.net-demo/Assets/Scenes/ConnectedComponents.unity b/aplib.net-demo/Assets/Scenes/ConnectedComponents.unity
new file mode 100644
index 000000000..854c2cec5
--- /dev/null
+++ b/aplib.net-demo/Assets/Scenes/ConnectedComponents.unity
@@ -0,0 +1,432 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_OcclusionBakeSettings:
+ smallestOccluder: 5
+ smallestHole: 0.25
+ backfaceThreshold: 100
+ m_SceneGUID: 00000000000000000000000000000000
+ m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 9
+ m_Fog: 0
+ m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+ m_FogMode: 3
+ m_FogDensity: 0.01
+ m_LinearFogStart: 0
+ m_LinearFogEnd: 300
+ m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+ m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+ m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+ m_AmbientIntensity: 1
+ m_AmbientMode: 0
+ m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+ m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+ m_HaloStrength: 0.5
+ m_FlareStrength: 1
+ m_FlareFadeSpeed: 3
+ m_HaloTexture: {fileID: 0}
+ m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+ m_DefaultReflectionMode: 0
+ m_DefaultReflectionResolution: 128
+ m_ReflectionBounces: 1
+ m_ReflectionIntensity: 1
+ m_CustomReflection: {fileID: 0}
+ m_Sun: {fileID: 0}
+ m_IndirectSpecularColor: {r: 0.18029143, g: 0.22572419, b: 0.30693057, a: 1}
+ m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+ m_ObjectHideFlags: 0
+ serializedVersion: 12
+ m_GIWorkflowMode: 1
+ m_GISettings:
+ serializedVersion: 2
+ m_BounceScale: 1
+ m_IndirectOutputScale: 1
+ m_AlbedoBoost: 1
+ m_EnvironmentLightingMode: 0
+ m_EnableBakedLightmaps: 1
+ m_EnableRealtimeLightmaps: 0
+ m_LightmapEditorSettings:
+ serializedVersion: 12
+ m_Resolution: 2
+ m_BakeResolution: 40
+ m_AtlasSize: 1024
+ m_AO: 0
+ m_AOMaxDistance: 1
+ m_CompAOExponent: 1
+ m_CompAOExponentDirect: 0
+ m_ExtractAmbientOcclusion: 0
+ m_Padding: 2
+ m_LightmapParameters: {fileID: 0}
+ m_LightmapsBakeMode: 1
+ m_TextureCompression: 1
+ m_FinalGather: 0
+ m_FinalGatherFiltering: 1
+ m_FinalGatherRayCount: 256
+ m_ReflectionCompression: 2
+ m_MixedBakeMode: 2
+ m_BakeBackend: 1
+ m_PVRSampling: 1
+ m_PVRDirectSampleCount: 32
+ m_PVRSampleCount: 512
+ m_PVRBounces: 2
+ m_PVREnvironmentSampleCount: 256
+ m_PVREnvironmentReferencePointCount: 2048
+ m_PVRFilteringMode: 1
+ m_PVRDenoiserTypeDirect: 1
+ m_PVRDenoiserTypeIndirect: 1
+ m_PVRDenoiserTypeAO: 1
+ m_PVRFilterTypeDirect: 0
+ m_PVRFilterTypeIndirect: 0
+ m_PVRFilterTypeAO: 0
+ m_PVREnvironmentMIS: 1
+ m_PVRCulling: 1
+ m_PVRFilteringGaussRadiusDirect: 1
+ m_PVRFilteringGaussRadiusIndirect: 5
+ m_PVRFilteringGaussRadiusAO: 2
+ m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+ m_PVRFilteringAtrousPositionSigmaIndirect: 2
+ m_PVRFilteringAtrousPositionSigmaAO: 1
+ m_ExportTrainingData: 0
+ m_TrainingDataDestination: TrainingData
+ m_LightProbeSampleCountMultiplier: 4
+ m_LightingDataAsset: {fileID: 0}
+ m_LightingSettings: {fileID: 0}
+--- !u!196 &4
+NavMeshSettings:
+ serializedVersion: 2
+ m_ObjectHideFlags: 0
+ m_BuildSettings:
+ serializedVersion: 3
+ agentTypeID: 0
+ agentRadius: 0.5
+ agentHeight: 2
+ agentSlope: 45
+ agentClimb: 0.4
+ ledgeDropHeight: 0
+ maxJumpAcrossDistance: 0
+ minRegionArea: 2
+ manualCellSize: 0
+ cellSize: 0.16666667
+ manualTileSize: 0
+ tileSize: 256
+ buildHeightMesh: 0
+ maxJobWorkers: 0
+ preserveTilesOutsideBounds: 0
+ debug:
+ m_Flags: 0
+ m_NavMeshData: {fileID: 0}
+--- !u!1 &24601448
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 24601450}
+ - component: {fileID: 24601449}
+ - component: {fileID: 24601451}
+ m_Layer: 0
+ m_Name: Directional Light
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!108 &24601449
+Light:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 24601448}
+ m_Enabled: 1
+ serializedVersion: 10
+ m_Type: 1
+ m_Shape: 0
+ m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+ m_Intensity: 1
+ m_Range: 10
+ m_SpotAngle: 30
+ m_InnerSpotAngle: 21.80208
+ m_CookieSize: 10
+ m_Shadows:
+ m_Type: 2
+ m_Resolution: -1
+ m_CustomResolution: -1
+ m_Strength: 1
+ m_Bias: 0.05
+ m_NormalBias: 0.4
+ m_NearPlane: 0.2
+ m_CullingMatrixOverride:
+ e00: 1
+ e01: 0
+ e02: 0
+ e03: 0
+ e10: 0
+ e11: 1
+ e12: 0
+ e13: 0
+ e20: 0
+ e21: 0
+ e22: 1
+ e23: 0
+ e30: 0
+ e31: 0
+ e32: 0
+ e33: 1
+ m_UseCullingMatrixOverride: 0
+ m_Cookie: {fileID: 0}
+ m_DrawHalo: 0
+ m_Flare: {fileID: 0}
+ m_RenderMode: 0
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingLayerMask: 1
+ m_Lightmapping: 4
+ m_LightShadowCasterMode: 0
+ m_AreaSize: {x: 1, y: 1}
+ m_BounceIntensity: 1
+ m_ColorTemperature: 6570
+ m_UseColorTemperature: 0
+ m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+ m_UseBoundingSphereOverride: 0
+ m_UseViewFrustumForShadowCasterCull: 1
+ m_ShadowRadius: 0
+ m_ShadowAngle: 0
+--- !u!4 &24601450
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 24601448}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+ m_LocalPosition: {x: 0, y: 3, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!114 &24601451
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 24601448}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_Version: 3
+ m_UsePipelineSettings: 1
+ m_AdditionalLightsShadowResolutionTier: 2
+ m_LightLayerMask: 1
+ m_RenderingLayers: 1
+ m_CustomShadowLayers: 0
+ m_ShadowLayerMask: 1
+ m_ShadowRenderingLayers: 1
+ m_LightCookieSize: {x: 1, y: 1}
+ m_LightCookieOffset: {x: 0, y: 0}
+ m_SoftShadowQuality: 0
+--- !u!1 &1378037378
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1378037381}
+ - component: {fileID: 1378037380}
+ - component: {fileID: 1378037379}
+ - component: {fileID: 1378037382}
+ m_Layer: 0
+ m_Name: Main Camera
+ m_TagString: MainCamera
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!81 &1378037379
+AudioListener:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1378037378}
+ m_Enabled: 1
+--- !u!20 &1378037380
+Camera:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1378037378}
+ m_Enabled: 1
+ serializedVersion: 2
+ m_ClearFlags: 1
+ m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+ m_projectionMatrixMode: 1
+ m_GateFitMode: 2
+ m_FOVAxisMode: 0
+ m_Iso: 200
+ m_ShutterSpeed: 0.005
+ m_Aperture: 16
+ m_FocusDistance: 10
+ m_FocalLength: 50
+ m_BladeCount: 5
+ m_Curvature: {x: 2, y: 11}
+ m_BarrelClipping: 0.25
+ m_Anamorphism: 0
+ m_SensorSize: {x: 36, y: 24}
+ m_LensShift: {x: 0, y: 0}
+ m_NormalizedViewPortRect:
+ serializedVersion: 2
+ x: 0
+ y: 0
+ width: 1
+ height: 1
+ near clip plane: 0.3
+ far clip plane: 1000
+ field of view: 60
+ orthographic: 0
+ orthographic size: 5
+ m_Depth: -1
+ m_CullingMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_RenderingPath: -1
+ m_TargetTexture: {fileID: 0}
+ m_TargetDisplay: 0
+ m_TargetEye: 3
+ m_HDR: 1
+ m_AllowMSAA: 1
+ m_AllowDynamicResolution: 0
+ m_ForceIntoRT: 0
+ m_OcclusionCulling: 1
+ m_StereoConvergence: 10
+ m_StereoSeparation: 0.022
+--- !u!4 &1378037381
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1378037378}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0.428509, y: -0, z: -0, w: 0.9035376}
+ m_LocalPosition: {x: 34, y: 67.6, z: -23.4}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 50.746, y: 0, z: 0}
+--- !u!114 &1378037382
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1378037378}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ m_RenderShadows: 1
+ m_RequiresDepthTextureOption: 2
+ m_RequiresOpaqueTextureOption: 2
+ m_CameraType: 0
+ m_Cameras: []
+ m_RendererIndex: -1
+ m_VolumeLayerMask:
+ serializedVersion: 2
+ m_Bits: 1
+ m_VolumeTrigger: {fileID: 0}
+ m_VolumeFrameworkUpdateModeOption: 2
+ m_RenderPostProcessing: 0
+ m_Antialiasing: 0
+ m_AntialiasingQuality: 2
+ m_StopNaN: 0
+ m_Dithering: 0
+ m_ClearDepth: 1
+ m_AllowXRRendering: 1
+ m_AllowHDROutput: 1
+ m_UseScreenCoordOverride: 0
+ m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
+ m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
+ m_RequiresDepthTexture: 0
+ m_RequiresColorTexture: 0
+ m_Version: 2
+ m_TaaSettings:
+ quality: 3
+ frameInfluence: 0.1
+ jitterScale: 1
+ mipBias: 0
+ varianceClampScale: 0.9
+ contrastAdaptiveSharpening: 0
+--- !u!1 &1455078761
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1455078763}
+ - component: {fileID: 1455078762}
+ m_Layer: 0
+ m_Name: Grid
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!114 &1455078762
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1455078761}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: bf81f8d2562f471f8fe5ad818d5670e6, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ RoomObjects: {fileID: 11400000, guid: 9962865d7cc12a74abe02efdb8b7d072, type: 2}
+--- !u!4 &1455078763
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1455078761}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 0, y: 0, z: 0}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1660057539 &9223372036854775807
+SceneRoots:
+ m_ObjectHideFlags: 0
+ m_Roots:
+ - {fileID: 1378037381}
+ - {fileID: 24601450}
+ - {fileID: 1455078763}
diff --git a/aplib.net-demo/Assets/Scenes/ConnectedComponents.unity.meta b/aplib.net-demo/Assets/Scenes/ConnectedComponents.unity.meta
new file mode 100644
index 000000000..2564f124d
--- /dev/null
+++ b/aplib.net-demo/Assets/Scenes/ConnectedComponents.unity.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: d2f440c864cdffb6a93277b407cdc730
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/aplib.net-demo/Assets/Scripts/Tiles/Corner.cs b/aplib.net-demo/Assets/Scripts/Tiles/Corner.cs
index 1ad77894f..d79de9de4 100644
--- a/aplib.net-demo/Assets/Scripts/Tiles/Corner.cs
+++ b/aplib.net-demo/Assets/Scripts/Tiles/Corner.cs
@@ -5,15 +5,15 @@ namespace Assets.Scripts.Tiles
///
/// Represents a corner tile.
/// ___ ___
- /// | | |_|
- /// | |____
+ /// |_| | |
+ /// ____| |
/// |_____|
///
public class Corner : Tile
{
///
/// Initializes a new instance of the class.
- /// The default is a top-right corner.
+ /// The default is a top-left corner.
///
/// The amount of times to rotate the tile.
public Corner(int rotate = 0)
@@ -21,7 +21,7 @@ public Corner(int rotate = 0)
Rotation = rotate;
AllowedDirections = new List { false, false, false, false };
- int index = rotate % 4;
+ int index = (rotate + 3) % 4;
int nextIndex = (index + 1) % 4;
AllowedDirections[index] = true;
diff --git a/aplib.net-demo/Assets/Scripts/Tiles/Straight.cs b/aplib.net-demo/Assets/Scripts/Tiles/Straight.cs
index 43c25380d..a65eb1699 100644
--- a/aplib.net-demo/Assets/Scripts/Tiles/Straight.cs
+++ b/aplib.net-demo/Assets/Scripts/Tiles/Straight.cs
@@ -18,6 +18,7 @@ public class Straight : Tile
/// The amount of times to rotate the tile.
public Straight(int rotate = 0)
{
+ rotate %= 4;
Rotation = rotate;
bool isVertical = rotate % 2 == 0;
diff --git a/aplib.net-demo/Assets/Scripts/Tiles/TSection.cs b/aplib.net-demo/Assets/Scripts/Tiles/TSection.cs
index 716091df3..ea68e08a4 100644
--- a/aplib.net-demo/Assets/Scripts/Tiles/TSection.cs
+++ b/aplib.net-demo/Assets/Scripts/Tiles/TSection.cs
@@ -4,16 +4,16 @@ namespace Assets.Scripts.Tiles
{
///
/// Represents a T-section tile.
- /// _______
- /// |_____|
/// ___ ___
/// |_| |_|
+ /// _______
+ /// |_____|
///
public class TSection : Tile
{
///
/// Initializes a new instance of the class.
- /// The default is a T-section with the top side closed.
+ /// The default is a T-section with the top side opened.
///
/// The amount of times to rotate the tile.
public TSection(int rotate = 0)
@@ -21,7 +21,7 @@ public TSection(int rotate = 0)
Rotation = rotate;
AllowedDirections = new List { true, true, true, true };
- int index = rotate % 4;
+ int index = (rotate + 2) % 4;
AllowedDirections[index] = false;
}
diff --git a/aplib.net-demo/Assets/Scripts/Tiles/Tile.cs b/aplib.net-demo/Assets/Scripts/Tiles/Tile.cs
index faa76acc3..1477c7507 100644
--- a/aplib.net-demo/Assets/Scripts/Tiles/Tile.cs
+++ b/aplib.net-demo/Assets/Scripts/Tiles/Tile.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using UnityEngine;
namespace Assets.Scripts.Tiles
{
@@ -7,6 +8,8 @@ namespace Assets.Scripts.Tiles
///
public abstract class Tile
{
+ public GameObject GameObject { get; set; }
+
///
/// The rotation of the tile. 0 = 0 degrees, 1 = 90 degrees, 2 = 180 degrees, 3 = 270 degrees.
///
diff --git a/aplib.net-demo/Assets/Scripts/WFC/Cell.cs b/aplib.net-demo/Assets/Scripts/WFC/Cell.cs
index 15b3552ae..4518a7213 100644
--- a/aplib.net-demo/Assets/Scripts/WFC/Cell.cs
+++ b/aplib.net-demo/Assets/Scripts/WFC/Cell.cs
@@ -18,11 +18,18 @@ public class Cell
///
public List Candidates { get; set; }
+ public int X { get; }
+
+ public int Y { get; }
+
///
/// Initializes a new instance of the class.
- ///
- public Cell()
+ /// // TODO comment posX/Y on both constructors
+ public Cell(int posX, int posY)
{
+ X = posX;
+ Y = posY;
+
Tile = new Empty();
Candidates = new List()
{
@@ -49,8 +56,11 @@ public Cell()
/// Initializes a new instance of the class.
///
/// The possible tiles that can be placed in this cell.
- public Cell(List tiles)
+ public Cell(int posX, int posY, List tiles)
{
+ X = posX;
+ Y = posY;
+
Tile = new Empty();
Candidates = tiles;
}
diff --git a/aplib.net-demo/Assets/Scripts/WFC/Grid.cs b/aplib.net-demo/Assets/Scripts/WFC/Grid.cs
index 3efbe9608..ab1c44ccc 100644
--- a/aplib.net-demo/Assets/Scripts/WFC/Grid.cs
+++ b/aplib.net-demo/Assets/Scripts/WFC/Grid.cs
@@ -1,5 +1,8 @@
using Assets.Scripts.Tiles;
+using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
namespace Assets.Scripts.WFC
{
@@ -42,8 +45,8 @@ public Grid(int width, int height)
/// The y-coordinate of the cell.
public Cell this[int x, int y]
{
- get => _cells[(y * Width) + x];
- set => _cells[(y * Width) + x] = value;
+ get => _cells[CoordinatesToIndex(x, y)];
+ set => _cells[CoordinatesToIndex(x, y)] = value;
}
///
@@ -62,7 +65,18 @@ public Cell this[int index]
public void Init()
{
for (int i = 0; i < Width * Height; i++)
- _cells.Add(new Cell());
+ {
+ (int x, int y) = IndexToCoordinates(i);
+ _cells.Add(new Cell(x, y));
+ }
+ }
+
+ protected (int x, int y) IndexToCoordinates(int index) => (index % Width, index / Width);
+
+ protected int CoordinatesToIndex(int x, int y)
+ {
+ if (x >= Width || y >= Height) throw new IndexOutOfRangeException("Coordinates specified are out of range.");
+ return y * Width + x;
}
///
@@ -76,5 +90,90 @@ public void PlaceRoom(int x, int y, Room room)
this[x, y].Tile = room;
this[x, y].Candidates = new List();
}
+
+ public ICollection Get4NeighbouringCells(Cell cell)
+ {
+ ICollection neighbours = new Collection();
+ if (cell.X > 0) neighbours.Add(this[cell.X - 1, cell.Y]);
+ if (cell.X < Width - 1) neighbours.Add(this[cell.X + 1, cell.Y]);
+ if (cell.Y > 0) neighbours.Add(this[cell.X, cell.Y - 1]);
+ if (cell.Y < Height - 1) neighbours.Add(this[cell.X, cell.Y + 1]);
+ return neighbours;
+ }
+
+ public ICollection Get8NeighbouringCells(Cell cell)
+ {
+ ICollection neighbours = new Collection();
+ for (int i = -1; i < 2; i++)
+ {
+ if (cell.X + i < 0 || cell.X + i >= Width) continue; // No out of range
+ for (int j = -1; j < 2; j++)
+ {
+ if (i == j && i == 0) continue; // Skip the cell itself
+ if (cell.Y + j < 0 || cell.Y + j >= Height) continue; // No out of range
+ neighbours.Add(this[cell.X + i, cell.Y + j]);
+ }
+ }
+ return neighbours;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Assumes that the cells are assigned a tile
+ public ICollection GetConnectedNeighbours(Cell cell)
+ {
+ ICollection connectedNeighbours = new Collection();
+ ICollection neighbours = Get4NeighbouringCells(cell); // Note: no diagonal neighbours
+ foreach (Cell neighbour in neighbours)
+ {
+ if (cell.Tile.CanConnectInDirection(1) && neighbour.X > cell.X && neighbour.Tile.CanConnectInDirection(3))
+ connectedNeighbours.Add(neighbour);
+ else if (cell.Tile.CanConnectInDirection(3) && neighbour.X < cell.X && neighbour.Tile.CanConnectInDirection(1))
+ connectedNeighbours.Add(neighbour);
+ else if (cell.Tile.CanConnectInDirection(0) && neighbour.Y > cell.Y && neighbour.Tile.CanConnectInDirection(2))
+ connectedNeighbours.Add(neighbour);
+ else if (cell.Tile.CanConnectInDirection(2) && neighbour.Y < cell.Y && neighbour.Tile.CanConnectInDirection(0))
+ connectedNeighbours.Add(neighbour);
+ }
+
+ return connectedNeighbours;
+ }
+
+ public IList> DetermineConnectedComponents()
+ {
+ ISet unvisitedCells = new HashSet(_cells.Where(cell => cell.Tile is not Empty)); // Deep copy
+ IList> connectedComponents = new List>();
+
+ while (unvisitedCells.Any())
+ {
+ ISet connectedComponent = new HashSet();
+ connectedComponents.Add(connectedComponent);
+
+ // Determine connected component, which updates unvisitedCells and connectedComponent
+ DetermineSingleConnectedComponent(unvisitedCells, connectedComponent, unvisitedCells.First());
+ }
+
+ return connectedComponents;
+ }
+
+ public void DetermineSingleConnectedComponent(in ISet unvisitedCells, in ISet connectedComponent, Cell cell)
+ {
+ connectedComponent.Add(cell);
+ unvisitedCells.Remove(cell);
+
+ ICollection connectedNeighbours = GetConnectedNeighbours(cell);
+ foreach (Cell connectedNeighbour in connectedNeighbours)
+ {
+ if (!unvisitedCells.Contains(connectedNeighbour)) continue; // Already visited
+
+ connectedComponent.Add(connectedNeighbour);
+ unvisitedCells.Remove(connectedNeighbour);
+
+ DetermineSingleConnectedComponent(unvisitedCells, connectedComponent, connectedNeighbour);
+ }
+ }
}
}
diff --git a/aplib.net-demo/Assets/Scripts/WFC/GridPlacer.cs b/aplib.net-demo/Assets/Scripts/WFC/GridPlacer.cs
index 959677105..9eee5301d 100644
--- a/aplib.net-demo/Assets/Scripts/WFC/GridPlacer.cs
+++ b/aplib.net-demo/Assets/Scripts/WFC/GridPlacer.cs
@@ -1,5 +1,6 @@
using Assets.Scripts.Tiles;
using System.Collections.Generic;
+using System.Linq;
using UnityEngine;
namespace Assets.Scripts.WFC
@@ -35,7 +36,7 @@ public class GridPlacer : MonoBehaviour
public RoomObjects RoomObjects;
///
- /// Awake is called when the script instance is being loaded.
+ /// This contains the whole 'pipeline' of level generation, including initialising the grid and placing teleporters.
///
public void Awake()
{
@@ -52,6 +53,8 @@ public void Awake()
PlaceTile(x, y, _grid[x, y].Tile);
}
}
+
+ JoinConnectedComponentsWithTeleporters();
}
///
@@ -59,22 +62,22 @@ public void Awake()
///
public void TempFillFunction()
{
- _grid.PlaceRoom(2, 1, new Room(new List { false, true, true, false }));
-
- _grid.PlaceRoom(4, 4, new Room(new List { false, true, true, false }));
-
- // Road 1
- _grid[2, 2].Tile = new Straight();
- _grid[2, 3].Tile = new Straight();
- _grid[2, 4].Tile = new Corner(2);
- _grid[3, 4].Tile = new Straight(1);
-
- // Road 2
- _grid[3, 1].Tile = new Straight(1);
- _grid[4, 1].Tile = new TSection(3);
- _grid[4, 2].Tile = new Straight();
- _grid[4, 3].Tile = new Straight();
- _grid[4, 0].Tile = new DeadEnd();
+ _grid[0, 0].Tile = new TSection(3);
+ _grid[0, 1].Tile = new Crossing();
+ _grid[0, 2].Tile = new DeadEnd(2);
+ _grid[0, 3].Tile = new Straight(1);
+ _grid[1, 0].Tile = new TSection();
+ _grid[1, 1].Tile = new Straight();
+ _grid[1, 2].Tile = new Corner(2);
+ _grid[1, 3].Tile = new Crossing();
+ _grid[2, 0].Tile = new Corner();
+ _grid.PlaceRoom(2, 1, new Room(new List { true, true, true, true }));
+
+ _grid.PlaceRoom(3, 3, new Room(new List { true, true, true, true }));
+ _grid[3, 2].Tile = new Corner(1);
+ _grid[4, 2].Tile = new TSection(3);
+ _grid[4, 1].Tile = new Straight();
+ _grid.PlaceRoom(4, 0, new Room(new List { true, true, true, true }));
}
///
@@ -87,18 +90,40 @@ public void PlaceTile(int x, int y, Tile tile)
{
GameObject prefab = tile switch
{
- Corner _ => RoomObjects.Corner,
- Crossing _ => RoomObjects.Crossing,
- DeadEnd _ => RoomObjects.DeadEnd,
- Empty _ => RoomObjects.Empty,
- Room _ => RoomObjects.Room,
- Straight _ => RoomObjects.Straight,
- TSection _ => RoomObjects.TSection,
- _ => null
+ Corner => RoomObjects.Corner,
+ Crossing => RoomObjects.Crossing,
+ DeadEnd => RoomObjects.DeadEnd,
+ Empty => RoomObjects.Empty,
+ Room => RoomObjects.Room,
+ Straight => RoomObjects.Straight,
+ TSection => RoomObjects.TSection,
+ _ => null
};
if (prefab != null)
- _ = Instantiate(prefab, new Vector3(x * _tileSizeX, 0, y * _tileSizeY), Quaternion.Euler(0, tile.Rotation * _tileRotation, 0), transform);
+ {
+ tile.GameObject = Instantiate(prefab,
+ new Vector3(x * _tileSizeX, 0, y * _tileSizeY),
+ Quaternion.Euler(0, tile.Rotation * _tileRotation, 0),
+ transform);
+ }
}
+
+ private void JoinConnectedComponentsWithTeleporters()
+ {
+ IList> connectedComponents = _grid.DetermineConnectedComponents();
+
+ // We draw all the connected components individually
+ foreach (ISet connectedComponent in connectedComponents)
+ {
+ Color color = GetUnusedColor();
+ foreach (Cell cell in connectedComponent)
+ cell.Tile.GameObject.GetComponent().material.color = color;
+ }
+ }
+
+ private static Color[] _colors = { Color.red, Color.blue, Color.green, Color.yellow, Color.magenta, Color.cyan };
+ private static int _colorIndex = -1;
+ private static Color GetUnusedColor() => _colors[_colorIndex = (_colorIndex + 1) % _colors.Length];
}
}
| | | | | | | | | | | | | | | | | |