// Update the segment's position and compute a smoothed velocity for the circle or the // endpoints of the segment based on the time it took it to move from the last position // to the current one. The velocity is in pixels per second. public void UpdateSegment(Segment s) { segLast = seg; seg = s; DateTime cur = DateTime.Now; double fMs = cur.Subtract(timeLastUpdated).TotalMilliseconds; if (fMs < 10.0) { fMs = 10.0; } double fFPS = 1000.0 / fMs; timeLastUpdated = cur; if (seg.IsCircle()) { xVel = xVel * smoothing + (1.0 - smoothing) * (seg.x1 - segLast.x1) * fFPS; yVel = yVel * smoothing + (1.0 - smoothing) * (seg.y1 - segLast.y1) * fFPS; } else { xVel = xVel * smoothing + (1.0 - smoothing) * (seg.x1 - segLast.x1) * fFPS; yVel = yVel * smoothing + (1.0 - smoothing) * (seg.y1 - segLast.y1) * fFPS; xVel2 = xVel2 * smoothing + (1.0 - smoothing) * (seg.x2 - segLast.x2) * fFPS; yVel2 = yVel2 * smoothing + (1.0 - smoothing) * (seg.y2 - segLast.y2) * fFPS; } }
// Using the velocity calculated above, estimate where the segment is right now. public Segment GetEstimatedSegment(DateTime cur) { Segment estimate = seg; double fMs = cur.Subtract(timeLastUpdated).TotalMilliseconds; estimate.x1 += fMs * xVel / 1000.0; estimate.y1 += fMs * yVel / 1000.0; if (seg.IsCircle()) { estimate.x2 = estimate.x1; estimate.y2 = estimate.y1; } else { estimate.x2 += fMs * xVel2 / 1000.0; estimate.y2 += fMs * yVel2 / 1000.0; } return(estimate); }
// Hit testing between this thing and a single segment. If hit, the center point on // the segment being hit is returned, along with the spot on the line from 0 to 1 if // a line segment was hit. public bool Hit(Segment seg, ref Point ptHitCenter, ref double lineHitLocation) { double minDxSquared = size + seg.radius; minDxSquared *= minDxSquared; // See if falling thing hit this body segment if (seg.IsCircle()) { if (SquaredDistance(center.X, center.Y, seg.x1, seg.y1) <= minDxSquared) { ptHitCenter.X = seg.x1; ptHitCenter.Y = seg.y1; lineHitLocation = 0; return true; } } else { double sqrLineSize = SquaredDistance(seg.x1, seg.y1, seg.x2, seg.y2); if (sqrLineSize < 0.5) // if less than 1/2 pixel apart, just check dx to an endpoint { return (SquaredDistance(center.X, center.Y, seg.x1, seg.y1) < minDxSquared) ? true : false; } else { // Find dx from center to line double u = ((center.X - seg.x1) * (seg.x2 - seg.x1) + (center.Y - seg.y1) * (seg.y2 - seg.y1)) / sqrLineSize; if ((u >= 0) && (u <= 1.0)) { // Tangent within line endpoints, see if we're close enough double xIntersect = seg.x1 + (seg.x2 - seg.x1) * u; double yIntersect = seg.y1 + (seg.y2 - seg.y1) * u; if (SquaredDistance(center.X, center.Y, xIntersect, yIntersect) < minDxSquared) { lineHitLocation = u; ptHitCenter.X = xIntersect; ptHitCenter.Y = yIntersect; ; return true; } } else { // See how close we are to an endpoint if (u < 0) { if (SquaredDistance(center.X, center.Y, seg.x1, seg.y1) < minDxSquared) { lineHitLocation = 0; ptHitCenter.X = seg.x1; ptHitCenter.Y = seg.y1; return true; } } else { if (SquaredDistance(center.X, center.Y, seg.x2, seg.y2) < minDxSquared) { lineHitLocation = 1; ptHitCenter.X = seg.x2; ptHitCenter.Y = seg.y2; return true; } } } } return false; } return false; }
// Update the segment's position and compute a smoothed velocity for the circle or the // endpoints of the segment based on the time it took it to move from the last position // to the current one. The velocity is in pixels per second. public void UpdateSegment(Segment s) { segLast = seg; seg = s; DateTime cur = DateTime.Now; double fMs = cur.Subtract(timeLastUpdated).TotalMilliseconds; if (fMs < 10.0) fMs = 10.0; double fFPS = 1000.0 / fMs; timeLastUpdated = cur; if (seg.IsCircle()) { xVel = xVel * smoothing + (1.0 - smoothing) * (seg.x1 - segLast.x1) * fFPS; yVel = yVel * smoothing + (1.0 - smoothing) * (seg.y1 - segLast.y1) * fFPS; } else { xVel = xVel * smoothing + (1.0 - smoothing) * (seg.x1 - segLast.x1) * fFPS; yVel = yVel * smoothing + (1.0 - smoothing) * (seg.y1 - segLast.y1) * fFPS; xVel2 = xVel2 * smoothing + (1.0 - smoothing) * (seg.x2 - segLast.x2) * fFPS; yVel2 = yVel2 * smoothing + (1.0 - smoothing) * (seg.y2 - segLast.y2) * fFPS; } }
public HitType LookForHits(Dictionary <Bone, BoneData> segments, int playerId) { DateTime cur = DateTime.Now; HitType allHits = HitType.None; // Zero out score if necessary if (!scores.ContainsKey(playerId)) { scores.Add(playerId, 0); } foreach (var pair in segments) { for (int i = 0; i < things.Count; i++) { HitType hit = HitType.None; Thing thing = things[i]; switch (thing.state) { case ThingState.Bouncing: case ThingState.Falling: { var ptHitCenter = new Point(0, 0); double lineHitLocation = 0; Segment seg = pair.Value.GetEstimatedSegment(cur); if (thing.Hit(seg, ref ptHitCenter, ref lineHitLocation)) { double fMs = 1000; if (thing.timeLastHit != DateTime.MinValue) { fMs = cur.Subtract(thing.timeLastHit).TotalMilliseconds; thing.avgTimeBetweenHits = thing.avgTimeBetweenHits * 0.8 + 0.2 * fMs; } thing.timeLastHit = cur; // Bounce off head and hands if (seg.IsCircle()) { // Bounce off of hand/head/foot thing.BounceOff(ptHitCenter.X, ptHitCenter.Y, seg.radius, pair.Value.xVel / targetFrameRate, pair.Value.yVel / targetFrameRate); if (fMs > 100.0) { hit |= HitType.Hand; } } else // Bonce off line segment { double xVel = pair.Value.xVel * (1.0 - lineHitLocation) + pair.Value.xVel2 * lineHitLocation; double yVel = pair.Value.yVel * (1.0 - lineHitLocation) + pair.Value.yVel2 * lineHitLocation; thing.BounceOff(ptHitCenter.X, ptHitCenter.Y, seg.radius, xVel / targetFrameRate, yVel / targetFrameRate); if (fMs > 100.0) { hit |= HitType.Arm; } } if (gameMode == GameMode.TwoPlayer) { if (thing.state == ThingState.Falling) { thing.state = ThingState.Bouncing; thing.touchedBy = playerId; thing.hotness = 1; thing.flashCount = 0; } else if (thing.state == ThingState.Bouncing) { if (thing.touchedBy != playerId) { if (seg.IsCircle()) { thing.touchedBy = playerId; thing.hotness = Math.Min(thing.hotness + 1, 4); } else { hit |= HitType.Popped; AddToScore(thing.touchedBy, 5 << (thing.hotness - 1), thing.center); } } } } else if (gameMode == GameMode.Solo) { if (seg.IsCircle()) { if (thing.state == ThingState.Falling) { thing.state = ThingState.Bouncing; thing.touchedBy = playerId; thing.hotness = 1; thing.flashCount = 0; } else if ((thing.state == ThingState.Bouncing) && (fMs > 100.0)) { hit |= HitType.Popped; AddToScore(thing.touchedBy, (pair.Key.joint1 == JointID.FootLeft || pair.Key.joint1 == JointID.FootRight) ? 10 : 5, thing.center); thing.touchedBy = playerId; } } } things[i] = thing; if (thing.avgTimeBetweenHits < 8) { hit |= HitType.Popped | HitType.Squeezed; if (gameMode != GameMode.Off) { AddToScore(playerId, 1, thing.center); } } } } break; } if ((hit & HitType.Popped) != 0) { thing.state = ThingState.Dissolving; thing.dissolve = 0; thing.xVelocity = thing.yVelocity = 0; thing.spinRate = thing.spinRate * 6 + 0.2; things[i] = thing; } allHits |= hit; } } return(allHits); }
// Hit testing between this thing and a single segment. If hit, the center point on // the segment being hit is returned, along with the spot on the line from 0 to 1 if // a line segment was hit. public bool Hit(Segment seg, ref Point ptHitCenter, ref double lineHitLocation) { double minDxSquared = size + seg.radius; minDxSquared *= minDxSquared; // See if falling thing hit this body segment if (seg.IsCircle()) { if (SquaredDistance(center.X, center.Y, seg.x1, seg.y1) <= minDxSquared) { ptHitCenter.X = seg.x1; ptHitCenter.Y = seg.y1; lineHitLocation = 0; return(true); } } else { double sqrLineSize = SquaredDistance(seg.x1, seg.y1, seg.x2, seg.y2); if (sqrLineSize < 0.5) // if less than 1/2 pixel apart, just check dx to an endpoint { return((SquaredDistance(center.X, center.Y, seg.x1, seg.y1) < minDxSquared) ? true : false); } else { // Find dx from center to line double u = ((center.X - seg.x1) * (seg.x2 - seg.x1) + (center.Y - seg.y1) * (seg.y2 - seg.y1)) / sqrLineSize; if ((u >= 0) && (u <= 1.0)) { // Tangent within line endpoints, see if we're close enough double xIntersect = seg.x1 + (seg.x2 - seg.x1) * u; double yIntersect = seg.y1 + (seg.y2 - seg.y1) * u; if (SquaredDistance(center.X, center.Y, xIntersect, yIntersect) < minDxSquared) { lineHitLocation = u; ptHitCenter.X = xIntersect; ptHitCenter.Y = yIntersect;; return(true); } } else { // See how close we are to an endpoint if (u < 0) { if (SquaredDistance(center.X, center.Y, seg.x1, seg.y1) < minDxSquared) { lineHitLocation = 0; ptHitCenter.X = seg.x1; ptHitCenter.Y = seg.y1; return(true); } } else { if (SquaredDistance(center.X, center.Y, seg.x2, seg.y2) < minDxSquared) { lineHitLocation = 1; ptHitCenter.X = seg.x2; ptHitCenter.Y = seg.y2; return(true); } } } } return(false); } return(false); }