private BulletPathBlueprint ExtractBestRay(List <Tuple <BulletPathBlueprint, float> >[] rayClock, int iStart, int cid) { float bestQuality = rayClock[iStart].First(p => p.Item1.TargetCannonID == cid).Item2; BulletPathBlueprint bestRay = rayClock[iStart].First(p => p.Item1.TargetCannonID == cid).Item1; for (int delta = 0; delta < RESOLUTION; delta++) { var ideg = (iStart + delta + RESOLUTION) % RESOLUTION; var clockrays = rayClock[ideg].Where(p => p.Item1.TargetCannonID == cid).ToList(); if (!clockrays.Any()) { break; } foreach (var ray in clockrays) { if (ray.Item2 < bestQuality) { bestQuality = ray.Item2; bestRay = ray.Item1; } rayClock[ideg].Remove(ray); } } for (int delta = 1; delta < RESOLUTION; delta++) { var ideg = (iStart - delta + RESOLUTION) % RESOLUTION; var clockrays = rayClock[ideg].Where(p => p.Item1.TargetCannonID == cid).ToList(); if (!clockrays.Any()) { break; } foreach (var ray in clockrays) { if (ray.Item2 < bestQuality) { bestQuality = ray.Item2; bestRay = ray.Item1; } rayClock[ideg].Remove(ray); } } return(bestRay); }
private List <Tuple <BulletPathBlueprint, float> > FindBulletPaths(LevelBlueprint lvl, World world, ICannonBlueprint cannon, float deg) { float startRadians = deg * FloatMath.DegRad; var scale = cannon.Diameter / Cannon.CANNON_DIAMETER; var spawnPoint = new FPoint(cannon.X, cannon.Y) + new Vector2(scale * (Cannon.CANNON_DIAMETER / 2 + Bullet.BULLET_DIAMETER * 0.66f), 0).Rotate(startRadians); var spawnVeloc = new Vector2(1, 0).Rotate(startRadians) * Cannon.BULLET_INITIAL_SPEED; var fbpresult = FindBulletPaths(lvl, world, cannon.CannonID, spawnPoint, spawnVeloc, new List <Vector2>(), scale, 0); var result = new List <Tuple <BulletPathBlueprint, float> >(); foreach (var r in fbpresult) { var tgray = new BulletPathBlueprint(r.Item2.CannonID, startRadians, SimplifyRays(new Vector2(cannon.X, cannon.Y), r.Item1), r.Item1); result.Add(Tuple.Create(tgray, r.Item3)); } return(result); }
private List <Tuple <BulletPathBlueprint, float> > FindLaserPaths(LevelBlueprint lvl, World wBase, World wCollision, int sourceID, FPoint rcStart, List <Tuple <Vector2, Vector2> > sourcerays, float startRadians, float cannonRadians, int remainingRecasts, bool inGlassBlock, object objIgnore) { var none = new List <Tuple <BulletPathBlueprint, float> >(); if (remainingRecasts <= 0) { return(none); } var rays = sourcerays.ToList(); var rcEnd = rcStart + new Vector2(2048, 0).Rotate(startRadians); var traceResult = RayCastLaser(wBase, rcStart, rcEnd, objIgnore); var traceResult2 = RayCastLaser(wCollision, rcStart, rcEnd, objIgnore); if (traceResult2 != null && traceResult != null && traceResult2.Item1.UserData != traceResult.Item1.UserData) { // Dirty hit return(none); } if (traceResult == null) { return(none); } foreach (var r in rays) { if (Math2D.LineIntersectionExt(rcStart, traceResult.Item2, r.Item1.ToFPoint(), r.Item2.ToFPoint(), -0.1f, out _, out _, out _)) { return(none); } } var fCannon = traceResult.Item1.UserData as ICannonBlueprint; if (fCannon != null) { if (fCannon.CannonID == sourceID) { return(none); } var quality = Math2D.LinePointDistance(rcStart, traceResult.Item2, new FPoint(fCannon.X, fCannon.Y)); rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var path = new BulletPathBlueprint(fCannon.CannonID, cannonRadians, rays.ToArray()); return(new List <Tuple <BulletPathBlueprint, float> > { Tuple.Create(path, quality) }); } var fGlassBlock = traceResult.Item1.UserData as MarkerRefractionEdge; if (fGlassBlock != null) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var normal = traceResult.Item3; var aIn = (rcStart - rcEnd).ToAngle() - normal.ToAngle(); // sin(aIn) / sin(aOut) = currRefractIdx / Glass.RefractIdx var n = inGlassBlock ? (GlassBlockBlueprint.REFRACTION_INDEX / 1f) : (1f / GlassBlockBlueprint.REFRACTION_INDEX); var sinaOut = FloatMath.Sin(aIn) * n; var dat = new List <Tuple <BulletPathBlueprint, float> >(); var isRefracting = sinaOut <1 && sinaOut> -1; var isReflecting = FloatMath.Abs(aIn) > LaserNetwork.MIN_REFRACT_ANGLE && (!inGlassBlock || (inGlassBlock && !isRefracting)); if (isRefracting) // refraction { // refraction var aOut = FloatMath.Asin(sinaOut); var pRefractAngle = (-normal).ToAngle() + aOut; var sub = FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pRefractAngle, cannonRadians, remainingRecasts - 1, !inGlassBlock, fGlassBlock); dat.AddRange(sub); } if (isReflecting) { // reflection var pReflectVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); var sub = FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pReflectVec.ToAngle(), cannonRadians, remainingRecasts - 1, !inGlassBlock, fGlassBlock); dat.AddRange(sub); } return(dat); } var fGlassBlockCorner = traceResult.Item1.UserData as MarkerRefractionCorner; if (fGlassBlockCorner != null) { if (NO_LASER_CORNER_HITS) { return(none); } rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var dat = new List <Tuple <BulletPathBlueprint, float> >(); if (!inGlassBlock) { // reflection var pReflectVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); var sub = FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pReflectVec.ToAngle(), cannonRadians, remainingRecasts - 1, !inGlassBlock, fGlassBlockCorner); dat.AddRange(sub); } return(dat); } var fMirrorBlock = traceResult.Item1.UserData as MirrorBlockBlueprint; if (fMirrorBlock != null) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var pVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); return(FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1, inGlassBlock, fMirrorBlock)); } var fMirrorCircle = traceResult.Item1.UserData as MirrorCircleBlueprint; if (fMirrorCircle != null) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var pVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); return(FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1, inGlassBlock, fMirrorCircle)); } var fVoidWall = traceResult.Item1.UserData as VoidWallBlueprint; if (fVoidWall != null) { return(none); } var fVoidCircle = traceResult.Item1.UserData as VoidCircleBlueprint; if (fVoidCircle != null) { return(none); } var fPortal = traceResult.Item1.UserData as PortalBlueprint; if (fPortal != null) { bool hit = FloatMath.DiffRadiansAbs(traceResult.Item3.ToAngle(), FloatMath.ToRadians(fPortal.Normal)) < FloatMath.RAD_POS_005; if (!hit) { return(none); } rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var dat = new List <Tuple <BulletPathBlueprint, float> >(); foreach (var outportal in lvl.BlueprintPortals.Where(p => p.Side != fPortal.Side && p.Group == fPortal.Group)) { var cIn = new FPoint(fPortal.X, fPortal.Y); var cOut = new FPoint(outportal.X, outportal.Y); var rot = FloatMath.ToRadians(outportal.Normal - fPortal.Normal + 180); var stretch = outportal.Length / fPortal.Length; var newAngle = FloatMath.NormalizeAngle(startRadians + rot); var newStart = cOut + stretch * (traceResult.Item2 - cIn).Rotate(rot); newStart = newStart.MirrorAtNormal(cOut, Vector2.UnitX.Rotate(FloatMath.ToRadians(outportal.Normal))); var sub = FindLaserPaths(lvl, wBase, wCollision, sourceID, newStart, rays, newAngle, cannonRadians, remainingRecasts - 1, inGlassBlock, outportal); dat.AddRange(sub); } return(dat); } var fBorder = traceResult.Item1.UserData as MarkerCollisionBorder; if (fBorder != null) { if (lvl.WrapMode == LevelBlueprint.WRAPMODE_DONUT) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStartX = traceResult.Item2.X; var pNewStartY = traceResult.Item2.Y; switch (fBorder.Side) { case FlatAlign4.NN: pNewStartY += lvl.LevelHeight; break; case FlatAlign4.EE: pNewStartX -= lvl.LevelWidth; break; case FlatAlign4.SS: pNewStartY -= lvl.LevelHeight; break; case FlatAlign4.WW: pNewStartX += lvl.LevelWidth; break; default: throw new ArgumentOutOfRangeException(); } var pVec = rcEnd - rcStart; var pNewStart = new FPoint(pNewStartX, pNewStartY); return(FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1, inGlassBlock, fBorder)); } else if (lvl.WrapMode == LevelBlueprint.WRAPMODE_SOLID) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var pVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); return(FindLaserPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1, inGlassBlock, fBorder)); } throw new Exception("Unsupported WrapMode: " + lvl.WrapMode); } throw new Exception("Unknown rayTrace resturn ficture: " + traceResult.Item1.UserData); }
private List <Tuple <BulletPathBlueprint, float> > FindBulletPaths(LevelBlueprint lvl, World wBase, World wCollision, int sourceID, FPoint rcStart, List <Tuple <Vector2, Vector2> > sourcerays, float startRadians, float cannonRadians, int remainingRecasts) { var none = new List <Tuple <BulletPathBlueprint, float> >(); if (remainingRecasts <= 0) { return(none); } var rays = sourcerays.ToList(); var rcEnd = rcStart + new Vector2(2048, 0).Rotate(startRadians); var traceResult = RayCastBullet(wBase, rcStart, rcEnd); var traceResult2 = RayCastBullet(wCollision, rcStart, rcEnd); if (traceResult2 != null && traceResult != null && traceResult2.Item1.UserData != traceResult.Item1.UserData) { // Dirty hit return(none); } if (traceResult == null) { return(none); } var fCannon = traceResult.Item1.UserData as ICannonBlueprint; if (fCannon != null) { if (fCannon.CannonID == sourceID) { return(none); } var quality = Math2D.LinePointDistance(rcStart, traceResult.Item2, new FPoint(fCannon.X, fCannon.Y)); rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var path = new BulletPathBlueprint(fCannon.CannonID, cannonRadians, rays.ToArray()); return(new List <Tuple <BulletPathBlueprint, float> > { Tuple.Create(path, quality) }); } var fGlassBlock = traceResult.Item1.UserData as GlassBlockBlueprint; if (fGlassBlock != null) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var pVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); return(FindBulletPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1)); } var fMirrorBlock = traceResult.Item1.UserData as MirrorBlockBlueprint; if (fMirrorBlock != null) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var pVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); return(FindBulletPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1)); } var fMirrorCircle = traceResult.Item1.UserData as MirrorCircleBlueprint; if (fMirrorCircle != null) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var pVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); return(FindBulletPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1)); } var fVoidWall = traceResult.Item1.UserData as VoidWallBlueprint; if (fVoidWall != null) { return(none); } var fVoidCircle = traceResult.Item1.UserData as VoidCircleBlueprint; if (fVoidCircle != null) { return(none); } var fBlackhole = traceResult.Item1.UserData as BlackHoleBlueprint; if (fBlackhole != null) { return(none); // Black holes are _not_ correctly calculated in this preprocessor } var fPortal = traceResult.Item1.UserData as PortalBlueprint; if (fPortal != null) { bool hit = FloatMath.DiffRadiansAbs(traceResult.Item3.ToAngle(), FloatMath.ToRadians(fPortal.Normal)) < FloatMath.RAD_POS_005; if (!hit) { return(none); } rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var dat = new List <Tuple <BulletPathBlueprint, float> >(); foreach (var outportal in lvl.BlueprintPortals.Where(p => p.Side != fPortal.Side && p.Group == fPortal.Group)) { var cIn = new FPoint(fPortal.X, fPortal.Y); var cOut = new FPoint(outportal.X, outportal.Y); var rot = FloatMath.ToRadians(outportal.Normal - fPortal.Normal + 180); var stretch = outportal.Length / fPortal.Length; var newAngle = FloatMath.NormalizeAngle(startRadians + rot); var newStart = cOut + (traceResult.Item2 - cIn).Rotate(rot) * stretch; newStart = newStart.MirrorAtNormal(cOut, Vector2.UnitX.Rotate(FloatMath.ToRadians(outportal.Normal))); var sub = FindBulletPaths(lvl, wBase, wCollision, sourceID, newStart, rays, newAngle, cannonRadians, remainingRecasts - 1); dat.AddRange(sub); } return(dat); } var fBorder = traceResult.Item1.UserData as MarkerCollisionBorder; if (fBorder != null) { if (lvl.WrapMode == LevelBlueprint.WRAPMODE_DONUT) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStartX = traceResult.Item2.X; var pNewStartY = traceResult.Item2.Y; switch (fBorder.Side) { case FlatAlign4.NN: pNewStartY += lvl.LevelHeight; break; case FlatAlign4.EE: pNewStartX -= lvl.LevelWidth; break; case FlatAlign4.SS: pNewStartY -= lvl.LevelHeight; break; case FlatAlign4.WW: pNewStartX += lvl.LevelWidth; break; default: throw new ArgumentOutOfRangeException(); } var pVec = rcEnd - rcStart; var pNewStart = new FPoint(pNewStartX, pNewStartY); return(FindBulletPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1)); } else if (lvl.WrapMode == LevelBlueprint.WRAPMODE_SOLID) { rays.Add(Tuple.Create(rcStart.ToVec2D(), traceResult.Item2.ToVec2D())); var pNewStart = traceResult.Item2; var pVec = Vector2.Reflect(rcEnd - rcStart, traceResult.Item3); return(FindBulletPaths(lvl, wBase, wCollision, sourceID, pNewStart, rays, pVec.ToAngle(), cannonRadians, remainingRecasts - 1)); } throw new Exception("Unsupported WrapMode: " + lvl.WrapMode); } throw new Exception("Unknown rayTrace resturn ficture: " + traceResult.Item1.UserData); }