Unity3D Building Damage Tutorial- Part VI - Walls between Alias and Twin

Ok, so lets say, that we have a thick mesh, than delete a Alias and its Twin. As a result, we will have something like that in photo: Between the Alias and its Twin, there is a void. Moreover, as inner and outer cube are visible on one side, some parts are transparent. Okay, so what we have to do is to produce walls between.

Plan
Lets look at this hole. We have 1-6 outside Aliases, and offset of 100 so inside Aliases (twins) are 101-106. As we know, mesh is made of triangles. To make a triangle we have to use 3 verticles. So, here there will be two triangles for every rectangle. First triangle would be made of 2 Aliases and Twin. Second would be made of 2 twins and Alias. Just like in  fourth photo. Now, i have to make three important rules.


 * 1) As "walls" i mean the triangles between Aliases and Twins
 * 2) Updating, Destroing, Fire-Spreading, and Wall-Building will be only made in Aliases (not Twins). It Will much simplify the process, as we will regard this thick mesh as standart, thin mesh.
 * 3) Responsible for making the Walls is the Alias being deleted.

As you may have noticed at the fourth image, we have to make 2 triangles for 2 Aliases and 2 twins. Aliases number 1 and 2 Formerly participated in triangle made of them and the Destroyed Alias. So, the number of triangles we will have to produce 2 * number of destroyed triangles.

Destroy method Verticle.cs
private void Destroy{ //DebEnlightenThisAlias; //DebEnlightenTriangles; //Debug.Log("liAl "+LinkedAliases[0]+" Da angle "+number); for(int i = 0; i<LinkedAliases.Count; i++){ OwnerManager.Aliases[ LinkedAliases[i]  ].RemoveLink(number); foreach(int l in Triangles){ OwnerManager.Aliases[ LinkedAliases[i]  ].RemoveLink(number); } 				RemoveLink( LinkedAliases[i]  ); } 			if((OwnerManager.IsMeshThick==true)&&IsATwin==false){ OwnerManager.Aliases[number+(OwnerManager.Aliases.Count/2)].Destroy; ProduceTrianglesBetweenWalls; } 			DestroyTriangles; OwnerManager.UpdateTrianglesList; } The intresting part is of course 			if((OwnerManager.IsMeshThick==true)&&IsATwin==false) 				OwnerManager.Aliases[number+(OwnerManager.Aliases.Count/2)].Destroy;	 				        ProduceTrianglesBetweenWalls; 			}
 * This is checking if 1) The mesh is thick 2)This is not a twin.
 * Here we tell the twin to destroy itself OwnerManager.Aliases.Count/2 is of course offset.
 * Finally, the method that produces walls.

ProduceTrianglesBetweenWalls method (Verticle.cs)
private void ProduceTrianglesBetweenWalls{//fills the void between Alias and its twin int[] TempListOfAliasNumbers= new int[2]; //Stores the numbers of other (not this) aliases that form a triangle foreach(int k in Triangles){ if(k < OwnerManager.OrgTriangleCount){//This triangle is not a wall triangle Vector3 VertNumbers = OwnerManager.Triangles[k]; if(VertNumbers != Vector3.zero){ int i = 0; for(int j=0; j<3; j++){ float f = VertNumbers[j]; if(OwnerManager.VerticleToAliasArray[ (int) f]!= number){ int z = OwnerManager.VerticleToAliasArray[ (int) f]; TempListOfAliasNumbers[i] = z; 								i++; } 						} 						if( (OwnerManager.Aliases[TempListOfAliasNumbers[0]].state != VerticleState.Destroyed) && (OwnerManager.Aliases[TempListOfAliasNumbers[1]].state != VerticleState.Destroyed) ){ OwnerManager.AddTriangleAndVerticles(TempListOfAliasNumbers[0]                              ,TempListOfAliasNumbers[1],  TempListOfAliasNumbers[0] + OwnerManager.Aliases.Count/2)  ; OwnerManager.AddTriangleAndVerticles(TempListOfAliasNumbers[0] + OwnerManager.Aliases.Count/2,TempListOfAliasNumbers[1], TempListOfAliasNumbers[0] )  ; OwnerManager.AddTriangleAndVerticles(TempListOfAliasNumbers[0] + OwnerManager.Aliases.Count/2,TempListOfAliasNumbers[1], TempListOfAliasNumbers[1] + OwnerManager.Aliases.Count/2)  ; OwnerManager.AddTriangleAndVerticles(TempListOfAliasNumbers[1] + OwnerManager.Aliases.Count/2,TempListOfAliasNumbers[1], TempListOfAliasNumbers[0] + OwnerManager.Aliases.Count/2)  ; } 					} 				} 			} 			OwnerManager.TranslateFromMeshToManager; } Okay, this is preety big. We have to do three things here Vector3 VertNumbers = OwnerManager.Triangles[k]; if(VertNumbers != Vector3.zero){ int i = 0; for(int j=0; j<3; j++){ float f = VertNumbers[j]; if(OwnerManager.VerticleToAliasArray[ (int) f]!= number){ int z = OwnerManager.VerticleToAliasArray[ (int) f]; TempListOfAliasNumbers[i] = z; 								i++; } 						} This part if filling the TempListOfAlias with aliases numbers taking part in traingle, but not being Alias being deleted. if( (OwnerManager.Aliases[TempListOfAliasNumbers[0]].state != VerticleState.Destroyed) && (OwnerManager.Aliases[TempListOfAliasNumbers[1]].state != VerticleState.Destroyed) ){ OwnerManager.AddTriangleAndVerticles(TempListOfAliasNumbers[0]                              ,TempListOfAliasNumbers[1],  TempListOfAliasNumbers[0] + OwnerManager.Aliases.Count/2)  ; OwnerManager.AddTriangleAndVerticles(TempListOfAliasNumbers[0] + OwnerManager.Aliases.Count/2,TempListOfAliasNumbers[1], TempListOfAliasNumbers[0] )  ; OwnerManager.AddTriangleAndVerticles(TempListOfAliasNumbers[0] + OwnerManager.Aliases.Count/2,TempListOfAliasNumbers[1], TempListOfAliasNumbers[1] + OwnerManager.Aliases.Count/2)  ; OwnerManager.AddTriangleAndVerticles(TempListOfAliasNumbers[1] + OwnerManager.Aliases.Count/2,TempListOfAliasNumbers[1], TempListOfAliasNumbers[0] + OwnerManager.Aliases.Count/2)  ; } Here we have really important code. It is making the triangles of wall. But before, lets look at condition. if( (OwnerManager.Aliases[TempListOfAliasNumbers[0]].state != VerticleState.Destroyed) && (OwnerManager.Aliases[TempListOfAliasNumbers[1]].state != VerticleState.Destroyed) ) I am checking here if both Aliases are not destroyed (as there should be no traingles made with them). In fact traingles and links with destroyed Alias should be deleted before, but if something goes wrong, and there still is a link between them, this condition will catch it.  OwnerManager.AddTriangleAndVerticles(..... This is the method that makes traingle, lets look at it
 * 1) Find the numbers of two Aliases that will form traingle (third is Alias being destroyed)
 * 2) Call function that will produce this triangle between them
 * 3) Call function that will again translate from mesh To aliases list etc (This is the last method). I will talk bout it later
 * This is an array which will have the numbers of Aliases taking part in making walls. The problem is that in Verticle class we have a list of triangles numbers. Using this numbers we may check in MeshManager which Aliases are taking part in making this triangle. Than, we have to check which Aliases is this one being destroyed (as he cannot make walls)
 * Than there is a foreach loop, as for every destroyed traingle a wall may be made. But not should be made
 * Here we check if current triangle is not a part of "wall"  is an int with the number of original triangles (before mesh-thickening. It's initialised in MeshManager class. We will not make walls from triangles arleady being part of "wall"

AddTriangleAndVerticles method (MeshManager class)
Before, I have to say how this triangles are made. Well I dont update Aliases, VTAA and other custom things. It is much easier to work and add on mesh.verticles and mesh.triangles class alone. After modifications, Aliases etc should be just updated. public int AddTriangleAndVerticles(int a, int b, int c){//gets 3 numbers of Aliases. Produces a triangle between them, and new verticles Vector3[] OldVerticleList = mesh.vertices; Vector3[] NewVerticleList = new Vector3 [OldVerticleList.Length+3]; Vector3[] LastThreeVerts = new Vector3[3]{Aliases[a].positionRelative,Aliases[b].positionRelative,Aliases[c].positionRelative }; OldVerticleList.CopyTo(NewVerticleList,0); LastThreeVerts.CopyTo(NewVerticleList, OldVerticleList.Length); mesh.vertices = NewVerticleList; int[] OldTriangleList = mesh.triangles; int[] NewTriangleList = new int [OldTriangleList.Length+3]; int[] NewTriangle = new int[3]{mesh.vertices.Length-1, mesh.vertices.Length-2, mesh.vertices.Length-3}; OldTriangleList.CopyTo(NewTriangleList, 0); NewTriangle.CopyTo(NewTriangleList, OldTriangleList.Length); mesh.triangles = NewTriangleList; return mesh.triangles.Length/3; //the number of added triangle } This function takes numbers of three Aliases between whom traingle should be made. 		Vector3[] LastThreeVerts = new Vector3[3]{Aliases[a].positionRelative,Aliases[b].positionRelative,Aliases[c].positionRelative }; Here we get the position of this Aliases and then make 3 new verticles. Theoretically, I could use arleady made verticles, but this is not so good idea becouse of some shading issues.

 Than I have to add traingle to mesh.traingles array. This triangle is made here: 		int[] NewTriangle = new int[3]{mesh.vertices.Length-1, mesh.vertices.Length-2, mesh.vertices.Length-3}; I use  mesh.vertices.Length-1, ...-2 and ...-3 as this will be 3 most recently added verticles, so that ones which i just made.

Last intresting thing is the returned value - number of made triangle. For now, it is not used.

Back to  Destroy method
You may ask why i call the  AddTriangleAndVerticles method 4 times, when we need 2 triangles. Well, for now i an not able to count which side this "wall" should be facing, so it has to be visible on both sides. To do so, 2nd function callis made with inverted arguments in comparing with 1st one. The same with 3 and 4.

Last thing is OwnerManager.TranslateFromMeshToManager; <span style="font-family:Helvetica,Arial,sans-serif;">This translares from MeshFiler.mesh to  MeshManager, like in constructor of MeshManager

<span style="font-family:Helvetica,Arial,sans-serif;">TranslateFromMeshToManager method (MeshManager class)
public void TranslateFromMeshToManager{ Triangles = new List<Vector3>; ManageVerticlesAddNewUpdateOld(mesh.vertices); ManageTriangles(mesh.triangles); CalcualateMinimumHeight; if(IsMeshThick==true){ for(int i=Aliases.Count/2; i<Aliases.Count; i++){ Aliases[i].IsATwin = true; } 		} 	} Intresting here is only one thing: The new  method.

ManageVerticleAddNewUpdateOld method (MeshManager class)
private void ManageVerticlesAddNewUpdateOld(Vector3[] verticles){ Dictionary<Vector3, List > TempAliases = new Dictionary<Vector3, List >; //list of ints are numbers of verticles in the specific position (the Vector3) int i = 0; foreach (Vector3 verticle in verticles){ if(TempAliases.ContainsKey(verticle)){//we've arleady added a verticle of this position, so the alias will have multiple verticles TempAliases[verticle].Add(i); }else{//we have to add a number of our verticle to our list TempAliases[verticle] = new List ; TempAliases[verticle].Add(i); } 			i++; } 		VerticleToAliasArray = new int[i]; i = 0; int OrgAliasesCount = Aliases.Count; foreach(var pair in TempAliases){//a Key-Value Pair if(i>OrgAliasesCount-1){//we add a new verticle Aliases.Add (new Verticle(this, i, pair.Value, pair.Key)); }else{ Aliases[i].Modify(i, pair.Value, pair.Key); } 			ManageVerticleToAliasArray(i,pair.Value); i++; } 	} It is nearly identical to ManageVerticles, except for one thing. <span style="font-family:Helvetica,Arial,sans-serif;">			if(i>OrgAliasesCount-1){//we add a new verticle <span style="font-family:Helvetica,Arial,sans-serif;">				Aliases.Add (new Verticle(this, i, pair.Value, pair.Key)); <span style="font-family:Helvetica,Arial,sans-serif;">			       }else{ <span style="font-family:Helvetica,Arial,sans-serif;">				       Aliases[i].Modify(i, pair.Value, pair.Key); <span style="font-family:Helvetica,Arial,sans-serif;">		         	} <span style="font-family:Helvetica,Arial,sans-serif;">This part. The aim of it, is to Not completly re-do all Aliases. The Original (not twin) ones are just Modified, not added again. Why? Becouse if we would Add them again, we would lose the health value and some other data. Twins have not updated health or state, so we can just add them.

<span style="font-family:Helvetica,Arial,sans-serif;">Modify method
public void Modify(int Xnumber, List XAliases, Vector3 XpositionRelative){ //this updates some elements, but saves ones like health Triangles = new List ;		//////Initialisation LinkedAliases = new List ;	// number = Xnumber; Aliases = XAliases; positionRelative = XpositionRelative; normal = OwnerManager.mesh.normals[Aliases[0]]; SetPositionAbsolute; } It is very similar to the constructor, just not initialises and sets everything again.



Okay, that should be it, just now click on building. (you may change the function started while clicking to sth that starts fire, like FFire method). And it works! But does it very, very slow. May even freeze Unity completly.

Ending
Files can be found at Github, Version 4.

At the bottom of Verticle Class you can find some Debug functions with Deb Prefix. You may use it so see better Aliases, Vertices, etc