public HitboxArmorMarker(HitboxPolygon hitbox, Armor arg_armor, float displacement, float segment_separation) { // we need to construct the lines to represent our armor segments. // We have to project the armors angular system onto the hitbox. armor = arg_armor; nodes = new List<Vector2>[armor.segment_count]; int count = hitbox.count; Vector2[] corners = new Vector2[count]; Vector2[] displacements = new Vector2[count]; Vector2 last = hitbox.corners.Last(); for (int i = 0; i < count; i++) { Vector2 p = hitbox.corners[i]; Vector2 delta = last - p; delta.Normalize(); displacements[i] = Utility.RotateNeg(delta) * displacement / 2.0f; corners[i] = p; last = p; } for (int i = 0; i < count; i++) { int k = (i == count - 1) ? 0 : i + 1; corners[i] += displacements[i]; corners[i] += displacements[k]; } Vector2 p1 = corners[0]; int first_segment = armor.GetSegmentLocal(p1); int segment = first_segment; nodes[segment] = new List<Vector2>(); List<Vector2> popped = null; for (int j = 0; j < count; j++) { // iterate through all hitbox segments int i = j + 1; if (i == count) { i = 0; } Vector2 p2 = corners[i]; // if this line has crossed an armor intersection int new_segment = armor.GetSegmentLocal(p2); if (new_segment != segment) { // We find the midpoint of the the line where it croses the armor angle Vector2 cossin = Utility.CosSin(-armor.GetSegmentStartAngle(segment)); float p1ry = p1.X * cossin.Y + p1.Y * cossin.X; float p2ry = p2.X * cossin.Y + p2.Y * cossin.X; float alpha = p1ry / (p1ry - p2ry); Vector2 mid = ((p2 - p1) * alpha) + p1; if (new_segment == first_segment) { // this segment already has data in it. // we will add this back in later. popped = nodes[new_segment]; } // the new segment starts at the midpoint nodes[new_segment] = new List<Vector2>(); nodes[new_segment].Add(mid); nodes[new_segment].Add(p2); // the previous segment ends at the midpoint nodes[segment].Add(mid); segment = new_segment; } else { nodes[segment].Add(p2); } p1 = p2; } if (popped != null) { // We popped some of the data from the first segment, time to get it back foreach (Vector2 pt in popped) { nodes[first_segment].Add(pt); } } float sep = segment_separation / 2.0f; foreach (List<Vector2> node in nodes) { trim(node, 1, sep); trim(node, -1, sep); } }
Intersection IntersectPolygonHalf(HitboxPolygon hitbox) { Intersection best_sect = null; // checks each point in the hitbox for (int i = 0; i < count; i++) { // shift the point into global frame Vector2 point = pos + Utility.Rotate(corners[i], angle); // we then see to if any of the points lie inside this polygon Intersection sect = hitbox.Intersect(point); if (sect != null) { // the intersection with the biggest overlap is the most important to service if (best_sect == null || sect.overlap > best_sect.overlap) { // we average the surface normal and the corner normal // To provide a better approximation of the impact normal float corner_normal = corner_normals[i] + angle; float delta = Utility.AngleDelta(corner_normal + MathHelper.Pi, sect.surface_normal); sect.surface_normal = Utility.WrapAngle(sect.surface_normal + delta / 2.0f); //sect.surface_normal = Utility.Angle(hitbox.pos - pos); // COM approx. A backup solution. best_sect = sect; } } } return best_sect; }
// Returns the intersection of two HitboxPolygons public Intersection IntersectPolygon(HitboxPolygon hitbox) { //TODO: abstract the two point test loops out. Intersection best_sect = this.IntersectPolygonHalf(hitbox); Intersection next_sect = hitbox.IntersectPolygonHalf(this); if (next_sect != null) { next_sect.surface_normal = Utility.WrapAngle(next_sect.surface_normal + MathHelper.Pi); } else { return best_sect; } if (best_sect == null) { return next_sect; } return (best_sect.overlap > next_sect.overlap) ? best_sect : next_sect; }
public HitboxPolygon( HitboxPolygon clone ) { corners = clone.corners; count = clone.count; segment_normals = clone.segment_normals; corner_normals = clone.corner_normals; radius = clone.radius; radius_sq = clone.radius_sq; size = clone.size; }