예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }