//Calculates the maximum boundingbox size of a standard rectangular boundingbox internal static float CalcBoxSize(MFG.Vector3 offset, Texture2D image) { float xx = Math.Max(Math.Abs(offset.x), Math.Abs(image.width - offset.x)); float yy = Math.Max(Math.Abs(offset.y), Math.Abs(image.height - offset.y)); return((float)Math.Sqrt(xx * xx + yy * yy)); }
//Constructor calls base constructor, setting velocity to speed in rotation direction, and parented to Scene public Bullet(MFG.Vector3 position, float rotation, SpriteSet sprites, List <SceneObject> ignoreList, SceneObject ignoreParent) : base(position, DistDirToXY(speed, rotation), rotation + (float)Math.PI, sprites, Scene) { image = sprites.images[2]; //Sets the image out of the spriteset friction = 0; //No friction offset = new MFG.Vector3(-image.width / 2, -image.height / 2, 0); //Sets the offset for the bullet (Centered) scale = 1F; //Full scale maxBoxDimension = CalcBoxSize(offset, image); //Returns the maxiumum size of the box dimension (NOTE THAT THIS ONLY WORKS WITH DEFAULT BOXES) Box = GetDefaultBoundingBox(); //Sets the default rectangular bounding box specificIgnore.AddRange(ignoreList.FindAll(x => (x != Scene))); //Finds all non-Scene sceneObjects in the provided list, and adds them to the ignorelist specificIgnore.Add(ignoreParent); //Adds the creator (not parent) to the ignorelist }
//Checks if the provided lines intersect //Derived from https://blogs.sas.com/content/iml/2018/07/09/intersection-line-segments.html private static bool Intersects(VecLine a, VecLine b) { //Convert the lines to 4 points MFG.Vector3 p1 = a.p; MFG.Vector3 p2 = a.p + a.v; MFG.Vector3 q1 = b.p; MFG.Vector3 q2 = b.p + b.v; //Form a matrix from the vector differences between the points MFG.Matrix3 A = new MFG.Matrix3((p2 - p1).x, (p2 - p1).y, 0, (q1 - q2).x, (q1 - q2).y, 0, 0, 0, 1); //Form a vector from the differences between the start points MFG.Vector3 B = q1 - p1; //Then //A*t = b //t = A^-1 * b //Get the inverted matrix as required by the previous maths MFG.Matrix3 inverted = A.GetInverted(); if (inverted != null) //If it is invertible, they don't share a slope. The lines will intersect. { MFG.Vector3 solution = inverted * B; //Solve the equation return((solution.x >= 0 && solution.x <= 1) && (solution.y >= 0 && solution.y <= 1)); //If the solution falls in the unit square, valid collision, else not. } else //Otherwise, if they share a slope, { //Check for overlaps if (IsBetween(p1, p2, q1)) //Is q1 between p1 and p2? { return(true); //They collide! } if (IsBetween(p1, p2, q2)) //Is q2 between p1 and p2? { return(true); //They collide! } if (IsBetween(q1, q2, p1)) //Is p11 between q1 and q2? { return(true); //They collide! } return(false); //If there were no overlaps, they don't collide! } }
/* * Narrow phase collision detection considers each line of the bounding box of object A vs each line in the bounding box of object B. * If slopes match+not collinear, it escapes as false. * It then checks for collisions by representing each line as a parametric linear equation point+t*vector, then checks for where their (x,y) match. * If the lines collide such that both parametric variables are between 0 and 1, there is a collision between the line segments. */ private static bool Collides(BoundingBox a, BoundingBox b) { var origin = new MFG.Vector3(0, 0, 1); int aLen = a.vertices.Length; int bLen = b.vertices.Length; for (int i = 0; i < aLen; i++) //For each vertex comprising the bounding box of the first object { var lineA = new VecLine(a.vertices[i], a.vertices[(i + 1) % aLen]); //Create a line to the next vertex for (int j = 0; j < bLen; j++) //For each vertex comprising the bounding box of the first object { var lineB = new VecLine(b.vertices[j], b.vertices[(j + 1) % bLen]); //Create a line to the next vertex if (Intersects(lineA, lineB)) //Do the line segments intersect? { return(true); //Yes! So the boxes collide! } } } return(false); //No, none do, so the boxes don't collide. }
//Checks if c is collinearly contained within a and b //Derived from https://stackoverflow.com/a/328122 private static Boolean IsBetween(MFG.Vector3 a, MFG.Vector3 b, MFG.Vector3 c) { float crossProduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y); if (Math.Abs(crossProduct) > 0.000001F) { return(false); } float dotProduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y) * (b.y - a.y); if (dotProduct < 0) { return(false); } float squaredLengthBA = (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y); if (dotProduct > squaredLengthBA) { return(false); } return(true); }
//Converts a homogenous V3 to a V2 internal static Vector2 ConvertV3ToV2(MFG.Vector3 vec) => new Vector2(vec.x, vec.y);
internal VecLine(MFG.Vector3 startPoint, MFG.Vector3 endPoint) { p = startPoint; v = endPoint - startPoint; }