void FixedUpdate() { if (!initialized) { return; } //See if any teams have captured the waypoint. foreach (Color c in collidedWith.Keys) { if (teams[c].Count == collidedWith[c].Count) { //Give the waypoint capture to the first player that entered the waypoint. teams[c][0].OwnerStats.WaypointsCaptured += 1; WorldConstants.Creator.CreateFloatingTextsForPlayers(WorldConstants.Creator.FourMessages(WorldConstants.ActorConsts.WaypointCapturedMessages, teams[c][0], null), st => st.ActorData.Team == c, WorldConstants.Creator.CreateWaypointFloatingText); WorldConstants.CrowdCheering.CreateCrowdCheer(CrowdCheers.Events.WaypointCaptured); GameObject.Destroy(gameObject); return; } } //Now check to see which players aren't colliding anymore. List <Color> keys = collidedWith.Keys.ToList(); List <StateMachine> temp; RecBounds thisB = new RecBounds(collider.bounds); foreach (Color c in keys) { temp = collidedWith[c].ToList(); foreach (StateMachine st in temp) { if (!st.ActorBounds.Intersects(thisB)) { collidedWith[c].Remove(st); } } } }
/// <summary> /// Checks to see if this actor got outside the level somehow, and puts him back in. /// </summary> private void CheckOutside() { if (!ActorBounds.Intersects(WorldConstants.LevelBounds)) { Vector2 pos = transform.position; RecBounds levelB = WorldConstants.LevelBounds; Vector2 dir = new Vector2(Sign(levelB.center.x - pos.x, 0.001f), Sign(levelB.center.y - pos.y, 0.001f)); //Move in along the X. if (!Manager.LevelGen.GenSettings.WrapX && !(new Interval(levelB.left, levelB.right, true, 2).Inside(pos.x))) { transform.position += new Vector3(2.0f * dir.x, 0.0f, transform.position.z); Velocity.x = 0.0f; if (IsPlayer && !(CurrentState is InAirState) && !(CurrentState is HurtState)) { ChangeState(ScriptableObject.CreateInstance <InAirState>(), false); } } //Move in along the Y. if (!Manager.LevelGen.GenSettings.WrapY && !(new Interval(levelB.bottom, levelB.top, true, 2).Inside(pos.y))) { transform.position += new Vector3(0.0f, 2.0f * dir.y, transform.position.z); Velocity.y = 0.0f; if (IsPlayer && !(CurrentState is InAirState) && !(CurrentState is HurtState)) { ChangeState(ScriptableObject.CreateInstance <InAirState>(), false); } } } }
public override void EnteringState() { Owner.Animator.CurrentAnimation = Animations.P_CeilingSlide; originalParticleYSpeed = Owner.RunningParts.WorldVelocity.y; Owner.RunningParts.WorldVelocity = new Vector3(Owner.RunningParts.WorldVelocity.x, 0.0f); RecBounds ab = Owner.ActorBounds; Owner.RunningParts.Position = new Vector3(ab.center.x, ab.top, Owner.RunningParts.Position.z); //Make the sliding noise. if (useSlidingNoise) { slidingNoise = new FadeLoopNoise(WorldConstants.PlayPhysNoises.GetNoise(PlayerPhysicsNoises.Events.Slide), "Sliding on Ceiling"); } else { slidingNoise = new FadeLoopNoise(WorldConstants.PlayPhysNoises.GetNoise(PlayerPhysicsNoises.Events.Run), "Runnin on Ceiling"); } slidingNoise.StartLoop(); slidingNoiseMaxVolume = slidingNoise.Loop.GetComponent <ControlledNoise>().MaxVolume; }
/// <summary> /// Adds a static wall to be tracked. /// </summary> public void AddWall(RecBounds wall) { wallBounds.Add(wall); }
/// <summary> /// Finds if the given side of the given wall exists in this system. /// </summary> public bool SideExists(RecBounds wall, ColType side) { return(references.ContainsKey(wall) && references[wall].ContainsKey(side)); }
/// <summary> /// Finds if the given wall exists in this system. /// </summary> public bool WallExists(RecBounds wall) { return(references.ContainsKey(wall)); }
/// <summary> /// Gets all sides of the givne wall that represent part of a Line. /// </summary> /// <param name="wall"></param> /// <returns></returns> public IEnumerable <ColType> GetSides(RecBounds wall) { return(references[wall].Keys.ToList()); }
/// <summary> /// Gets all Lines that the given wall is a part of. /// </summary> public IEnumerable <Line> GetLines(RecBounds wall) { return(references[wall].Values.ToList()); }
public static ColType CollisionType(RecBounds actor, Vector2 velocity, RecBounds wall) { //TODO: [SO FAR, THIS DOESN'T SEEM NECESSARY]. If the player hit a wall but only barely, and the y interval below/above the wall that the player is mainly occupying is clear, let him pass through the wall. //Figure out which edge was collided with first: top/bottom, or side. Return that edge. //1) Get the closest wall corner to the actor's center, and the opposite corner on the actor's bounds. Vector2 lastCenter = actor.center - (velocity * Time.fixedDeltaTime); ColType topOrBottom = (lastCenter.y > wall.center.y) ? ColType.Top : ColType.Bottom; ColType leftOrRight = (lastCenter.x > wall.center.x) ? ColType.Right : ColType.Left; //If the actor is going at least half a unit per second, use Vector2 playerCenter = new Vector2(actor.center.x, actor.center.y); Vector2 wallCorner = new Vector2(wall.center.x - wall.extents.x, wall.center.y - wall.extents.y); Vector2 actorOppositeCorner = new Vector2(actor.center.x + actor.extents.x, actor.center.y + actor.extents.y); float temp, tempDistSqr = System.Single.MaxValue; //Go through every corner searching for the closest. Vector2 tempDir, tempCorner; for (int i = 0; i < 4; ++i) { switch (i) { case 0: tempDir = new Vector2(-1.0f, -1.0f); break; case 1: tempDir = new Vector2(-1.0f, 1.0f); break; case 2: tempDir = new Vector2(1.0f, -1.0f); break; case 3: tempDir = new Vector2(1.0f, 1.0f); break; default: tempDir = Vector2.zero; break; } tempCorner = new Vector2(wall.center.x + (tempDir.x * wall.extents.x), wall.center.y + (tempDir.y * wall.extents.y)); temp = Mathf.Pow(playerCenter.x - tempCorner.x, 2.0f) + Mathf.Pow(playerCenter.y - tempCorner.y, 2.0f); if (temp < tempDistSqr) { tempDistSqr = temp; actorOppositeCorner = new Vector2(actor.center.x - (tempDir.x * actor.extents.x), actor.center.y - (tempDir.y * actor.extents.y)); wallCorner = tempCorner; } } //2) Get the amount of overlap along both dimensions. Vector2 overlap = wallCorner - actorOppositeCorner; //3) Handle edge cases for the overlap. const float marginOfErrorOverlap = 0.01f; if (Mathf.Abs(overlap.x) <= marginOfErrorOverlap) { return(leftOrRight); } if (Mathf.Abs(overlap.y) <= marginOfErrorOverlap) { return(topOrBottom); } //4) Handle edge cases for velocity. //No margin of error is needed because StateMachines already set the velocity to 0 when under a certain magnitude. if (velocity.x == 0) { return(topOrBottom); } if (velocity.y == 0) { return(leftOrRight); } //5) Get the amount of time needed at the actor's current velocity // to move both the side and top/bottom edges back to bare contact with the wall. Vector2 t = new Vector2(Mathf.Abs(overlap.x / velocity.x), Mathf.Abs(overlap.y / velocity.y)); //6) Depending on which edge would take longer to move back to bare contact // (i.e. which edge was collided with first), return the correct value. if (t.x < t.y) { return(leftOrRight); } else { return(topOrBottom); } }
void CollideWithWall(RecBounds bounds) { if (DebugStopOnCol) { DebugStopOnCol = DebugStopOnCol; } StateMachine.DrawBounds(bounds, Color.cyan); //Get the side of the wall that was collided with. Ignore collision if necessary. ColType c = CollisionType(thisActor.NextActorBounds, thisActor.Velocity, bounds); if (disableVerticalColl && (c == ColType.Bottom || c == ColType.Top)) { return; } //Get the closest single wall inside the bound to the player. Vector2 wallCenter = new Vector2(Mathf.RoundToInt(transform.position.x), Mathf.RoundToInt(transform.position.y)); RecBounds tempB; wallCenter = new Vector2(Mathf.Clamp(wallCenter.x, bounds.left + 0.5f, bounds.right - 0.5f), Mathf.Clamp(wallCenter.y, bounds.bottom + 0.5f, bounds.top - 0.5f)); if (false && !bounds.Inside(wallCenter)) { switch (c) { case ColType.Bottom: wallCenter.y += 1.0f; break; case ColType.Left: wallCenter.x += 1.0f; break; case ColType.Top: wallCenter.y -= 1.0f; break; case ColType.Right: wallCenter.x -= 1.0f; break; default: throw new NotImplementedException(); } } tempB = new RecBounds(wallCenter, new Vector2(1.0f, 1.0f)); Line l = null; //Check to see if the line exists in the collision tracker. if (!colTracker.Lines.WallExists(tempB)) { //Debug.Log("Wall not valid: wall " + bounds + ", small wall " + tempB + ", side " + CollisionManager.ToString(c)); //Create a substitute line. switch (c) { case ColType.Bottom: l = new Line(Line.Orientation.Horizontal, new Interval(tempB.left, tempB.right, true, 2), tempB.bottom); break; case ColType.Left: l = new Line(Line.Orientation.Vertical, new Interval(tempB.bottom, tempB.top, true, 2), tempB.left); break; case ColType.Top: l = new Line(Line.Orientation.Horizontal, new Interval(tempB.left, tempB.right, true, 2), tempB.top); break; case ColType.Right: l = new Line(Line.Orientation.Vertical, new Interval(tempB.bottom, tempB.top, true, 2), tempB.right); break; } } else if (!colTracker.Lines.SideExists(tempB, c)) { //Debug.Log("Coll. side not valid: wall " + bounds + ", small wall " + tempB + ", side " + CollisionManager.ToString(c)); //Create a substitute line. switch (c) { case ColType.Bottom: l = new Line(Line.Orientation.Horizontal, new Interval(tempB.left, tempB.right, true, 2), tempB.bottom); break; case ColType.Left: l = new Line(Line.Orientation.Vertical, new Interval(tempB.bottom, tempB.top, true, 2), tempB.left); break; case ColType.Top: l = new Line(Line.Orientation.Horizontal, new Interval(tempB.left, tempB.right, true, 2), tempB.top); break; case ColType.Right: l = new Line(Line.Orientation.Vertical, new Interval(tempB.bottom, tempB.top, true, 2), tempB.right); break; } } else { l = colTracker.Lines.GetLine(tempB, c); } l = new Line(l.Dir, new Interval(l.LineRange), l.ConstValue); l.LineRange.Range -= ColLineMarginOfError * 2.0f; //If the collision was already being tracked, don't change anything. if (WallSides[c].Contains(l)) { return; } //Otherwise, start tracking the line. WallSides[c].Add(l); SendMessage("WallCollision", new ColIndexPair() { Index = WallSides[c].Count - 1, Type = c }, SendMessageOptions.DontRequireReceiver); }
public static bool OnLine(Line l, ColType side, RecBounds b) { const float error = 0.01f; switch (side) { case ColType.Bottom: //Make sure this line makes sense. if (l.Dir == Line.Orientation.Vertical) { throw new ArgumentException(); } //Next, if the bound's top edge isn't touching the line, exit. float top = b.center.y + b.extents.y; float lineTop = l.ConstValue; if (!StateMachine.WithinError(top, lineTop, error)) { return(false); } //Finally, check to make sure the bounds are within the range of the line. return(l.LineRange.Touches(new Interval(b.center.x - b.extents.x, b.center.x + b.extents.x, true, 2))); case ColType.Top: //Make sure this line makes sense. if (l.Dir == Line.Orientation.Vertical) { throw new ArgumentException(); } //Next, if the bound's bottom edge isn't touching the line, exit. float bottom = b.center.y - b.extents.y; float lineBottom = l.ConstValue; if (!StateMachine.WithinError(bottom, lineBottom, error)) { return(false); } //Finally, check to make sure the bounds are within the range of the line. return(l.LineRange.Touches(new Interval(b.center.x - b.extents.x, b.center.x + b.extents.x, true, 2))); case ColType.Left: //Make sure this line makes sense. if (l.Dir == Line.Orientation.Horizontal) { throw new ArgumentException(); } //Next, if the bound's right edge isn't touching the line, exit. float right = b.center.x + b.extents.x; float lineRight = l.ConstValue; if (!StateMachine.WithinError(right, lineRight, error)) { return(false); } //Finally, check to make sure the bounds are within the range of the line. return(l.LineRange.Touches(new Interval(b.center.y - b.extents.y, b.center.y + b.extents.y, true, 2))); case ColType.Right: //Make sure this line makes sense. if (l.Dir == Line.Orientation.Horizontal) { throw new ArgumentException(); } //Next, if the bound's left edge isn't touching the line, exit. float left = b.center.x - b.extents.x; float lineLeft = l.ConstValue; if (!StateMachine.WithinError(left, lineLeft, error)) { return(false); } //Finally, check to make sure the bounds are within the range of the line. return(l.LineRange.Touches(new Interval(b.center.y - b.extents.y, b.center.y + b.extents.y, true, 2))); default: throw new NotImplementedException(); } }
/// <summary> /// Adds the given wall boundaries to the collection of walls to create. /// </summary> /// <exception cref="InvalidOperationException">Thrown if this object is no longer taking walls to create.</exception> public void AddWall(RecBounds b) { if (currentWallsState != InitializeWallsState.TakingWalls) { throw new System.InvalidOperationException("This object is no longer taking walls!"); } WallBounds.Add(b); //If the wall is close enough to the edge and the level wraps around horizontally, duplicate it. if (WrapX) { float left = b.center.x - b.extents.x, right = b.center.x + b.extents.x; //If the wall is near the left edge, put a wall on the right. if (Mathf.Abs(left - (levelBounds.center.x - levelBounds.extents.x)) <= 1.0f) { MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(WorldConstants.Size.x, 0.0f), b.size)); //If the level also wraps vertically, put the wall above and below. if (WrapY) { MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(WorldConstants.Size.x, -WorldConstants.Size.y), b.size)); MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(WorldConstants.Size.x, WorldConstants.Size.y), b.size)); } } //If the wall is near the right edge, put a wall on the left. if (Mathf.Abs(right - (levelBounds.center.x + levelBounds.extents.x)) <= 1.0f) { MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(-WorldConstants.Size.x, 0.0f), b.size)); //If the level also wraps vertically, put the wall above and below. if (WrapY) { MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(-WorldConstants.Size.x, -WorldConstants.Size.y), b.size)); MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(-WorldConstants.Size.x, WorldConstants.Size.y), b.size)); } } } //Do the same for vertical wrapping. if (WrapY) { float bottom = b.center.y - b.extents.y, top = b.center.y + b.extents.y; //If the wall is near the bottom edge, put a wall on the top. if (Mathf.Abs(bottom - (levelBounds.center.y - levelBounds.extents.y)) <= 1.0f) { MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(0.0f, WorldConstants.Size.y), b.size)); //If the level also wraps horizontally, put the wall to the left and right. if (WrapX) { MirroredWallBounds.Add(new RecBounds(b.center - new Vector2(-WorldConstants.Size.x, WorldConstants.Size.y), b.size)); MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(WorldConstants.Size.x, WorldConstants.Size.y), b.size)); } } //If the wall is near the top edge, put a wall on the bottom. if (Mathf.Abs(top - (levelBounds.center.y + levelBounds.extents.y)) <= 1.0f) { MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(0.0f, -WorldConstants.Size.y), b.size)); //If the level also wraps horizontally, put the wall to the left and right. if (WrapX) { MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(WorldConstants.Size.x, -WorldConstants.Size.y), b.size)); MirroredWallBounds.Add(new RecBounds(b.center + new Vector2(-WorldConstants.Size.x, -WorldConstants.Size.y), b.size)); } } } }