public static RopeCastingSegment NewSeg(RopeCasting mother, Vector2 start, RopeCastingSegment end, Collider2D col, float bendsCross) { var gObj = new GameObject("RopeSegment"); gObj.transform.parent = mother.transform; gObj.layer = 12; var nxt = gObj.AddComponent<RopeCastingSegment>(); nxt.mother = mother; nxt.end = end; nxt.col = col; nxt.startOffset = nxt.col.transform.InverseTransformPoint(start); nxt.bendsCross = bendsCross; nxt.eCol = gObj.AddComponent<EdgeCollider2D>(); nxt.eCol.isTrigger = true; nxt.IgnoreCollisions (); nxt.isEnd = false; // TODO Hacked to always add rigidbody so that it will detect when moving platforms hits it. // TODO RopeCast instead when you break instead? !?!?!? its not actualy because of moving platforms!!! if (col == null || end.isEnd || true) { // in this case this is the first or second to last segment // TODO add a seperate signifier for col == null var rig = gObj.AddComponent<Rigidbody2D> (); rig.gravityScale = 0; // TODO fix this hack to make it collide ? (it will not detect collision if there is no non kinematic rigidbodies involved). rig.collisionDetectionMode = CollisionDetectionMode2D.Continuous; } // Add Linerenderer var lr = gObj.AddComponent<LineRenderer> (); lr.SetVertexCount (2); lr.SetWidth (mother.ropeWidth, mother.ropeWidth); lr.material = mother.ropeMaterial; nxt.lr = lr; nxt.UpdateECol(); return nxt; }
// Destroy the bend at the end of this segment eg. the bend with a corner in end.start private void DestroyBend() { // I assume i dont have to touch: mother col eCol start isEnd bendsCross = end.bendsCross; var oldEnd = end; end = end.end; Destroy(oldEnd.gameObject); // If we just deleted the segment with a rigidbody we need to add it to ourself if (end.isEnd && rigidbody2D == null) { var rig = gameObject.AddComponent<Rigidbody2D> (); rig.gravityScale = 0; // TODO This hack again... } UpdateECol(); // TODO Check if any of the other ends are good? }
// Finds a corner based on the hits and splits the segment by that corner. // Should always be followed by RopeCast() and end.RopeCast() to check if ropes are ok. // hit1 and hit2 should always be on the same collider! // hit1 and hit2 should always be in order based on their order on the rope private bool SplitSegment(RaycastHit2D hit1, RaycastHit2D hit2) { if (hit1.collider != hit2.collider) { Debug.LogError("SplitSegment should only be called with the same collider"); } var ang = Vector2.Angle(hit1.normal, hit2.normal); // Find which normal is the first in a clockwise rotation so that the angle is the smallest // and use this to calculate a vector that is exactly between the two normals. var cross = Vector3.Cross(hit1.normal, hit2.normal); Vector3 dir = Quaternion.AngleAxis(ang/2, new Vector3(0,0,-1)) * ((cross.z < 0) ? hit1.normal : hit2.normal); // Calculate the corner of the collider by intersect the rays from the points with vectors perpendicular to the normals. Vector3 p1 = hit1.point; Vector3 p2 = hit2.point; Vector3 v1 = Quaternion.AngleAxis(90,new Vector3(0,0,-1)) * hit1.normal; Vector3 v2 = Quaternion.AngleAxis(90,new Vector3(0,0,-1)) * hit2.normal; Vector3 corner = Math2D.LineIntersectionPoint(p1, p1+v1, p2, p2+v2); // Calculate a point outside the collider with a given offset var ropePoint = corner + (dir.normalized * mother.ropeOffset); // Check if ropePoint is inside a collider and move it out in that case var lc = Physics2D.Linecast (ropePoint, ropePoint, 1 << 9); // We do not check for players as that might break it. // TODO WHY THE F**K DOES THIS MAKE A STACKOVERFLOW??? int i = 1; while (lc.collider != null) { // TODO dont do shit and let the player die? if (i > 4) return false; Debug.LogError("RopePoint was set inside a collider: Moving it out nr of time: " + i); ropePoint = corner + (dir.normalized * mother.ropeOffset * i++ * 2); lc = Physics2D.Linecast (ropePoint, ropePoint, 1 << 9); // We do not check for players as that might break it. } end = NewSeg(mother, ropePoint, end, hit1.collider, bendsCross); // TODO We could do end.CheckCross() Here if its needed. // The new segment is now in control of the line this last hat so it inherits bendcross while this takes the new cross // This assumes that hit1 is before hit2 on the rope bendsCross = cross.z; UpdateECol(); return true; }
private void InitializeSegments() { if (isInitialized) { Debug.LogError("Rope was already initialized"); return; } if (gameObject.GetComponentsInChildren<RopeCastingSegment> ().Length != 0) { Debug.LogError("InitializeSegments was called while it still has segments."); DestroySegments(); } // TODO Fix hack to find the real player object (Which doen't roll) var p1c = p1.GetComponent<PlayerController> (); var p2c = p2.GetComponent<PlayerController> (); var p1col = p1c != null ? p1c.roller.collider2D : p1.collider2D; var p2col = p2c != null ? p2c.roller.collider2D : p2.collider2D; var lastEnd = RopeCastingSegment.NewEndSeg (this, p2.transform.position, p2col); //TODO change the child order? We could do this to order the update order if needed. ropePath = RopeCastingSegment.NewSeg (this, p1.transform.position, lastEnd, p1col, 0); crossColliders = null; GetCrossColliders (); isInitialized = true; }