public PixelBox(PixelBox body) { this.top = body.top; this.left = body.left; this.right = body.right; this.bottom = body.bottom; }
public PixelBox MatchCollisionBody(PixelBox input, bool center = true) { float h = 0.0f; if (rampDirection == Direction.NE || rampDirection == Direction.SW) { h = slope * Vector2.Distance(input.bottom, input.right); } if (rampDirection == Direction.SE || rampDirection == Direction.NW) { h = slope * Vector2.Distance(input.bottom, input.left); } Vector2 inputTopWorldElevated = (rampDirection == Direction.NW || rampDirection == Direction.NE) ? input.top + new Vector2(0.0f, h) : input.top; Vector2 inputbottomWorldElevated = (rampDirection == Direction.SW || rampDirection == Direction.SE) ? input.bottom + new Vector2(0.0f, h) : input.bottom; Vector2 inputleftWorldElevated = (rampDirection == Direction.NW || rampDirection == Direction.SW) ? input.left + new Vector2(0.0f, h) : input.left; Vector2 inputrightWorldElevated = (rampDirection == Direction.NE || rampDirection == Direction.SE) ? input.right + new Vector2(0.0f, h) : input.right; if (center) { inputTopWorldElevated.y = inputTopWorldElevated.y - h / 2; inputbottomWorldElevated.y = inputbottomWorldElevated.y - h / 2; inputleftWorldElevated.y = inputleftWorldElevated.y - h / 2; inputrightWorldElevated.y = inputrightWorldElevated.y - h / 2; } PixelBox cbody = new PixelBox(inputTopWorldElevated, inputleftWorldElevated, inputrightWorldElevated, inputbottomWorldElevated); return(cbody); }
public bool OnFarSide(PixelBox body) { bool onTop = centerSegment.AboveSegment(body); if (Math.Abs(slope) < float.Epsilon) { return(false); } if ((rampDirection == Direction.NE || rampDirection == Direction.NW) && onTop) { return(true); } if ((rampDirection == Direction.SE || rampDirection == Direction.SW) && !onTop) { return(true); } return(false); }
public static PixelBoxComparison CompareTwoCollisionBodies(PixelBox a, PixelBox b, float margin = 0.0f, bool debug = false) { Vector2 atopWorld = a.top; Vector2 abottomWorld = a.bottom; Vector2 aleftWorld = a.left; Vector2 arightWorld = a.right; Vector2 btopWorld = b.top; Vector2 bbottomWorld = b.bottom; Vector2 bleftWorld = b.left; Vector2 brightWorld = b.right; PixelBoxComparison collisionBodyComparision = new PixelBoxComparison(); bool aTopLeft = PixelLine.DistanceOrthographic(a.lineNW, b.lineSE) >= -margin; bool aTopRight = PixelLine.DistanceOrthographic(a.lineNE, b.lineSW) >= -margin; bool aBottomRight = PixelLine.DistanceOrthographic(b.lineNW, a.lineSE) >= -margin; bool aBottomLeft = PixelLine.DistanceOrthographic(b.lineNE, a.lineSW) >= -margin; bool aTopRightWithin = PixelLine.DistanceOrthographic(b.lineNE, a.lineNE) <= margin; bool aTopLeftWithin = PixelLine.DistanceOrthographic(b.lineNW, a.lineNW) <= margin; bool aBottomLeftWithin = PixelLine.DistanceOrthographic(a.lineSW, b.lineSW) <= margin; bool aBottomRightWithin = PixelLine.DistanceOrthographic(a.lineSE, b.lineSE) <= margin; collisionBodyComparision.NEinside = aTopRightWithin; collisionBodyComparision.NWinside = aTopLeftWithin; collisionBodyComparision.SEinside = aBottomRightWithin; collisionBodyComparision.SWinside = aBottomLeftWithin; collisionBodyComparision.NEoutside = aBottomLeft; collisionBodyComparision.NWoutside = aBottomRight; collisionBodyComparision.SEoutside = aTopLeft; collisionBodyComparision.SWoutside = aTopRight; // Debugging Tools if (debug) { if (aTopRightWithin) { b.lineNE.Draw(Color.blue, 1.0f); } if (aTopLeftWithin) { b.lineNW.Draw(Color.blue, 1.0f); } if (aBottomLeftWithin) { b.lineSW.Draw(Color.blue, 1.0f); } if (aBottomRightWithin) { b.lineSE.Draw(Color.blue, 1.0f); } } // Sides Vertical if (aTopLeft) { collisionBodyComparision.NWvertical |= (aleftWorld.x < brightWorld.x && aleftWorld.y < brightWorld.y); } if (aTopRight) { collisionBodyComparision.NEvertical |= (arightWorld.x > bleftWorld.x && arightWorld.y < bleftWorld.y); } if (aBottomRight) { collisionBodyComparision.SEvertical |= (bleftWorld.x < arightWorld.x && bleftWorld.y < arightWorld.y); } if (aBottomLeft) { collisionBodyComparision.SWvertical |= (brightWorld.x > aleftWorld.x && brightWorld.y < aleftWorld.y); } // Corners Exclusive if (aTopLeft && aTopRight) { collisionBodyComparision.Nexclusive = true; } if (aTopLeft && aBottomLeft) { collisionBodyComparision.Wexclusive = true; } if (aBottomLeft && aBottomRight) { collisionBodyComparision.Sexclusive = true; } if (aBottomRight && aTopRight) { collisionBodyComparision.Eexclusive = true; } // Sides Inclusive if (aTopLeft && (aBottomLeftWithin || aTopRightWithin)) { collisionBodyComparision.NWinclusive = true; } if (aBottomRight && (aBottomLeftWithin || aTopRightWithin)) { collisionBodyComparision.SEinclusive = true; } if (aTopRight && (aTopLeftWithin || aBottomRightWithin)) { collisionBodyComparision.NEinclusive = true; } if (aBottomLeft && (aBottomRightWithin || aTopLeftWithin)) { collisionBodyComparision.SWinclusive = true; } // Sides Exclusive if (aTopLeft && !aTopRight && !aBottomLeft) { collisionBodyComparision.NWexclusive = true; } if (aTopRight && !aTopLeft && !aBottomRight) { collisionBodyComparision.NEexclusive = true; } if (aBottomLeft && !aBottomRight && !aTopLeft) { collisionBodyComparision.SEexclusive = true; } if (aBottomRight && !aBottomLeft && !aTopRight) { collisionBodyComparision.SWexclusive = true; } // Above and Below if (arightWorld.x < brightWorld.x && aleftWorld.x > bleftWorld.x && (aBottomLeftWithin && aBottomRightWithin)) { collisionBodyComparision.aAbove = true; } if (arightWorld.x < brightWorld.x && aleftWorld.x > bleftWorld.x && (aTopLeftWithin && aTopRightWithin)) { collisionBodyComparision.aBelow = true; } return(collisionBodyComparision); }
// Extend and Stretch and increase size of collision Body public PixelBox Extend(Direction direction, float distance) { PixelBox copy = new PixelBox(this); return(copy); }
// Within Range of a collisionBody public bool WithinRange(PixelBox other, Direction direction, float distance = 0.4f, float negDistance = 2.0f) { PixelBoxComparison comparison = this.CompareWith(other); if (direction == Direction.NW) { if (PixelLine.DistanceOrthographic(lineNW, other.lineSE) < distance && PixelLine.DistanceOrthographic(lineNW, other.lineSE) > -negDistance && left.x < (other.right.x) && top.x > (other.bottom.x) && left.y < (other.right.y) && top.y > (other.bottom.y)) { return(true); } return(false); } else if (direction == Direction.NE) { if (PixelLine.DistanceOrthographic(lineNE, other.lineSW) < distance && PixelLine.DistanceOrthographic(lineNE, other.lineSW) > -negDistance && top.x < (other.bottom.x) && right.x > (other.left.x) && top.y > (other.bottom.y) && right.y < (other.left.y)) { return(true); } return(false); } else if (direction == Direction.SW) { if (PixelLine.DistanceOrthographic(lineSW, other.lineNE) > -distance && PixelLine.DistanceOrthographic(lineSW, other.lineNE) < negDistance && left.x < (other.right.x) && bottom.x > (other.top.x) && left.y > (other.right.y) && bottom.y < (other.top.y)) { return(true); } return(false); } else if (direction == Direction.SE) { if (PixelLine.DistanceOrthographic(lineSE, other.lineNW) > -distance && PixelLine.DistanceOrthographic(lineSE, other.lineNW) < negDistance && bottom.x < (other.top.x) && right.x > (other.left.x) && bottom.y < (other.top.y) && right.y > (other.left.y)) { return(true); } return(false); } else if (direction == Direction.All) { if (PixelLine.DistanceOrthographic(lineNW, other.lineSE) < distance && PixelLine.DistanceOrthographic(lineNW, other.lineSE) > -negDistance && left.x < (other.right.x) && top.x > (other.bottom.x) && left.y < (other.right.y) && top.y > (other.bottom.y)) { return(true); } if (PixelLine.DistanceOrthographic(lineNE, other.lineSW) < distance && PixelLine.DistanceOrthographic(lineNE, other.lineSW) > -negDistance && top.x < (other.bottom.x) && right.x > (other.left.x) && top.y > (other.bottom.y) && right.y < (other.left.y)) { return(true); } if (PixelLine.DistanceOrthographic(lineSW, other.lineNE) > -distance && PixelLine.DistanceOrthographic(lineSW, other.lineNE) < negDistance && left.x < (other.right.x) && bottom.x > (other.top.x) && left.y > (other.right.y) && bottom.y < (other.top.y)) { return(true); } if (PixelLine.DistanceOrthographic(lineSE, other.lineNW) > -distance && PixelLine.DistanceOrthographic(lineSE, other.lineNW) < negDistance && bottom.x < (other.top.x) && right.x > (other.left.x) && bottom.y < (other.top.y) && right.y > (other.left.y)) { return(true); } return(false); } return(false); }
public PixelBoxComparison CompareWith(PixelBox other, float margin = 0.0f) { PixelBoxComparison bodyComparison = CompareTwoCollisionBodies(this, other, margin); return(bodyComparison); }
protected override void Awake() { if (noCollision) { return; } collider2D = GetComponent <PolygonCollider2D>(); Debug.Assert(collider2D != null); for (int i = 0; i < collider2D.pathCount; ++i) { Debug.Assert(collider2D.GetPath(i).Length == 4); } Debug.Assert(transform.parent.GetComponent <PixelRoom>() == null); Debug.Assert(transform.parent.GetComponent <PolygonCollider2D>() == null); collisionBodies = new PixelBox[collider2D.pathCount]; for (int i = 0; i < collider2D.pathCount; ++i) { collisionBodies[i] = new PixelBox(); collisionBodies[i].top = collider2D.GetPath(i)[0]; collisionBodies[i].bottom = collider2D.GetPath(i)[0]; collisionBodies[i].left = collider2D.GetPath(i)[0]; collisionBodies[i].right = collider2D.GetPath(i)[0]; } for (int j = 0; j < collider2D.pathCount; ++j) { for (int i = 0; i < 4; ++i) { if (collider2D.GetPath(j)[i].y > collisionBodies[j].top.y) { collisionBodies[j].top = collider2D.GetPath(j)[i]; } if (collider2D.GetPath(j)[i].y < collisionBodies[j].bottom.y) { collisionBodies[j].bottom = collider2D.GetPath(j)[i]; } if (collider2D.GetPath(j)[i].x < collisionBodies[j].left.x) { collisionBodies[j].left = collider2D.GetPath(j)[i]; } if (collider2D.GetPath(j)[i].x > collisionBodies[j].right.x) { collisionBodies[j].right = collider2D.GetPath(j)[i]; } } } for (int i = 0; i < collider2D.pathCount; ++i) { collisionBodies[i].top += collider2D.offset; collisionBodies[i].bottom += collider2D.offset; collisionBodies[i].left += collider2D.offset; collisionBodies[i].right += collider2D.offset; } collisionBodiesP = new PixelBox[collider2D.pathCount]; for (int i = 0; i < collider2D.pathCount; ++i) { collisionBodiesP[i] = new PixelBox(); collisionBodiesP[i].top = collisionBodies[i].top + new Vector2(0, pixelProximity); collisionBodiesP[i].bottom = collisionBodies[i].bottom + new Vector2(0, -pixelProximity); collisionBodiesP[i].left = collisionBodies[i].left + new Vector2(-2 * pixelProximity, 0); collisionBodiesP[i].right = collisionBodies[i].right + new Vector2(2 * pixelProximity, 0); } }
// Returns 1 if in front of the other, returns 1 if object is in front of other public int CompareTo(PixelCollider other) { int comparison = 0; if (other == this) { return(0); } if (other is MultiBodyPixelCollider && this is MultiBodyPixelCollider) { MultiBodyPixelCollider a = this as MultiBodyPixelCollider; MultiBodyPixelCollider b = other as MultiBodyPixelCollider; Debug.Assert(a.collisionBodiesWorld.Count() > 0); Debug.Assert(b.collisionBodiesWorld.Count() > 0); // Find the front most box of all the boxes // TODO: Top sort for more complicated buildings for (int i = 0; i < a.collisionBodies.Count(); ++i) { for (int j = 0; j < b.collisionBodies.Count(); ++j) { int comp = PixelBox.CompareTwoCollisionBodies(a.collisionBodiesWorld[i], b.collisionBodiesWorld[j], 2.0f).inFront; if (comp == 1) { comparison = 1; } if (comp == -1) { comparison = -1; } } } } else if (other is MultiBodyPixelCollider || this is MultiBodyPixelCollider) { MultiBodyPixelCollider multi; PixelCollider single; if (other is MultiBodyPixelCollider) { multi = other as MultiBodyPixelCollider; single = this; } else { multi = this as MultiBodyPixelCollider; single = other; } PixelBox singleBody = single.collisionBodyWorld; // If any of the multi are in front of the single, multi wins int multiInFront = 0; for (int i = 0; i < multi.collisionBodiesWorld.Count(); ++i) { int comp = PixelBox.CompareTwoCollisionBodies(multi.collisionBodiesWorld[i], singleBody, 2.0f).inFront; if (comp == 1) { multiInFront = 1; } if (comp == -1) { multiInFront = -1; } } if (single != this) { comparison = multiInFront; } else { if (multiInFront == 1) { comparison = -1; } if (multiInFront == -1) { comparison = 1; } } } else if (other is RampCollider && transform.parent.GetComponent <Character>() != null || this is RampCollider && other.transform.parent.GetComponent <Character>() != null) { RampCollider rampCollider = (RampCollider)((other is RampCollider) ? other : this); PixelCollider characterCollider = (other is RampCollider) ? this : other; PixelBoxComparison bodyComparision = PixelBox.CompareTwoCollisionBodies(characterCollider.collisionBodyWorld, rampCollider.collisionBodyWorld, 0.0f); if (characterCollider.within || characterCollider.withinProximityBox) { if (other is RampCollider) { comparison = 1; } else { comparison = -1; } } else { Debug.Assert(this.colliderPoints.Length == 4); Debug.Assert(other.colliderPoints.Length == 4); PixelBox a = collisionBodyWorld; PixelBox b = other.collisionBodyWorld; comparison = PixelBox.CompareTwoCollisionBodies(a, b, 10.0f).inFront; } } else { Debug.Assert(this.colliderPoints.Length == 4); Debug.Assert(other.colliderPoints.Length == 4); PixelBox a = collisionBodyWorld; PixelBox b = other.collisionBodyWorld; comparison = PixelBox.CompareTwoCollisionBodies(a, b, 10.0f).inFront; } return(comparison); }
public virtual MovementRestriction CheckForCollision() { Debug.Assert(!(this is MultiBodyPixelCollider)); Vector3 castStart = transform.position; castStart.z = -10.0f; RaycastHit2D[] castStar = Physics2D.CircleCastAll(castStart, GameSettings.inspectRadius * 10.0f, Vector2.zero); MovementRestriction restriction = new MovementRestriction(); // Collided with floor PixelRoom floor = transform.parent.parent.GetComponent <PixelRoom>(); Debug.Assert(floor != null); Debug.Assert(floor.colliderPoints.Length == 4); PixelBoxComparison cbc = PixelBox.CompareTwoCollisionBodies(collisionBodyWorld, floor.collisionbodyWorld, -2.0f); if (!cbc.SEinside) { restriction.restrictSE = true; } if (!cbc.SWinside) { restriction.restrictSW = true; } if (!cbc.NEinside) { restriction.restrictNE = true; } if (!cbc.NWinside) { restriction.restrictNW = true; } // Collided with other object foreach (RaycastHit2D raycastHit in castStar) { PixelCollider otherPixelCollider = raycastHit.collider.GetComponent <PixelCollider>(); if (otherPixelCollider == null) { continue; } if (otherPixelCollider.noCollision) { continue; } if (otherPixelCollider.ParentIsContainer()) { continue; } if (!OtherPixelColliderSameParent(otherPixelCollider)) { continue; } Transform otherTransform = otherPixelCollider.gameObject.transform; if (otherPixelCollider is MultiBodyPixelCollider) { MultiBodyPixelCollider multi = otherPixelCollider as MultiBodyPixelCollider; foreach (PixelBox cbody in multi.collisionBodiesWorld) { cbody.Draw(Color.white, 1.0f); if (collisionBodyWorld.WithinRange(cbody, Direction.NW, 0.4f)) { restriction.restrictNW = true; } if (collisionBodyWorld.WithinRange(cbody, Direction.NE, 0.4f)) { restriction.restrictNE = true; } if (collisionBodyWorld.WithinRange(cbody, Direction.SW, 0.4f)) { restriction.restrictSW = true; } if (collisionBodyWorld.WithinRange(cbody, Direction.SE, 0.4f)) { restriction.restrictSE = true; } } } else if (otherPixelCollider is RampCollider) { Debug.Assert(otherPixelCollider.colliderPoints.Length == 4); RampCollider rampCollider = (RampCollider)otherPixelCollider; otherPixelCollider.collisionBodyWorld.Draw(Color.white, 1.0f); if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.NW, 0.4f)) { restriction.restrictNW = true; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.NE, 0.4f)) { restriction.restrictNE = true; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.SW, 0.4f)) { restriction.restrictSW = true; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.SE, 0.4f)) { restriction.restrictSE = true; } // Comparison with actual box PixelBoxComparison bodyComparison = PixelBox.CompareTwoCollisionBodies(collisionBodyWorld, rampCollider.collisionBodyWorld, 0.0f, true); PixelBoxComparison proximityComparison = PixelBox.CompareTwoCollisionBodies(collisionBodyWorld, rampCollider.proximityBodyWorld, 0.0f, true); // Close to the ramp collision (remove the wall collision) and prevent glitches Direction proximityDirection = Direction.All; if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.SE, navigationMargin, navigationMargin) && rampCollider.rampDirection == Direction.SE) { proximityDirection = Direction.SE; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.SW, navigationMargin, navigationMargin) && rampCollider.rampDirection == Direction.SW) { proximityDirection = Direction.SW; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.NE, navigationMargin, navigationMargin) && rampCollider.rampDirection == Direction.NE) { proximityDirection = Direction.NE; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.NW, navigationMargin, navigationMargin) && rampCollider.rampDirection == Direction.NW) { proximityDirection = Direction.NW; } // Entered the ramp bool closeToRamp = proximityDirection != Direction.All; // Free the character to go in that direction if (proximityComparison.inside) { if (rampCollider.rampDirection == Direction.NE) { restriction.restrictNE = false; } else if (rampCollider.rampDirection == Direction.NW) { restriction.restrictNW = false; } else if (rampCollider.rampDirection == Direction.SE) { restriction.restrictSE = false; } else if (rampCollider.rampDirection == Direction.SW) { restriction.restrictSW = false; } } // Check if entered ramp withinProximityBox = rampCollider.proximityBodyWorld.WithinCollisionBody(transform.position); if (withinProximityBox) { within = rampCollider.collisionBodyWorld.WithinCollisionBody(transform.position); if (bodyComparison.overlap) { // Remove glitch caused by going to the side of the walls if (rampCollider.rampDirection == Direction.NE || rampCollider.rampDirection == Direction.SW) { if (!proximityComparison.NWinside) { restriction.restrictNW = true; } if (!proximityComparison.SEinside) { restriction.restrictSE = true; } } else if (rampCollider.rampDirection == Direction.NW || rampCollider.rampDirection == Direction.SE) { if (!proximityComparison.NEinside) { restriction.restrictNE = true; } if (!proximityComparison.SWinside) { restriction.restrictSW = true; } } } if (within) { rampCollider.OnEffectorEnter(); } else { rampCollider.OnEffectorExit(); } } if (within) { // Draw the ramps rampCollider.collisionBodyRampedWorld.Draw(Color.magenta, 2.0f); PixelBox cramped = rampCollider.MatchCollisionBody(collisionBodyWorld); cramped.Draw(Color.magenta, 2.0f); // Ramp Collision mechanics restriction.restrictNE = false; restriction.restrictNW = false; restriction.restrictSE = false; restriction.restrictSW = false; // Collision with side of ramp PixelBoxComparison cbcRamp = PixelBox.CompareTwoCollisionBodies(cramped, rampCollider.collisionBodyRampedWorld, -2.0f); if (!cbcRamp.SEinside && rampCollider.rampDirection != Direction.NW) { restriction.restrictSE = true; } if (!cbcRamp.SWinside && rampCollider.rampDirection != Direction.NE) { restriction.restrictSW = true; } if (!cbcRamp.NEinside && rampCollider.rampDirection != Direction.SW) { restriction.restrictNE = true; } if (!cbcRamp.NWinside && rampCollider.rampDirection != Direction.SE) { restriction.restrictNW = true; } restriction.slopeDirection = rampCollider.rampDirection; restriction.slope = rampCollider.slope; // Check for room entry PixelStair pixelStair = otherPixelCollider.transform.parent.GetComponent <PixelStair>(); if (pixelStair != null) { bool above = rampCollider.OnFarSide(cramped); if (above) { restriction.enteredDoor = pixelStair; } } } } else { otherPixelCollider.collisionBodyWorld.Draw(Color.white, 1.0f); if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.NW, 0.4f)) { restriction.restrictNW = true; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.NE, 0.4f)) { restriction.restrictNE = true; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.SW, 0.4f)) { restriction.restrictSW = true; } if (collisionBodyWorld.WithinRange(otherPixelCollider.collisionBodyWorld, Direction.SE, 0.4f)) { restriction.restrictSE = true; } } } return(restriction); }
public bool WithinRampCollider(PixelBox body) { return(false); }
public bool AboveSegment(PixelBox body) { return(DistanceOrthographic(this, body.center) > 0); }