コード例 #1
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        public myLineSegment(double x1, double y1, double x2, double y2)
        {
            p1 = new myPoint(x1, y1);
            p2 = new myPoint(x2, y2);

            v = new myVector(x2 - x1, y2 - y1);
        }
コード例 #2
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        // Update this segment based on new information
        public void Update(myPoint p1, myPoint p2)
        {
            this.p1 = p1;
            this.p2 = p2;

            v = new myVector(p2.x - p1.x, p2.y - p1.y);
        }
コード例 #3
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        public myLineSegment(double x, double y, myVector v)
        {
            p1 = new myPoint(x, y);
            p2 = new myPoint(x + v.x, y + v.y);

            this.v = v;
        }
コード例 #4
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        ////////////////////////////////////
        // Derp-LineSegment Circle Casting - for field tile collisions
        // Returns: true if collision, false otherwise
        // out double t: this will be the parameter t, how far we can move along our vector before we get within Derp's radius of the line segment
        ////////////////////////////////////
        public static bool DerpLineSegmentCast(Derp d, myVector v, myLineSegment wall, out double t)
        {
            myLineSegment derpMoveLine = new myLineSegment(d.x, d.y, v);

            t = derpMoveLine.SegmentIntersectionWithRadius(wall, d.stats.radius);

            return(t < 1.0 - 1e-6);
        }
コード例 #5
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        public myLineSegment(myPoint p1, myPoint p2)
        {
            this.p1 = p1;
            this.p2 = p2;

            if (p1 != null && p2 != null)
            {
                v = new myVector(p2.x - p1.x, p2.y - p1.y);
            }
        }
コード例 #6
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        public double SegmentIntersectionWithRadius(myLineSegment o, double radius)
        {
            // get determinate and check for parallel lines
            double D = v.cross(o.v);

            if (Math.Abs(D) < 1e-6)
            {
                // Are we already within the line radius?
                if (o.DistToPoint2(p1) < radius * radius)
                {
                    return(0.0);
                }
                // Check if we are now moving onto the line segement.
                else if (NonIntersectingSegmentDistance(o, 0.0, radius) < 0.1)
                {
                    // return 1.0;
                    return(Math.Min(Geometry.MovingCirlcePointCast(this, radius, o.p1), Geometry.MovingCirlcePointCast(this, radius, o.p2)));
                }
                // No collision
                else
                {
                    return(1.0);
                }
            }

            // relative vector from the other segments starting point to my own
            myVector relVect = new myVector(p1, o.p1);
            double   t       = relVect.cross(o.v) / D;
            double   u       = relVect.cross(v) / D;

            // find if the intersection happens along the other line segment
            if (u < 0.0 || u > 1.0)
            {
                return(NonIntersectingSegmentDistance(o, t, radius));
            }

            // find if the intersection happens along this line segment
            if (t < 0.0 || t > 1.0)
            {
                return(NonIntersectingSegmentDistance(o, t, radius));
            }

            // An intersection is happening! Scoot the t parameter back a bit for the radius and buffer then return it
            // Scoot t back so the radius is equal to our radius
            double sintheta = Math.Abs(o.v.cross(v)) / (v.mag() * o.v.mag());

            t -= (radius / sintheta) / v.mag();

            // also remove the collision buffer, then return it
            t -= (CollisionBuffer / v.mag());
            return(t < 0.0 ? 0.0 : t);
        }
コード例 #7
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        // The above situation in a more general form
        static public double MovingCirlcePointCast(myLineSegment move, double radius, myPoint point)
        {
            double distX = move.p1.x - point.x;
            double distY = move.p1.y - point.y;

            // make sure we are close before we do any of the computational checking
            if (distX * distX + distY * distY > distSquaredThreshholdX)
            {
                return(1.0);
            }

            // solve the quadratic to find the intersection of two circles
            myPoint  p1 = move.p1;
            myPoint  p2 = point;
            myVector v  = move.v;

            double A = v.x * v.x + v.y * v.y;
            double B = 2 * (p1.x * v.x - p2.x * v.x + p1.y * v.y - p2.y * v.y);
            double C = (p1.x * p1.x) + (p2.x * p2.x) - 2 * p2.x * p1.x + (p1.y * p1.y) + (p2.y * p2.y) - 2 * p2.y * p1.y - (radius * radius);

            // unreal answers or a t that is greater than 1.0 means no collision
            double discr = (B * B) - 4 * A * C;

            if (discr < 0.0)
            {
                return(1.0); //imaginary answer
            }
            double t = (-B - Math.Sqrt(discr)) / (2 * A);

            if (t > 1.0)
            {
                return(1.0); // no collision with this step size
            }
            // this is detecting a collision behind us
            // NOTICE: there may be issues here in the future... if someone moves into us? (wait... they can't though. we guarentee that no one will move somewhere they can't... I think...)
            if (t < 0.0)
            {
                return(1.0);
            }

            // BUFFER
            // if we let them get right up next to each other, sometimes the floating point error is enough to let them slip through (I think)
            // add a buffer if there is a collision
            if (t < 1.0 - 1e-6)
            {
                t -= bufferDistance / Math.Sqrt(v.x * v.x + v.y * v.y);
                t  = Math.Max(t, 0.0);
            }

            return(t);
        }
コード例 #8
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        // Find the nearest cardinal direction to a vector (for snapping movement and sprites to 8 frames)
        public static int GetNearestCardinalDir(myVector v)
        {
            int ret = 0;

            for (int i = 1; i < 8; ++i)
            {
                if (v.dot(Geometry.cardinalUnitVectors[i]) > v.dot(Geometry.cardinalUnitVectors[ret]))
                {
                    ret = i;
                }
            }

            return(ret);
        }
コード例 #9
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
        // return the squared distanc to the point (remove squareroots)
        public double DistToPoint2(myPoint p)
        {
            // my length squared
            double l2 = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);

            // find the parameterized value of where the nearest point would be
            // (dot product of my vector to the vector from my start to the point)
            myVector toPoint = new myVector(p1, p);
            double   t       = v.dot(toPoint) / l2;

            if (t < 0.0)
            {
                return(p1.distance2(p));
            }
            if (t > 1.0)
            {
                return(p2.distance2(p));
            }

            // it's on the line segment, project to the position
            myPoint projPoint = new myPoint(p1.x + t * v.x, p1.y + t * v.y);

            return(projPoint.distance2(p));
        }
コード例 #10
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
 public double cross(myVector o)
 {
     return(x * o.y - y * o.x);
 }
コード例 #11
0
ファイル: Geometry.cs プロジェクト: GoodSky/game-nuggets
 public double dot(myVector o)
 {
     return(x * o.x + y * o.y);
 }
コード例 #12
0
ファイル: Field.cs プロジェクト: GoodSky/game-nuggets
        // Check for a Derp's Circle-Cast across the field
        // This will work like a BFS, starting from the initial position
        // then check all 4 corners around the position to build on the bfs
        public bool CheckFieldCollision(Derp d, myVector v, out double t, out myLineSegment col)
        {
            // initial optimistic setup that there will not be a collision
            bool ret = false;

            t   = 1.0;
            col = null;

            // calculate starting point
            int startX = (int)(d.x / BLOCK_WIDTH);
            int startY = (int)(d.y / BLOCK_HEIGHT);

            // Unit Vector in desired direction
            myVector vUnit = new myVector(v.x, v.y);

            vUnit.toUnit();

            // set up the bfs
            Queue <SimpleNode> q = new Queue <SimpleNode>();

            bool[,] vis = new bool[height + 1, width + 1];

            q.Enqueue(new SimpleNode(startX, startY, 0));
            vis[startY, startX] = true;

            // Create the 4 line segments so we don't have to do quiiite as much object creation in this loop
            myLineSegment[] segs = new myLineSegment[4];
            for (int i = 0; i < 4; ++i)
            {
                segs[i] = new myLineSegment(null, null);
            }

            // BFS
            int[] dx       = { 0, 1, 0, -1 };
            int[] dy       = { -1, 0, 1, 0 };
            int   cur_step = 0;

            while (q.Count > 0)
            {
                SimpleNode cur = q.Dequeue();

                // end early if we had a hit already in a previous step
                if (ret && cur_step != cur.step)
                {
                    break;
                }

                // checking 4 nodes around us
                myPoint p1 = new myPoint(cur.x * BLOCK_WIDTH, cur.y * BLOCK_HEIGHT);
                myPoint p2 = new myPoint((cur.x + 1) * BLOCK_WIDTH, cur.y * BLOCK_HEIGHT);
                myPoint p3 = new myPoint((cur.x + 1) * BLOCK_WIDTH, (cur.y + 1) * BLOCK_HEIGHT);
                myPoint p4 = new myPoint(cur.x * BLOCK_WIDTH, (cur.y + 1) * BLOCK_HEIGHT);
                segs[0].Update(p1, p2);
                segs[1].Update(p2, p3);
                segs[2].Update(p4, p3);
                segs[3].Update(p1, p4);

                for (int i = 0; i < 4; ++i)
                {
                    int nx = cur.x + dx[i];
                    int ny = cur.y + dy[i];

                    if (nx < 0 || nx > width || ny < 0 || ny >= height || vis[ny, nx])
                    {
                        continue;
                    }

                    double possible_t;
                    if (Geometry.DerpLineSegmentCast(d, v, segs[i], out possible_t))
                    {
                        // We have a hit! If the next zone is safe to move in, then continue the bfs
                        if (gameGrid[ny, nx] != '0')
                        {
                            q.Enqueue(new SimpleNode(nx, ny, cur.step + 1));
                            vis[ny, nx] = true;
                        }
                        // We hit an unnavigable space. Stop the BFS, this is as far as we go
                        else
                        {
                            ret = true;

                            if (Math.Abs(possible_t - t) < 1e-5 && col != null)
                            {
                                // break ties by taking the furthest behind the direction we wish to go
                                // Calculate the center point on the wall, and get the dot product of the vector to that point.
                                // The most negative value is the furthest behind
                                myPoint  segMidPoint1 = new myPoint((segs[i].p1.x + segs[i].p2.x) / 2.0, (segs[i].p1.y + segs[i].p2.y) / 2.0);
                                myVector toMidPoint1  = new myVector(segMidPoint1.x - d.x, segMidPoint1.y - d.y);

                                myPoint  segMidPoint2 = new myPoint((col.p1.x + col.p2.x) / 2.0, (col.p1.y + col.p2.y) / 2.0);
                                myVector toMidPoint2  = new myVector(segMidPoint2.x - d.x, segMidPoint2.y - d.y);

                                if (vUnit.dot(toMidPoint1) < vUnit.dot(toMidPoint2))
                                {
                                    t   = possible_t;
                                    col = new myLineSegment(segs[i].p1.x, segs[i].p1.y, segs[i].p2.x, segs[i].p2.y); // careful... memory bugs
                                }
                            }
                            else if (possible_t < t)
                            {
                                t   = possible_t;
                                col = new myLineSegment(segs[i].p1.x, segs[i].p1.y, segs[i].p2.x, segs[i].p2.y); // careful... memory bugs
                            }
                        }
                    }
                }

                // if we are a special diagonal case, then check the cross hit as well
                myLineSegment diag = null;

                char c = gameGrid[cur.y, cur.x];
                if (c == '1' || c == '3')
                {
                    diag = new myLineSegment(p2, p4);
                }

                if (c == '2' || c == '4')
                {
                    diag = new myLineSegment(p1, p3);
                }

                if (diag != null)
                {
                    double possible_t;
                    if (Geometry.DerpLineSegmentCast(d, v, diag, out possible_t))
                    {
                        ret = true;

                        if (Math.Abs(possible_t - t) < 1e-5 && col != null)
                        {
                            // break ties by taking the furthest behind the direction we wish to go
                            // Calculate the center point on the wall, and get the dot product of the vector to that point.
                            // The most negative value is the furthest behind
                            myPoint  segMidPoint1 = new myPoint((diag.p1.x + diag.p2.x) / 2.0, (diag.p1.y + diag.p2.y) / 2.0);
                            myVector toMidPoint1  = new myVector(segMidPoint1.x - d.x, segMidPoint1.y - d.y);

                            myPoint  segMidPoint2 = new myPoint((col.p1.x + col.p2.x) / 2.0, (col.p1.y + col.p2.y) / 2.0);
                            myVector toMidPoint2  = new myVector(segMidPoint2.x - d.x, segMidPoint2.y - d.y);

                            if (vUnit.dot(toMidPoint1) < vUnit.dot(toMidPoint2))
                            {
                                t   = possible_t;
                                col = new myLineSegment(diag.p1.x, diag.p1.y, diag.p2.x, diag.p2.y); // careful... memory bugs
                            }
                        }
                        else if (possible_t < t)
                        {
                            t   = possible_t;
                            col = new myLineSegment(diag.p1.x, diag.p1.y, diag.p2.x, diag.p2.y); // careful... memory bugs
                        }
                    }
                }

                cur_step = cur.step;
            }

            return(ret);
        }