public int Hash(Vector3 p) { for (int i = 0; i < count; i++) { var item = buckets[i]; float diffX = p.x - item.x; float diffY = p.y - item.y; float diffZ = p.z - item.z; float sqrMag = diffX * diffX + diffY * diffY + diffZ * diffZ; if (sqrMag < bucketSize2) { return(i); } } if (count >= buckets.Length) { Exploder2DUtils.Log("Hash out of range: " + count + " " + buckets.Length); return(count - 1); } buckets[count++] = p; return(count - 1); }
private void ExplodeObject(GameObject gameObject) { var exploder = Exploder2D.Utils.Exploder2DSingleton.Exploder2DInstance; exploder.transform.position = Exploder2DUtils.GetCentroid(gameObject); exploder.Radius = 1.0f; exploder.Explode(); }
public void Remove(int key) { Exploder2DUtils.Assert(key < Size, "Key index out of range! " + key + " maxSize: " + Size); Exploder2DUtils.Assert(dictionary[key].valid == true, "Key does not exist!"); dictionary[key].valid = false; Count--; }
private void explode() { // Blow up comet Exploder2DUtils.SetActive(exploder.gameObject, true); exploder.transform.position = Exploder2DUtils.GetCentroid(gameObject); GameObject.FindGameObjectWithTag(Constants.EXPLOSION_PLAYER).GetComponent <AudioSource>().Play(); exploder.Explode(); Invoke("destroy", DESTROY_DELAY); }
private void explode() { Exploder2DUtils.SetActive(exploder.gameObject, true); exploder.Radius = 0.1f; exploder.Force = 1.0f; exploder.TargetFragments = 50; exploder.transform.position = Exploder2DUtils.GetCentroid(gameObject); exploder.Explode(); }
public void Add(int key, T data) { Exploder2DUtils.Assert(key < Size, "Key index out of range! " + key + " maxSize: " + Size); Exploder2DUtils.Assert(dictionary[key].valid == false, "Key already exists!"); dictionary[key].valid = true; dictionary[key].data = data; Count++; }
public T this[int key] { get { Exploder2DUtils.Assert(key < Size, "Key index out of range! " + key + " maxSize: " + Size); Exploder2DUtils.Assert(dictionary[key].valid == true, "Key does not exist!"); return(dictionary[key].data); } set { Exploder2DUtils.Assert(dictionary[key].valid == true, "Key does not exist!"); dictionary[key].data = value; } }
public T GetFirstValue() { for (int i = 0; i < Size; i++) { var item = dictionary[i]; if (item.valid) { return(item.data); } } Exploder2DUtils.Assert(false, "No valid key!"); return(default(T)); }
public bool TryGetValue(int key, out T value) { Exploder2DUtils.Assert(key < Size, "Key index out of range! " + key + " maxSize: " + Size); var item = dictionary[key]; if (item.valid) { value = item.data; return(true); } value = default(T); return(false); }
void ExplodeList() { if (index >= sprites.Count) { return; } var exploder = Exploder2DSingleton.Exploder2DInstance; // move exploder object to the same position exploder.transform.position = Exploder2DUtils.GetCentroid(sprites[index]); // decrease the radius so the exploder is not interfering other objects exploder.Radius = 1.0f; exploder.Explode(OnExplosion); }
private void OnTriggerEnter2D(Collider2D other) { if (!other.CompareTag("Player")) { return; } FindObjectOfType <CameraController>().StopFollowingPlayer(); other.gameObject.tag = Constants.EXPLODER_2D; Exploder2DUtils.SetActive(exploder.gameObject, true); exploder.transform.position = Exploder2DUtils.GetCentroid(other.gameObject); exploder.Radius = 1.0f; exploder.Force = 5.0f; exploder.TargetFragments = 50; exploder.Explode(); GetComponent <AudioSource>().Play(); Invoke("fadeOut", FADE_DELAY); }
void ExplodeObject(GameObject obj) { // activate exploder Exploder2DUtils.SetActive(exploder.gameObject, true); // move exploder object to the same position exploder.transform.position = Exploder2DUtils.GetCentroid(obj); // decrease the radius so the exploder is not interfering other objects exploder.Radius = 0.1f; // DONE! #if ENABLE_CRACK_AND_EXPLODE exploder.Crack(OnCracked); #else exploder.Explode(OnExplosion); #endif }
private void startBlackHole() { if (sunExploded) { return; } FindObjectOfType <LevelManager>().PlayEvilBGM(); sun.tag = Constants.EXPLODER_2D; Exploder2DUtils.SetActive(sun, true); exploder.transform.position = Exploder2DUtils.GetCentroid(sun); exploder.Radius = 100.0f; exploder.Force = 32.0f; exploder.TargetFragments = 420; sunExploded = true; exploder.Explode(); blackHoleIsActive = true; blackHole.SetActive(true); }
public T[] ToArray() { var array = new T[Count]; var idx = 0; for (int i = 0; i < Size; i++) { if (dictionary[i].valid) { array[idx++] = dictionary[i].data; if (idx == Count) { return(array); } } } Exploder2DUtils.Assert(false, "ToArray failed, Count is wrong!"); return(null); }
/// <summary> /// Compute intersection between a segment line (a, b) and a plane (p) /// from Real-Time Collision Detection Book by Christer Ericson /// </summary> /// <param name="a">first point of a segment</param> /// <param name="b">second point of a segment</param> /// <param name="t">normalized distance of intersection point on vector (ab)</param> /// <param name="q">point in intersection</param> /// <returns>true if there is an intersection</returns> public bool IntersectSegment(Vector2 a, Vector2 b, out float t, ref Vector2 q) { var abx = b.x - a.x; var aby = b.y - a.y; var dot0 = Normal.x * a.x + Normal.y * a.y; var dot1 = Normal.x * abx + Normal.y * aby; t = (Distance - dot0) / dot1; if (t >= 0.0f - epsylon && t <= 1.0f + epsylon) { q.x = a.x + t * abx; q.y = a.y + t * aby; return(true); } Exploder2DUtils.Log("IntersectSegment failed: " + t); q = Vector2.zero; return(false); }
/// <summary> /// cut mesh by plane /// </summary> /// <param name="spriteMesh">mesh to cut</param> /// <param name="meshTransform">transformation of the mesh</param> /// <param name="line2D">cutting plane</param> /// <returns>processing time</returns> public float Cut(SpriteMesh spriteMesh, Transform meshTransform, Math.Line2D line2D, ref List <CutterMesh> meshes) { var stopWatch = new Stopwatch(); stopWatch.Start(); #if PROFILING MeasureIt.Begin("CutAllocations"); #endif // cache mesh data var trianglesNum = spriteMesh.triangles.Length; var verticesNum = spriteMesh.vertices.Length; var meshTriangles = spriteMesh.triangles; var meshVertices = spriteMesh.vertices; // preallocate buffers AllocateBuffers(trianglesNum, verticesNum); CutterMesh mesh0, mesh1; #if PROFILING MeasureIt.End("CutAllocations"); MeasureIt.Begin("CutCycleFirstPass"); #endif // inverse transform cutting plane // line2D.InverseTransform(meshTransform); // first pass - find complete triangles on both sides of the plane for (int i = 0; i < trianglesNum; i += 3) { // get triangle points var v0 = meshVertices[meshTriangles[i]]; var v1 = meshVertices[meshTriangles[i + 1]]; var v2 = meshVertices[meshTriangles[i + 2]]; var side0 = line2D.GetSideFix(ref v0); var side1 = line2D.GetSideFix(ref v1); var side2 = line2D.GetSideFix(ref v2); meshVertices[meshTriangles[i]] = v0; meshVertices[meshTriangles[i + 1]] = v1; meshVertices[meshTriangles[i + 2]] = v2; // Utils.Log(plane.Pnt + " " + v0 + " " + v1 + " " + " " + v2); // all points on one side if (side0 == side1 && side1 == side2) { var idx = side0 ? 0 : 1; if (meshTriangles[i] >= triCache.Length) { Exploder2DUtils.Log("TriCacheError " + meshTriangles[i] + " " + triCache.Length + " " + meshVertices.Length); } if (triCache[meshTriangles[i]] == 0) { triangles[idx].Add(triCounter[idx]); vertices[idx].Add(meshVertices[meshTriangles[i]]); centroid[idx] += meshVertices[meshTriangles[i]]; triCache[meshTriangles[i]] = triCounter[idx] + 1; triCounter[idx]++; } else { triangles[idx].Add(triCache[meshTriangles[i]] - 1); } if (triCache[meshTriangles[i + 1]] == 0) { triangles[idx].Add(triCounter[idx]); vertices[idx].Add(meshVertices[meshTriangles[i + 1]]); centroid[idx] += meshVertices[meshTriangles[i + 1]]; triCache[meshTriangles[i + 1]] = triCounter[idx] + 1; triCounter[idx]++; } else { triangles[idx].Add(triCache[meshTriangles[i + 1]] - 1); } if (triCache[meshTriangles[i + 2]] == 0) { triangles[idx].Add(triCounter[idx]); vertices[idx].Add(meshVertices[meshTriangles[i + 2]]); centroid[idx] += meshVertices[meshTriangles[i + 2]]; triCache[meshTriangles[i + 2]] = triCounter[idx] + 1; triCounter[idx]++; } else { triangles[idx].Add(triCache[meshTriangles[i + 2]] - 1); } } else { // intersection triangles add to list and process it in second pass cutTris.Add(i); } } if (vertices[0].Count == 0) { centroid[0] = meshVertices[0]; } else { centroid[0] /= vertices[0].Count; } if (vertices[1].Count == 0) { centroid[1] = meshVertices[1]; } else { centroid[1] /= vertices[1].Count; } #if PROFILING MeasureIt.End("CutCycleFirstPass"); MeasureIt.Begin("CutCycleSecondPass"); #endif mesh0.centroidLocal = centroid[0]; mesh1.centroidLocal = centroid[1]; mesh0.mesh = null; mesh1.mesh = null; if (cutTris.Count < 1) { stopWatch.Stop(); return(stopWatch.ElapsedMilliseconds); } AllocateContours(cutTris.Count); // second pass - cut intersecting triangles in half foreach (var cutTri in cutTris) { var triangle = new Triangle { ids = new[] { meshTriangles[cutTri + 0], meshTriangles[cutTri + 1], meshTriangles[cutTri + 2] }, pos = new[] { meshVertices[meshTriangles[cutTri + 0]], meshVertices[meshTriangles[cutTri + 1]], meshVertices[meshTriangles[cutTri + 2]] }, }; // check points with a plane var side0 = line2D.GetSide(triangle.pos[0]); var side1 = line2D.GetSide(triangle.pos[1]); var side2 = line2D.GetSide(triangle.pos[2]); float t0, t1; Vector2 s0 = Vector2.zero, s1 = Vector2.zero; var idxLeft = side0 ? 0 : 1; var idxRight = 1 - idxLeft; if (side0 == side1) { var a = line2D.IntersectSegment(triangle.pos[2], triangle.pos[0], out t0, ref s0); var b = line2D.IntersectSegment(triangle.pos[2], triangle.pos[1], out t1, ref s1); Exploder2DUtils.Assert(a && b, "!!!!!!!!!!!!!!!"); // left side ... 2 triangles var s0Left = AddIntersectionPoint(s0, triangle.ids[2], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft]); var s1Left = AddIntersectionPoint(s1, triangle.ids[2], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft]); var v0Left = AddTrianglePoint(triangle.pos[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft]); var v1Left = AddTrianglePoint(triangle.pos[1], triangle.ids[1], triCache, cornerVertCache[idxLeft], vertices[idxLeft]); // Triangle (s0, v0, s1) triangles[idxLeft].Add(s0Left); triangles[idxLeft].Add(v0Left); triangles[idxLeft].Add(s1Left); // Triangle (s1, v0, v1) triangles[idxLeft].Add(s1Left); triangles[idxLeft].Add(v0Left); triangles[idxLeft].Add(v1Left); // right side ... 1 triangle var s0Right = AddIntersectionPoint(s0, triangle.ids[2], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight]); var s1Right = AddIntersectionPoint(s1, triangle.ids[2], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight]); var v2Right = AddTrianglePoint(triangle.pos[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight]); // Triangle (v2, s0, s1) triangles[idxRight].Add(v2Right); triangles[idxRight].Add(s0Right); triangles[idxRight].Add(s1Right); } else if (side0 == side2) { var a = line2D.IntersectSegment(triangle.pos[1], triangle.pos[0], out t0, ref s1); var b = line2D.IntersectSegment(triangle.pos[1], triangle.pos[2], out t1, ref s0); Exploder2DUtils.Assert(a && b, "!!!!!!!!!!!!!"); // left side ... 2 triangles var s0Left = AddIntersectionPoint(s0, triangle.ids[1], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft]); var s1Left = AddIntersectionPoint(s1, triangle.ids[1], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft]); var v0Left = AddTrianglePoint(triangle.pos[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft]); var v2Left = AddTrianglePoint(triangle.pos[2], triangle.ids[2], triCache, cornerVertCache[idxLeft], vertices[idxLeft]); // Triangle (v2, s1, s0) triangles[idxLeft].Add(v2Left); triangles[idxLeft].Add(s1Left); triangles[idxLeft].Add(s0Left); // Triangle (v2, v0, s1) triangles[idxLeft].Add(v2Left); triangles[idxLeft].Add(v0Left); triangles[idxLeft].Add(s1Left); // right side ... 1 triangle var s0Right = AddIntersectionPoint(s0, triangle.ids[1], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight]); var s1Right = AddIntersectionPoint(s1, triangle.ids[1], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight]); var v1Right = AddTrianglePoint(triangle.pos[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight]); // Triangle (s0, s1, v1) triangles[idxRight].Add(s0Right); triangles[idxRight].Add(s1Right); triangles[idxRight].Add(v1Right); } else { var a = line2D.IntersectSegment(triangle.pos[0], triangle.pos[1], out t0, ref s0); var b = line2D.IntersectSegment(triangle.pos[0], triangle.pos[2], out t1, ref s1); Exploder2DUtils.Assert(a && b, "!!!!!!!!!!!!!"); // right side ... 2 triangles var s0Right = AddIntersectionPoint(s0, triangle.ids[0], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight]); var s1Right = AddIntersectionPoint(s1, triangle.ids[0], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight]); var v1Right = AddTrianglePoint(triangle.pos[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight]); var v2Right = AddTrianglePoint(triangle.pos[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight]); // Triangle (v2, s1, v1) triangles[idxRight].Add(v2Right); triangles[idxRight].Add(s1Right); triangles[idxRight].Add(v1Right); // Triangle (s1, s0, v1) triangles[idxRight].Add(s1Right); triangles[idxRight].Add(s0Right); triangles[idxRight].Add(v1Right); // left side ... 1 triangle var s0Left = AddIntersectionPoint(s0, triangle.ids[0], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft]); var s1Left = AddIntersectionPoint(s1, triangle.ids[0], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft]); var v0Left = AddTrianglePoint(triangle.pos[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft]); // Triangle (s1, v0, s0) triangles[idxLeft].Add(s1Left); triangles[idxLeft].Add(v0Left); triangles[idxLeft].Add(s0Left); } } #if PROFILING MeasureIt.End("CutCycleSecondPass"); #endif List <int>[] trianglesCut = null; if (vertices[0].Count > 3 && vertices[1].Count > 3) { #if PROFILING MeasureIt.Begin("CutEndCopyBack"); #endif mesh0.mesh = new SpriteMesh(); mesh1.mesh = new SpriteMesh(); var verticesArray0 = vertices[0].ToArray(); var verticesArray1 = vertices[1].ToArray(); mesh0.mesh.vertices = verticesArray0; mesh1.mesh.vertices = verticesArray1; if (trianglesCut != null && trianglesCut[0].Count > 3) { triangles[0].AddRange(trianglesCut[0]); triangles[1].AddRange(trianglesCut[1]); } mesh0.mesh.triangles = triangles[0].ToArray(); mesh1.mesh.triangles = triangles[1].ToArray(); mesh0.centroidLocal = Vector2.zero; mesh1.centroidLocal = Vector2.zero; foreach (var p in vertices[0]) { mesh0.centroidLocal += p; } mesh0.centroidLocal /= vertices[0].Count; foreach (var p in vertices[1]) { mesh1.centroidLocal += p; } mesh1.centroidLocal /= vertices[1].Count; #if PROFILING MeasureIt.End("CutEndCopyBack"); #endif meshes = new List <CutterMesh> { mesh0, mesh1 }; stopWatch.Stop(); return(stopWatch.ElapsedMilliseconds); } stopWatch.Stop(); // UnityEngine.Debug.Log("Empty cut! " + vertices[0].Count + " " + vertices[1].Count); return(stopWatch.ElapsedMilliseconds); }
public void Intersect(Vector2[] path) { int v1 = 0, h1 = 0; for (var i = 0; i < path.Length - 1; i++) { var p0 = path[i] - min; var p1 = path[i + 1] - min; int seg = (int)((p0 - p1).sqrMagnitude / (resolution * 0.3 * resolution * 0.3f)) + 1; for (int j = 0; j <= seg; j++) { var t = (float)j / seg; var p = p0 * (1.0f - t) + p1 * t; var h0 = (short)((p.x + resolution * 1.5f) / resolution); var v0 = (short)((p.y + resolution * 1.5f) / resolution); Exploder2DUtils.Assert(v0 < vCount); Exploder2DUtils.Assert(h0 < hCount); grid[v0][h0].type = CellType.Edge; if (j == 0 || j == seg) { grid[v0][h0].LineIntersection(p0 + min, p1 + min, v0, h0, intersections); grid[v0][h0].PointIntersection(p + min, v0, h0, intersections); grid[v0][h0].AddPnt(p + min); } else if (v0 != v1 || h0 != h1) { grid[v0][h0].LineIntersection(p0 + min, p1 + min, v0, h0, intersections); } v1 = v0; h1 = h0; } } for (var i = 0; i < vCount; i++) { int leftEdge = -1; int rightEdge = -1; for (var j = 0; j < hCount; j++) { if (leftEdge == -1 && grid[i][j].type == CellType.Edge) { leftEdge = j; } if (rightEdge == -1 && grid[i][hCount - 1 - j].type == CellType.Edge) { rightEdge = hCount - 1 - j; } if (leftEdge != -1 && rightEdge != -1) { break; } } if (leftEdge != -1 && rightEdge != -1) { for (int j = leftEdge + 1; j < rightEdge; j++) { if (grid[i][j].type != CellType.Edge) { grid[i][j].type = CellType.In; } } } } foreach (var inter in intersections) { var cell0 = (int)inter.Key; var cell1 = (int)(inter.Key >> 32); var hp0 = (short)cell0; var vp0 = (short)(cell0 >> 16); var hp1 = (short)cell1; var vp1 = (short)(cell1 >> 16); grid[vp0][hp0].AddPnt(inter.Value); grid[vp1][hp1].AddPnt(inter.Value); } }
/// <summary> /// find and isolate independent (not connecting) parts in a mesh /// </summary> public static List <CutterMesh> IsolateMeshIslands(SpriteMesh mesh) { var triangles = mesh.triangles; var vertexCount = mesh.vertices.Length; // cache mesh data var trianglesNum = mesh.triangles.Length; var vertices = mesh.vertices; if (trianglesNum <= 3) { return(null); } Exploder2DUtils.Assert(trianglesNum > 3, "IsolateMeshIslands error: " + trianglesNum); var lsHash = new LSHash(0.1f, vertexCount); var vertHash = new int[trianglesNum]; for (int i = 0; i < trianglesNum; i++) { vertHash[i] = lsHash.Hash(vertices[triangles[i]]); } var islands = new List <HashSet <int> > { new HashSet <int> { vertHash[0], vertHash[1], vertHash[2] } }; var islandsIdx = new List <List <int> > { new List <int>(trianglesNum) { 0, 1, 2 } }; var triVisited = new bool[trianglesNum]; triVisited[0] = true; triVisited[1] = true; triVisited[2] = true; var currIsland = islands[0]; var currIslandIdx = islandsIdx[0]; var counter = 3; var lastInvalidIdx = -1; var loopCounter = 0; while (true) { var foundIsland = false; for (int j = 3; j < trianglesNum; j += 3) { if (triVisited[j]) { continue; } if (currIsland.Contains(vertHash[j]) || currIsland.Contains(vertHash[j + 1]) || currIsland.Contains(vertHash[j + 2])) { currIsland.Add(vertHash[j]); currIsland.Add(vertHash[j + 1]); currIsland.Add(vertHash[j + 2]); currIslandIdx.Add(j); currIslandIdx.Add(j + 1); currIslandIdx.Add(j + 2); triVisited[j] = true; triVisited[j + 1] = true; triVisited[j + 2] = true; counter += 3; foundIsland = true; } else { lastInvalidIdx = j; } } if (counter == trianglesNum) { break; } if (!foundIsland) { // create new island currIsland = new HashSet <int> { vertHash[lastInvalidIdx], vertHash[lastInvalidIdx + 1], vertHash[lastInvalidIdx + 2] }; currIslandIdx = new List <int>(trianglesNum / 2) { lastInvalidIdx, lastInvalidIdx + 1, lastInvalidIdx + 2 }; islands.Add(currIsland); islandsIdx.Add(currIslandIdx); } loopCounter++; if (loopCounter > 100) { Exploder2DUtils.Log("10000 loop exceeded, islands: " + islands.Count); break; } } var islandNum = islands.Count; Exploder2DUtils.Assert(islandNum >= 1, "No island found!"); // no more than one islands if (islandNum == 1) { return(null); } var result = new List <CutterMesh>(islands.Count); foreach (var island in islandsIdx) { var cutterMesh = new CutterMesh { mesh = new SpriteMesh() }; var triCount = island.Count; var m = cutterMesh.mesh; var tt = new List <int>(triCount); var vs = new List <Vector2>(triCount); var triCache = new Dictionary <int, int>(trianglesNum); var centroid = Vector2.zero; var centroidCounter = 0; var triCounter = 0; foreach (var i in island) { var tri = triangles[i]; var id = 0; if (triCache.TryGetValue(tri, out id)) { tt.Add(id); continue; } tt.Add(triCounter); triCache.Add(tri, triCounter); triCounter++; centroid += vertices[tri]; centroidCounter++; vs.Add(vertices[tri]); } m.vertices = vs.ToArray(); m.triangles = tt.ToArray(); cutterMesh.centroidLocal = centroid / centroidCounter; result.Add(cutterMesh); } return(result); }