using UnityEngine;
using System.Collections;
using System.Collections.Generic;
///
/// This class was created originally to change the faces of meshes that were covered by a fold.
/// Originally it figured out what vertices were covered, then began removing all faces that accessed that vertice.
/// Since we have changed to removing the meshcollider from the object instead, it now just checks if a point is covered
/// and once it finds one it removes the mesh colliders and moves on to the next object.
///
/// It can deal with objects with different tags to differentiate what you want to do.
/// Created by Douglas Weller
///
public class ChangeMeshScript : MonoBehaviour {
#region variables
#region bounds
///
/// predeclared variable for the max X point in a objects bounding box
///
public Vector3 foldMaxX;
///
/// predeclared variable for the min X point in a objects bounding box
///
public Vector3 foldMaxY;
///
/// predeclared variable for the max y point in a objects bounding box
///
public Vector3 foldMinX;
///
/// predeclared variable for the min y point in a objects bounding box
///
public Vector3 foldMinY;
private Vector3 boundsPoint1;
private Vector3 boundsPoint2;
private Vector3 boundsPoint3;
private Vector3 boundsPoint4;
///
/// This is the current max x point on the coverup rectangle
///
public Vector3 coverMaxX;
///
/// This is the current min x point on the coverup rectangle
///
public Vector3 coverMinX;
///
/// This is the current max y point on the coverup rectangle
///
public Vector3 coverMaxY;
///
/// This is the current min y point on the coverup rectangle
///
public Vector3 coverMinY;
///
/// Dictionary with the type of platform in the world
/// along with array of them
///
private Dictionary platFormsInWorld;
#endregion
#region Used For RevertChange
///
/// The list of objects that get their meshes changed.
///
// public List changedObjects;
///
/// List of the triangle array for each object that was changed.
///
// private List changedObjectsTriangles;
public Dictionary changedObjs;
public Dictionary origMeshCollider;
public Dictionary origMeshColliderTri;
#endregion
#endregion
// Use this for initialization
void Start () {
platFormsInWorld = new Dictionary();
origMeshCollider = new Dictionary();
changedObjs = new Dictionary();
GrabPlatformsInWorld("FoldPlatform");
GrabPlatformsInWorld("Platform");
}
///
/// Update this instance.
///
private void Update ()
{
}
///
/// Changes the mesh with the square, then double checks that the point
/// isn't in the missing triangles.
///
///
/// The transform of the object thats over platforms
///
///
/// Tthe tag of target platforms we want to remove
///
///
/// array of triangles no longer used by the object
///
public void ChangeMeshWithSquareIgnoreMissingTriangles(Transform tran, string target, int[] misTri)
{
List misTriLoc = new List();
//find bounds
Vector3[] verts = tran.GetComponent().mesh.vertices;
Bounds foldBounds = tran.GetComponent().mesh.bounds;
boundsPoint1 = tran.TransformPoint(foldBounds.max);
boundsPoint2 = tran.TransformPoint(foldBounds.min);
boundsPoint3 = tran.TransformPoint(new Vector3(foldBounds.min.x, foldBounds.max.y, foldBounds.max.z));
boundsPoint4 = tran.TransformPoint(new Vector3(foldBounds.max.x, foldBounds.min.y, foldBounds.min.z));
List possible = new List();
possible.Add(boundsPoint1);
possible.Add(boundsPoint2);
possible.Add(boundsPoint3);
possible.Add(boundsPoint4);
foldMaxX = FindLargestX(possible);//point with the largest x value
possible.Remove(foldMaxX); //removes it from possible so the next point can't have one point be max x and max y or min y
foldMinX = FindSmallestX(possible); //point with smallest x
possible.Remove(foldMinX); //removes it from possibles
foldMaxY = FindLargestY(possible);
possible.Remove(foldMaxY);
foldMinY = FindSmallestY(possible);
//This is a list of all the objects in the world that are platforms.
GameObject[] targetPlatInWorld;
Vector3[] backsideVerts = tran.GetComponent().mesh.vertices;
if(platFormsInWorld.TryGetValue(target, out targetPlatInWorld))
{
//This is a list of vertices from meshPoints that hit something during the raycast
//This is the current world space location for the current vertice checking whether to raycast
Vector3[] objVert; // This is the array that holds the vertices from the mesh that is currently being changed.
Mesh objMesh; // This is the Mesh for the GameObjects that are being affected by ChangeMeshScript.
//set the current missing triangle to their world space location at this moment
for(int i = 0; i < misTri.Length; i = i+ 3)
{
misTriLoc.Add(tran.TransformPoint(verts[misTri[i]]));
misTriLoc.Add(tran.TransformPoint(verts[misTri[i+1]]));
misTriLoc.Add(tran.TransformPoint(verts[misTri[i+2]]));
}
//After cycling through the array of vertices from meshPoints we cycle through the gameObjects that were hit
foreach(GameObject obj in targetPlatInWorld){
//set objMesh to the mesh of the current object, meshcollider and meshfilter are always the same
//but the meshfilter will always be there and unchanged, so this is the basis for objmesh
objMesh = obj.GetComponent().mesh;
//double checks that there is in fact a mesh on the object. If there isn't it skips this object and sends out a
//debug.log
if(objMesh == null)
{
Debug.Log(obj.name + " has NO MESHFILTER. So cannot delete mesh. Moving on.");
}
else
{
//set objVert to the vertices of the current object
objVert = objMesh.vertices;
//reset removeI so it is fresh for new object
//This is the vertice currently being checked, set to world space
Vector3 theCheckedVertice;
//This cycles through the verts of the object currently being checked
int i = 0;
while (i < objVert.Length) {
//set theCheckedVertice to world space using transformpoint
theCheckedVertice = obj.transform.TransformPoint(objVert[i]);
//This checks if the point is within the 2 triangles that make up the rectangle which is the fold.
if(PointInTriangle(theCheckedVertice, foldMinX, foldMaxY, foldMaxX) ||
PointInTriangle(theCheckedVertice, foldMinX, foldMinY, foldMaxX))
{
//check if the point is also inside the missing triangles
bool inMissing = false;
for(int k = 0; k < misTriLoc.Count; k = k + 3)
{
//if it is then set inMissing to true so we ignore it
if(PointInTriangle(theCheckedVertice, misTriLoc[k], misTriLoc[k+1],
misTriLoc[k+2]))
{
inMissing = true;
break;
}
}
//if it is not in there, its time to remove his meshcollider
if(!inMissing)
{
if(!changedObjs.ContainsKey(obj))
{
changedObjs.Add(obj, objMesh.triangles);
Destroy(obj.GetComponent());
}
break;
}
}
i++;
}
}
}
}
}
///
/// Changes the platforms with the basic square of the fold
///
///
/// The transform of object doing deleting platforms
///
///
/// the tag of the platform you want deleted
///
public void ChangeWithBasicMeshSquare(Transform tran, string target)
{
//grab bounds of object
Bounds foldBounds = tran.GetComponent().mesh.bounds;
boundsPoint1 = tran.TransformPoint(foldBounds.max);
boundsPoint2 = tran.TransformPoint(foldBounds.min);
boundsPoint3 = tran.TransformPoint(new Vector3(foldBounds.min.x, foldBounds.max.y, foldBounds.max.z));
boundsPoint4 = tran.TransformPoint(new Vector3(foldBounds.max.x, foldBounds.min.y, foldBounds.min.z));
//this will be a list of all the points that make triangle, and they will be removed as we learn where they reside
List possible = new List();
possible.Add(boundsPoint1);
possible.Add(boundsPoint2);
possible.Add(boundsPoint3);
possible.Add(boundsPoint4);
foldMaxX = FindLargestX(possible);//point with the largest x value
possible.Remove(foldMaxX); //removes it from possible so the next point can't have one point be max x and max y or min y
foldMinX = FindSmallestX(possible); //point with smallest x
possible.Remove(foldMinX); //removes it from possibles
foldMaxY = FindLargestY(possible);
possible.Remove(foldMaxY);
foldMinY = FindSmallestY(possible);
//the fold cover will never have points removed
//but players should be killed if they are inside of its radius
//so whenever a fold happens you check if this is the foldcover
//and if it is, you save these values so the player can check if he's inside
//the triangles that make up the square.
if(tran.gameObject.tag == "FoldCover")
{
coverMaxX = foldMaxX;
coverMinX = foldMinX;
coverMaxY = foldMaxY;
coverMinY = foldMinY;
}
//Now do the actual deletion
ChangeMeshWithSquare(tran, target);
}
///
/// Removes the meshcollider of platforms underneath the rectangular object which is a fold.
/// But, it allows it to be smaller or bigger than it actually is
///
///
/// The transform of the object that will be covering platforms.
///
///
/// The tag of the platforms we are trying to delete
///
///
/// The percentage you want removed or added from rectangle, such as 0.05(for rectangle 95% as big or
/// 1 for rectangle 2x as big
///
public void ChangeWithSmallerMeshSquare(Transform tran, string target, float percentSize)
{
Bounds foldBounds = tran.GetComponent().mesh.bounds;
//Change the bounds based on the ppercent size you want
float xChange = (foldBounds.max.x - foldBounds.min.x) * percentSize;
float yChange = (foldBounds.max.y - foldBounds.min.y) * percentSize;
//Debug.Log(xChange + " " + yChange);
//get an pointfrom each of the bounds to make the rectangle
boundsPoint1 = tran.TransformPoint(new Vector3(foldBounds.max.x-xChange, foldBounds.max.y-yChange, foldBounds.max.z));
boundsPoint2 = tran.TransformPoint(new Vector3(foldBounds.min.x+xChange, foldBounds.min.y+yChange, foldBounds.min.z));
boundsPoint3 = tran.TransformPoint(new Vector3(foldBounds.min.x+xChange, foldBounds.max.y-yChange, foldBounds.max.z));
boundsPoint4 = tran.TransformPoint(new Vector3(foldBounds.max.x-xChange, foldBounds.min.y+yChange, foldBounds.min.z));
//this will be a list of all the points that make triangle, and they will be removed as we learn where they reside
List possible = new List();
possible.Add(boundsPoint1);
possible.Add(boundsPoint2);
possible.Add(boundsPoint3);
possible.Add(boundsPoint4);
foldMaxX = FindLargestX(possible);//point with the largest x value
possible.Remove(foldMaxX); //removes it from possible so the next point can't have one point be max x and max y or min y
foldMinX = FindSmallestX(possible); //point with smallest x
possible.Remove(foldMinX); //removes it from possibles
foldMaxY = FindLargestY(possible);
possible.Remove(foldMaxY);
foldMinY = FindSmallestY(possible);
//do deletion
ChangeMeshWithSquare(tran, target);
}
///
/// Changes the mesh.
/// This is the transform of the GameObject that is being used to determine what vertices should be removed.
///
private void ChangeMeshWithSquare(Transform tran, string target)
{
//This is a list of all the objects in the world that are platforms.
GameObject[] targetPlatInWorld;
if(platFormsInWorld.TryGetValue(target, out targetPlatInWorld))
{
#region cycling through game objects for triangle deletion
Vector3[] objVert; // This is the array that holds the vertices from the mesh that is currently being changed.
Mesh objMesh; // This is the Mesh for the GameObjects that are being affected by ChangeMeshScript.
//After cycling through the array of vertices from meshPoints we cycle through the gameObjects that were hit
foreach(GameObject obj in targetPlatInWorld){
//set objMesh to the mesh of the current object, meshcollider and meshfilter are always the same
//but the meshfilter will always be there and unchanged, so this is the basis for objmesh
objMesh = obj.GetComponent().mesh;
//double checks that there is in fact a mesh on the object. If there isn't it skips this object and sends out a
if(objMesh == null)
{
Debug.Log(obj.name + " has NO MESHFILTER. So cannot delete mesh. Moving on.");
}
else
{
//set objVert to the vertices of the current object
objVert = objMesh.vertices;
int i = 0;
//This is the vertice currently being checked, set to world space
Vector3 theCheckedVertice;
//This cycles through the verts of the object currently being checked
while (i < objVert.Length) {
//set theCheckedVertice to world space using transformpoint
theCheckedVertice = obj.transform.TransformPoint(objVert[i]);
//This checks if the point is within the 2 triangles that make up the rectangle which is the fold.
if(PointInTriangle(theCheckedVertice, foldMinX, foldMaxY, foldMaxX) ||
PointInTriangle(theCheckedVertice, foldMinX, foldMinY, foldMaxX))
{
//make sure the gameobject hasn't already been added
if(!changedObjs.ContainsKey(obj))
changedObjs.Add(obj, objMesh.triangles);
Destroy(obj.GetComponent());//now remove the meshcollider
break;
}
i++;
}
}
}
}
}
#endregion
///
/// This deletes the meshcolliders of the platforms that have been 'torn out' by a tear, on the backside.
/// This function should only be called once, at some point after the tear. Its not right after tear
/// because it would make the tear lag more noticeable
///
///
/// List of triangles the backside no longer uses
///
///
/// The transform of the object with the missing triangles.
///
///
/// The tag the platforms we are removing will have.
///
public void DeletePlatformsFromMissingTriangles(int[] missingTri, Transform tran, string target)
{
List missingTriangles = new List();
Vector3[] verts = tran.GetComponent().mesh.vertices;//MeshCollider>().sharedMesh.vertices;
bool triExists = false;
//return missingTriangles;
//This is creating a list filled with the current world coordinites of the triangles that
//should removed since that part of the backside is gone.
for(int i = 0; i < missingTri.Length; i = i+3)
{
missingTriangles.Add(tran.TransformPoint(verts[missingTri[i]]));
missingTriangles.Add(tran.TransformPoint(verts[missingTri[i+1]]));
missingTriangles.Add(tran.TransformPoint(verts[missingTri[i+2]]));
}
Vector3 pointA;
Vector3 pointB;
Vector3 pointC;
GameObject[] tarPlatInWorld;
//Checks the dictionary for the target, if it finds it it then sends the list
//of gameobjects to tarPlatInWorld
if(platFormsInWorld.TryGetValue(target, out tarPlatInWorld))
{
Vector3[] objVert; // This is the array that holds the vertices from the mesh that is currently being changed.
Mesh objMesh; // This is the Mesh for the GameObjects that are being affected by ChangeMeshScript.
bool ifShouldBeRemoved;
Vector3 theCheckedVertice;
foreach(GameObject obj in tarPlatInWorld)
{
objMesh = obj.GetComponent().mesh;
int[] chngObjTri;
objVert = objMesh.vertices;
ifShouldBeRemoved = false;
for(int i = 0; i < missingTriangles.Count; i = i + 3)
{
pointA = missingTriangles[i];
pointB = missingTriangles[i+1];
pointC = missingTriangles[i+2];
objMesh = obj.GetComponent().mesh;
if(objMesh != null)
{
for(int j = 0; j < objVert.Length; j++)
{
theCheckedVertice = obj.transform.TransformPoint(objVert[j]);
//checks if the vert is inside this a triangle thats been removed
if(PointInTriangle(theCheckedVertice, pointA, pointB, pointC))
{
//if it has then break out out cause we don't need to check anymore
ifShouldBeRemoved = true;
break;
// obj.GetComponent().enabled = false;
// removeI.Add(j);
}
}
//since one vert was found within a triangle, the whole plat meshcollider
//is removed
if(ifShouldBeRemoved)
{
Destroy(obj.GetComponent());
//obj.SetActive(false);
//obj.GetComponent().enabled = false;
break;
}
}
}
}
}
}
///
/// Calculates the new set of triangles for a mesh.
/// It determines what vertices should not longer be used and removes any triangle
/// that uses it.
///
/// Code currently not in use since we changed from using one mesh per platform,
/// to have each platform made up of independant triangles.
///
///
/// Delete, list of verts that are to be removed
///
private int[] CalcTriangles(List indicesToDelete, int[] triObjTri)
{
//Debug.Log(indicesToDelete.Count);
//this is the current set of triangles before and after update
int[] triangles = triObjTri;
//This is a list of the new triangles
List newTrianglesList = new List();
//This is a bool that checks whether triangle should be removed or not
bool dontRemoveTriangle;
//this cycles through the array of triangles in triangles
//it uses i+3 because a triangle is always 3 points, so triangle
//is a array of sets of 3 points
int triLength = triangles.Length;
for(int i = 0; i < triLength; i = i+3)
{
//Debug.Log(triangles[i] + " " + triangles[i+1] + " " + triangles[i+2]);
//set to true to begin with
dontRemoveTriangle = true;
//this cycles through the indices in indicesTodelete
foreach(int j in indicesToDelete)
{
//it checks if any pointi n the triangle is that current indice
if((triangles[i] == j || triangles[i+1] == j || triangles[i+2] == j))
{
dontRemoveTriangle = false; //if it is it sets dontRemoveTriangle to false so it won't be added
break;
}
}
//if dontRemoveTriangle was never set to false it adds the current triangle to
//the newTrianglesList
if(dontRemoveTriangle)
{
newTrianglesList.Add(triangles[i]);
newTrianglesList.Add(triangles[i+1]);
newTrianglesList.Add (triangles[i+2]);
//Debug.Log("CHECK2");
}
}
//set newTrianglesList to an array and make triangles equal to it
triangles = newTrianglesList.ToArray();
return triangles;
//set the triangle for the objMesh equal to newtriangles
//triObjMesh.triangles = triangles;
//return triObjMesh;
}
#region Find Min and Max Vector3
///
/// Looks through array of vector3's for the one with max x.
///
///
/// The largest x vector3.
///
///
/// Array filled with the Vector3's we're looking for.
///
private Vector3 FindLargestX(List possibleMax)
{
Vector3 largest;
largest = possibleMax[0];
foreach( Vector3 currentV in possibleMax)
{
if(largest.x < currentV.x)
largest = currentV;
}
return largest;
}
///
/// Looks through array of vector3's for the one with max y.
///
///
/// The largest y vector3.
///
///
/// Array filled with the Vector3's we're looking for.
///
private Vector3 FindLargestY(List possibleMax)
{
Vector3 largest;
largest = possibleMax[0];
foreach( Vector3 currentV in possibleMax)
{
if(largest.y < currentV.y)
largest = currentV;
}
return largest;
}
///
/// Looks through array of vector3's for the one with minimum x.
///
///
/// The smallest x.
///
///
/// Array filled with the Vector3's we're looking for.
///
private Vector3 FindSmallestX(List possibleMin)
{
Vector3 smallest;
smallest = possibleMin[0];
foreach( Vector3 currentV in possibleMin)
{
if(smallest.x > currentV.x)
smallest = currentV;
}
return smallest;
}
///
/// Looks through array of vector3's for the one with minimum y.
///
///
/// The smallest y.
///
///
/// Array filled with the Vector3's we're looking for.
///
private Vector3 FindSmallestY(List possibleMin)
{
Vector3 smallest;
smallest = possibleMin[0];
foreach( Vector3 currentV in possibleMin)
{
if(smallest.y > currentV.y)
smallest = currentV;
}
return smallest;
}
#endregion
#region Calculate Triangle area, and if point is in it
//Function/Algorithm/Equation found from http://www.blackpawn.com/texts/pointinpoly/
private bool SameSide(Vector3 p1, Vector3 p2, Vector3 a,Vector3 b)
{
Vector3 cp1 = Vector3.Cross(b-a, p1-a);
Vector3 cp2 = Vector3.Cross(b-a, p2-a);
if(Vector3.Dot(cp1, cp2) >= 0) return true;
else return false;
}
//Function/Algorithm/Equation found from http://www.blackpawn.com/texts/pointinpoly/
///
/// Checks if the Vector3 point p, is somewhere in the triangle formed by the 3 points
/// a, b, and c.
///
private bool PointInTriangle(Vector3 p, Vector3 a,Vector3 b,Vector3 c)
{
// Compute vectors
Vector3 v0 = c - a;
Vector3 v1 = b - a;
Vector3 v2 = p - a;
// Compute dot products
float dot00 = Vector3.Dot(v0, v0);
float dot01 = Vector3.Dot(v0, v1);
float dot02 = Vector3.Dot(v0, v2);
float dot11 = Vector3.Dot(v1, v1);
float dot12 = Vector3.Dot(v1, v2);
// Compute barycentric coordinates
float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
if((u >= 0) && (v >= 0) && (u + v < 1))
return true;
else return false;
}
#endregion
#region Grab and Revert World
///
/// Grabs the targeted platforms in world. These are currently "FoldPlatforms" and
/// "Platforms", fold platforms are the ones that exist on the back side of the paper.
///
///
/// Tthe tag that the platform you want added is named.
///
public void GrabPlatformsInWorld(string target)
{
GameObject[] tempArray;
//Do this so when the script hits the Awake function it will be able to replace the old platforms with new ones
if(platFormsInWorld.ContainsKey(target))
{
tempArray = GameObject.FindGameObjectsWithTag(target);
platFormsInWorld.Remove(target);
platFormsInWorld.Add(target, tempArray);
}
else
{
tempArray = GameObject.FindGameObjectsWithTag(target);
platFormsInWorld.Add(target, tempArray);
}
}
///
/// Reverts the changes that were made by ChangeMesh
/// It will set all meshes that are in changedObj back to have meshcolliders.
///
public void RevertChanges()
{
//loops through each object to reset triangles
foreach(GameObject currentObj in changedObjs.Keys)
{
currentObj.AddComponent();
}
changedObjs.Clear();
}
///
/// Reverts the world platforms back to how they originally were. Since tear and fold both work by
/// removing meshcolliders, you just need to add them back in.
///
public void RevertWorld()
{
foreach(string tar in platFormsInWorld.Keys)
{
foreach(GameObject g in platFormsInWorld[tar])
{
if(g != null)
{
if(!g.GetComponent()) g.AddComponent();
}
}
}
changedObjs.Clear();
}
#endregion
}