Added player character and step in/out of dialogue in scene 101
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEngine.ProBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a boundary edge where three faces meet. It holds references to:
|
||||
/// - The <see cref="Face" /> connected to this edge
|
||||
/// - An <see cref="EdgeLookup" /> for finding coincident vertices on this edge
|
||||
/// - The previous and next winged edges in its triangle
|
||||
/// - The common ([coincident](../manual/gloss.html#coincident)) winged edge, called the 'opposite' edge
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// ```
|
||||
/// . / (face) /
|
||||
/// . prev / / next
|
||||
/// . / edge /
|
||||
/// . /_ _ _ _ _ _ _/
|
||||
/// . |- - - - - - -|
|
||||
/// . | opposite |
|
||||
/// . | |
|
||||
/// . | |
|
||||
/// . | |
|
||||
/// ```
|
||||
/// </example>
|
||||
public sealed class WingedEdge : IEquatable<WingedEdge>
|
||||
{
|
||||
static readonly Dictionary<Edge, WingedEdge> k_OppositeEdgeDictionary = new Dictionary<Edge, WingedEdge>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local and shared edge that this edge belongs to.
|
||||
/// </summary>
|
||||
public EdgeLookup edge { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the connected face that this wing belongs to.
|
||||
/// </summary>
|
||||
public Face face { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WingedEdge that is connected to the `edge.y` vertex.
|
||||
/// </summary>
|
||||
public WingedEdge next { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WingedEdge that is connected to the `edge.x` vertex.
|
||||
/// </summary>
|
||||
public WingedEdge previous { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WingedEdge that is on the "opposite" side of this edge.
|
||||
/// </summary>
|
||||
public WingedEdge opposite { get; private set; }
|
||||
|
||||
WingedEdge() {}
|
||||
|
||||
/// <summary>
|
||||
/// Tests to see whether the specified Edge is equal to the local edge, disregarding other values.
|
||||
/// </summary>
|
||||
/// <param name="other">The WingedEdge to compare against.</param>
|
||||
/// <returns>True if the local edges are equal, false if not.</returns>
|
||||
public bool Equals(WingedEdge other)
|
||||
{
|
||||
return !ReferenceEquals(other, null) && edge.local.Equals(other.edge.local);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests to see whether the specified object is equal to the local edge, disregarding other values.
|
||||
/// </summary>
|
||||
/// <param name="obj">The WingedEdge to compare against.</param>
|
||||
/// <returns>True if the local edges are equal, false if not.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
WingedEdge be = obj as WingedEdge;
|
||||
|
||||
if (be != null && this.Equals(be))
|
||||
return true;
|
||||
|
||||
if (obj is Edge && this.edge.local.Equals((Edge)obj))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this edge.
|
||||
/// </summary>
|
||||
/// <returns>WingedEdge comparison only considers the local edge. As such, this returns the local edge hashcode.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return edge.local.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of edges connected in this sequence.
|
||||
/// </summary>
|
||||
/// <returns>The number of WingedEdges found with the <see cref="next">WingedEdge.next</see> property.</returns>
|
||||
public int Count()
|
||||
{
|
||||
WingedEdge current = this;
|
||||
int count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
count++;
|
||||
current = current.next;
|
||||
}
|
||||
while (current != null && !ReferenceEquals(current, this));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representation of the winged edge.
|
||||
/// </summary>
|
||||
/// <returns>String formatted as follows:
|
||||
///
|
||||
/// `Common: [common]`
|
||||
///
|
||||
/// `Local: [local]`
|
||||
///
|
||||
/// `Opposite: [opposite]`
|
||||
///
|
||||
/// `Face: [face]`</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Common: {0}\nLocal: {1}\nOpposite: {2}\nFace: {3}",
|
||||
edge.common.ToString(),
|
||||
edge.local.ToString(),
|
||||
opposite == null ? "null" : opposite.edge.ToString(),
|
||||
face.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given two adjacent triangle wings, attempt to create a single quad.
|
||||
/// </summary>
|
||||
/// <param name="left"></param>
|
||||
/// <param name="right"></param>
|
||||
/// <returns></returns>
|
||||
internal static int[] MakeQuad(WingedEdge left, WingedEdge right)
|
||||
{
|
||||
// Both faces must be triangles in order to be considered a quad when combined
|
||||
if (left.Count() != 3 || right.Count() != 3)
|
||||
return null;
|
||||
|
||||
EdgeLookup[] all = new EdgeLookup[6]
|
||||
{
|
||||
left.edge,
|
||||
left.next.edge,
|
||||
left.next.next.edge,
|
||||
right.edge,
|
||||
right.next.edge,
|
||||
right.next.next.edge
|
||||
};
|
||||
|
||||
int[] dup = new int[6];
|
||||
int matches = 0;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
for (int n = 3; n < 6; n++)
|
||||
{
|
||||
if (all[i].Equals(all[n]))
|
||||
{
|
||||
matches++;
|
||||
dup[i] = 1;
|
||||
dup[n] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Edges are either not adjacent, or share more than one edge
|
||||
if (matches != 1)
|
||||
return null;
|
||||
|
||||
int qi = 0;
|
||||
|
||||
EdgeLookup[] edges = new EdgeLookup[4];
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
if (dup[i] < 1)
|
||||
edges[qi++] = all[i];
|
||||
|
||||
int[] quad = new int[4] { edges[0].local.a, edges[0].local.b, -1, -1 };
|
||||
|
||||
int c1 = edges[0].common.b, c2 = -1;
|
||||
|
||||
if (edges[1].common.a == c1)
|
||||
{
|
||||
quad[2] = edges[1].local.b;
|
||||
c2 = edges[1].common.b;
|
||||
}
|
||||
else if (edges[2].common.a == c1)
|
||||
{
|
||||
quad[2] = edges[2].local.b;
|
||||
c2 = edges[2].common.b;
|
||||
}
|
||||
else if (edges[3].common.a == c1)
|
||||
{
|
||||
quad[2] = edges[3].local.b;
|
||||
c2 = edges[3].common.b;
|
||||
}
|
||||
|
||||
if (edges[1].common.a == c2)
|
||||
quad[3] = edges[1].local.b;
|
||||
else if (edges[2].common.a == c2)
|
||||
quad[3] = edges[2].local.b;
|
||||
else if (edges[3].common.a == c2)
|
||||
quad[3] = edges[3].local.b;
|
||||
|
||||
if (quad[2] == -1 || quad[3] == -1)
|
||||
return null;
|
||||
|
||||
return quad;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see cref="previous">WingedEdge.previous</see> or
|
||||
/// <see cref="next">WingedEdge.next</see> if it contains the specified common (shared) index.
|
||||
/// </summary>
|
||||
/// <param name="common">The common index to search next and previous for.</param>
|
||||
/// <returns>The next or previous WingedEdge that contains common; or null if not found.</returns>
|
||||
public WingedEdge GetAdjacentEdgeWithCommonIndex(int common)
|
||||
{
|
||||
if (next.edge.common.Contains(common))
|
||||
return next;
|
||||
else if (previous.edge.common.Contains(common))
|
||||
return previous;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Orders a face's edges in sequence, starting from the first edge.
|
||||
/// </summary>
|
||||
/// <param name="face">The source face.</param>
|
||||
/// <returns>A new set of edges where each edge's Y value matches the next edge's X value.</returns>
|
||||
public static List<Edge> SortEdgesByAdjacency(Face face)
|
||||
{
|
||||
if (face == null || face.edgesInternal == null)
|
||||
throw new ArgumentNullException("face");
|
||||
List<Edge> edges = new List<Edge>(face.edgesInternal);
|
||||
SortEdgesByAdjacency(edges);
|
||||
return edges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the specified list of edges by adjacency, such that each edge's common Y value matches the next edge's common X value.
|
||||
/// </summary>
|
||||
/// <param name="edges">The edges to sort in-place.</param>
|
||||
public static void SortEdgesByAdjacency(List<Edge> edges)
|
||||
{
|
||||
if (edges == null)
|
||||
throw new ArgumentNullException("edges");
|
||||
|
||||
for (int i = 1; i < edges.Count; i++)
|
||||
{
|
||||
int want = edges[i - 1].b;
|
||||
|
||||
for (int n = i + 1; n < edges.Count; n++)
|
||||
{
|
||||
if (edges[n].a == want || edges[n].b == want)
|
||||
{
|
||||
Edge swap = edges[n];
|
||||
edges[n] = edges[i];
|
||||
edges[i] = swap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dictionary of common indices and all WingedEdge values that touch each common index.
|
||||
/// </summary>
|
||||
/// <param name="wings">The list of WingedEdges to search.</param>
|
||||
/// <returns>A dictionary where each key is a common index mapped to a list of each winged edge that touches it.</returns>
|
||||
public static Dictionary<int, List<WingedEdge>> GetSpokes(List<WingedEdge> wings)
|
||||
{
|
||||
if (wings == null)
|
||||
throw new ArgumentNullException("wings");
|
||||
|
||||
Dictionary<int, List<WingedEdge>> spokes = new Dictionary<int, List<WingedEdge>>();
|
||||
List<WingedEdge> l = null;
|
||||
|
||||
for (int i = 0; i < wings.Count; i++)
|
||||
{
|
||||
if (spokes.TryGetValue(wings[i].edge.common.a, out l))
|
||||
l.Add(wings[i]);
|
||||
else
|
||||
spokes.Add(wings[i].edge.common.a, new List<WingedEdge>() { wings[i] });
|
||||
|
||||
if (spokes.TryGetValue(wings[i].edge.common.b, out l))
|
||||
l.Add(wings[i]);
|
||||
else
|
||||
spokes.Add(wings[i].edge.common.b, new List<WingedEdge>() { wings[i] });
|
||||
}
|
||||
|
||||
return spokes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given a set of winged edges and list of common indexes, attempt to create a complete path of indexes where each is connected by edge.
|
||||
/// <br />
|
||||
/// May be clockwise or counter-clockwise ordered, or null if no path is found.
|
||||
/// </summary>
|
||||
/// <param name="wings">The wings to be sorted.</param>
|
||||
/// <param name="common">The common indexes to be sorted.</param>
|
||||
/// <returns></returns>
|
||||
internal static List<int> SortCommonIndexesByAdjacency(List<WingedEdge> wings, HashSet<int> common)
|
||||
{
|
||||
List<Edge> matches = wings.Where(x => common.Contains(x.edge.common.a) && common.Contains(x.edge.common.b)).Select(y => y.edge.common).ToList();
|
||||
|
||||
// if edge count != index count there isn't a full perimeter
|
||||
if (matches.Count != common.Count)
|
||||
return null;
|
||||
|
||||
SortEdgesByAdjacency(matches);
|
||||
return matches.ConvertAll(x => x.a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new list of WingedEdge values from all faces on the specified ProBuilder mesh.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh containing the faces to analyze.</param>
|
||||
/// <param name="oneWingPerFace">Set this parameter to true to restrict the list to include only one WingedEdge per face. The default value is false.</param>
|
||||
/// <returns>A new list of WingedEdge values gathered from the <see cref="ProBuilderMesh.faces">ProBuilderMesh.faces</see>.</returns>
|
||||
public static List<WingedEdge> GetWingedEdges(ProBuilderMesh mesh, bool oneWingPerFace = false)
|
||||
{
|
||||
if (mesh == null)
|
||||
throw new ArgumentNullException("mesh");
|
||||
|
||||
return GetWingedEdges(mesh, mesh.facesInternal, oneWingPerFace);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new list of WingedEdge values from a specific set of faces on the specified ProBuilder mesh.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh containing the faces to analyze.</param>
|
||||
/// <param name="faces">The collection of faces to include in the WingedEdge list.</param>
|
||||
/// <param name="oneWingPerFace">Set this parameter to true to restrict the list to include only one WingedEdge per face. The default value is false.</param>
|
||||
/// <returns>A new list of WingedEdge values gathered from the specified faces.</returns>
|
||||
public static List<WingedEdge> GetWingedEdges(ProBuilderMesh mesh, IEnumerable<Face> faces, bool oneWingPerFace = false)
|
||||
{
|
||||
if (mesh == null)
|
||||
throw new ArgumentNullException("mesh");
|
||||
|
||||
var lookup = mesh.sharedVertexLookup;
|
||||
|
||||
List<WingedEdge> winged = new List<WingedEdge>();
|
||||
k_OppositeEdgeDictionary.Clear();
|
||||
|
||||
foreach (Face f in faces)
|
||||
{
|
||||
List<Edge> edges = SortEdgesByAdjacency(f);
|
||||
int edgeLength = edges.Count;
|
||||
WingedEdge first = null, prev = null;
|
||||
|
||||
for (int n = 0; n < edgeLength; n++)
|
||||
{
|
||||
Edge e = edges[n];
|
||||
|
||||
WingedEdge w = new WingedEdge();
|
||||
w.edge = new EdgeLookup(lookup[e.a], lookup[e.b], e.a, e.b);
|
||||
w.face = f;
|
||||
if (n < 1)
|
||||
first = w;
|
||||
|
||||
if (n > 0)
|
||||
{
|
||||
w.previous = prev;
|
||||
prev.next = w;
|
||||
}
|
||||
|
||||
if (n == edgeLength - 1)
|
||||
{
|
||||
w.next = first;
|
||||
first.previous = w;
|
||||
}
|
||||
|
||||
prev = w;
|
||||
|
||||
WingedEdge opp;
|
||||
|
||||
if (k_OppositeEdgeDictionary.TryGetValue(w.edge.common, out opp))
|
||||
{
|
||||
opp.opposite = w;
|
||||
w.opposite = opp;
|
||||
}
|
||||
else
|
||||
{
|
||||
w.opposite = null;
|
||||
k_OppositeEdgeDictionary.Add(w.edge.common, w);
|
||||
}
|
||||
|
||||
if (!oneWingPerFace || n < 1)
|
||||
winged.Add(w);
|
||||
}
|
||||
}
|
||||
|
||||
return winged;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user