private static Dir4 GetNormal(Loc invEntry, Loc invExit, Multiplier entryX, Multiplier entryY) { if (entryX > entryY) { return((invEntry.X < 0) || (invEntry.X == 0 && invExit.X < 0) ? Dir4.Right : Dir4.Left); } else if (entryX < entryY) { return((invEntry.Y < 0 || (invEntry.Y == 0 && invExit.Y < 0)) ? Dir4.Down : Dir4.Up); } else { return(Dir4.None); } }
private static Hit ResolveNarrow(Loc origin1, Loc origin2, Loc destination, Rect other) { var velocity = (destination - origin1); Loc invEntry, invExit; Multiplier entryX, entryY, exitX, exitY; if (velocity.X > 0) { invEntry.X = other.Left - origin2.X; invExit.X = other.Right - origin1.X; } else { invEntry.X = other.Right - origin1.X; invExit.X = other.Left - origin2.X; } if (velocity.Y > 0) { invEntry.Y = other.Top - origin2.Y; invExit.Y = other.Bottom - origin1.Y; } else { invEntry.Y = other.Bottom - origin1.Y; invExit.Y = other.Top - origin2.Y; } if (velocity.X == 0) { entryX = Multiplier.MinValue; exitX = Multiplier.MaxValue; } else { entryX = new Multiplier(invEntry.X, velocity.X); exitX = new Multiplier(invExit.X, velocity.X); if (entryX > new Multiplier(1, 1)) { entryX = Multiplier.MaxValue; } } if (velocity.Y == 0) { entryY = Multiplier.MinValue; exitY = Multiplier.MaxValue; } else { entryY = new Multiplier(invEntry.Y, velocity.Y); exitY = new Multiplier(invExit.Y, velocity.Y); if (entryY > new Multiplier(1, 1)) { entryY = Multiplier.MinValue; } } var entryTime = Multiplier.Max(entryX, entryY); var exitTime = Multiplier.Min(exitX, exitY); if ((entryTime > exitTime || entryX == Multiplier.MinValue && entryY == Multiplier.MinValue) || (entryX == Multiplier.MinValue && (origin2.X < other.Left || origin1.X > other.Right)) || entryY == Multiplier.MinValue && (origin2.Y < other.Top || origin1.Y > other.Bottom)) { return(null); } var result = new Hit() { Amount = entryTime, Position = origin1 + velocity * entryTime.Numerator / entryTime.Denominator, Normal = GetNormal(invEntry, invExit, entryX, entryY), }; return(result); }