private void CheckDoorwayForwardVectors(DungeonFlow flow, DungeonValidator validator, Dictionary <GameObject, Doorway[]> tileDoorways) { foreach (var pair in tileDoorways) { var tile = pair.Key; var bounds = UnityUtil.CalculateObjectBounds(tile, true, false); foreach (var doorway in pair.Value) { Vector3 forwardVector = doorway.transform.forward; if (!IsAxisAligned(forwardVector)) { validator.AddError("Doorway '{0}' in tile '{1}' has an invalid rotation. the forward vector is not axis-aligned", tile, doorway.name, tile.name); } else { Vector3 centerToDoorway = (doorway.transform.position - bounds.center).normalized; float angle = Vector3.Angle(centerToDoorway, forwardVector); if (angle > 85f) { validator.AddError("Doorway '{0}' in tile '{1}' is facing the wrong way. Doorways should face outwards from the tile (local z-axis, blue line)", tile, doorway.name, tile.name); } } } } }
private void CheckArchetypes(DungeonFlow flow, DungeonValidator validator) { var archetypes = flow.GetUsedArchetypes(); foreach (var archetype in archetypes) { if (archetype == null) { continue; } if (archetype.TileSets.Count == 0) { validator.AddError("The archetype '{0}' has no tile sets assigned", archetype, archetype.name); } else { foreach (var tileSet in archetype.TileSets) { if (tileSet == null) { validator.AddError("The archetype '{0}' has a missing tile set", archetype, archetype.name); } } } foreach (var tileSet in archetype.BranchCapTileSets) { if (tileSet == null) { validator.AddError("Archetype '{0}' has a missing branch cap tile set", archetype, archetype.name); } } } }
private void CheckNodes(DungeonFlow flow, DungeonValidator validator) { if (flow.Nodes.Count < 2) { validator.AddError("The dungeon flow must contain at least two nodes"); } foreach (var node in flow.Nodes) { if (node.TileSets.Count == 0) { validator.AddError("The node '{0}' in the dungeon flow graph has no tile sets applied", node.Label); } else { foreach (var tileSet in node.TileSets) { if (tileSet == null) { validator.AddError("Node '{0}' in your dungeon flow graph has an unset tileset value", node.Label); } } } } }
private void CheckDoorwayUpVectors(DungeonFlow flow, DungeonValidator validator, Dictionary <GameObject, Doorway[]> tileDoorways) { var doorwaysByUpVector = new Dictionary <Vector3, List <DoorwayInfo> >(); foreach (var pair in tileDoorways) { foreach (var doorway in pair.Value) { Vector3 upVector = doorway.transform.up; List <DoorwayInfo> doorwaySet = null; foreach (var existingPair in doorwaysByUpVector) { if (Vector3.Angle(upVector, existingPair.Key) <= AngleThreshold) { doorwaySet = existingPair.Value; } } if (doorwaySet == null) { doorwaySet = new List <DoorwayInfo>(); doorwaysByUpVector[upVector] = doorwaySet; } doorwaySet.Add(new DoorwayInfo(doorway, pair.Key)); } } if (doorwaysByUpVector.Count > 1) { Vector3 mostCommonUpVector = doorwaysByUpVector.OrderByDescending(x => x.Value.Count).First().Key; if (!IsAxisAligned(mostCommonUpVector)) { validator.AddError("The most common doorway up vector is not axis-aligned"); } foreach (var pair in doorwaysByUpVector) { if (pair.Key == mostCommonUpVector) { continue; } foreach (var info in pair.Value) { validator.AddError("Doorway '{0}' in tile '{1}' has an invalid rotation. The most common up-vector among doorways is {2}", info.TilePrefab, info.Doorway.name, info.TilePrefab.name, mostCommonUpVector); } } } }
private void CheckDoorwayCount(DungeonFlow flow, DungeonValidator validator) { var pathTileSets = new List <TileSet>(); foreach (var node in flow.Nodes) { if (node.NodeType != NodeType.Start && node.NodeType != NodeType.Goal) { pathTileSets.AddRange(node.TileSets); } } foreach (var line in flow.Lines) { foreach (var archetype in line.DungeonArchetypes) { pathTileSets.AddRange(archetype.TileSets); } } var pathTiles = pathTileSets.SelectMany(ts => ts.TileWeights.Weights.Select(w => w.Value)).Where(t => t != null); foreach (var tile in pathTiles) { int doorwayCount = tile.GetComponentsInChildren <Doorway>(true).Count(); if (doorwayCount < 2) { validator.AddError("Tile '{0}' does not have enough doorways. Two doorways are required for all tiles except those that appear exclusively as a start node, goal node, or branch cap", tile, tile.name); } } }
public void Validate(DungeonFlow flow, DungeonValidator validator) { // Check DungeonFlow if (flow == null) { validator.AddError("No DungeonFlow is assigned"); return; } CheckLineSegments(flow, validator); CheckNodes(flow, validator); CheckArchetypes(flow, validator); CheckTileSets(flow, validator); }
private void CheckLineSegments(DungeonFlow flow, DungeonValidator validator) { if (flow.Lines.Count < 1) { validator.AddError("The dungeon flow must contain at least one line segment"); } foreach (var line in flow.Lines) { if (line.DungeonArchetypes.Count == 0) { validator.AddError("A line segments in your dungeon flow graph has no archetype applied"); } foreach (var archetype in line.DungeonArchetypes) { if (archetype == null) { validator.AddError("A line segment in your dungeon flow graph has an unset archetype value"); } } } }