public Path(float totalTime, Vector2 pos, Vector2 v, Vector2 a, Path prev) { this.totalTime = totalTime; this.pos = pos; this.v = v; this.a = a; this.prev = prev; this.time = totalTime - ((prev == null) ? 0 : prev.totalTime); }
public PointFunction(Geometry.Point p1, Geometry.Point p2, PointFunction old, float accel, float gravity) { Vector2 path = ((Vector2)p2-(Vector2)p1); Vector2 normalized = path; normalized.Normalize(); float g = gravity * path.Y / path.Length(); // r and l have been specifically framed this way, and affect several equations float r = g + accel; float l = -g + accel; float d = path.Length(); foreach(var pair in old.timings) { // is positive if it assists acceleration towards p2 (aka right) float b = FromKey(pair.Key); // collisions reduce speed Vector2 prevPath = (Vector2)p1 - pair.Value.posAt(0); if (prevPath != Vector2.Zero) { b *= Math.Abs(Vector2.Dot(path, prevPath)) / (path.Length() * prevPath.Length()); } Parabola fullSpeedPath = new Parabola(r, b, 0); Parabola fullRetreatPath = new Parabola(-l, b, 0); Paraboloid speedThenRetreat = fullSpeedPath.FollowedBy(fullRetreatPath); int lowerBound = ToKey(fullRetreatPath.SpeedAt(d, 0)); int upperBound = ToKey(fullSpeedPath.SpeedAt(d, 0)); for (int i = lowerBound; i <= upperBound; i++) { float f = FromKey(i); float newPartialTime = speedThenRetreat.SpecialShit(d, f, -1); if (newPartialTime >= 0) { float newT = newPartialTime + pair.Value.totalTime; if (!timings.ContainsKey(i) || timings[i].totalTime > newT) { float rT = (l * newPartialTime + f - b) / (l + r); float lT = newPartialTime - rT; timings[i] = new Path(newT-lT, p1, b * normalized, r * normalized, pair.Value); timings[i] = new Path(newT, timings[i].posAt(rT), timings[i].vAt(rT), -l * normalized, timings[i]); } } } } }
public PointFunction(float p) { timings[ToKey(p)] = new Path(0, Vector2.Zero, Vector2.Zero, Vector2.Zero, null); }
internal void Update() { mouseListener.Update(); var keystate = Keyboard.GetState(); if(keystate.IsKeyDown(Keys.Z) && !playback && isBound) // TODO: we can improve this to work even when unbound { var target = geometry.SnapToClosePoint(mouseListener.Transform(Mouse.GetState())); recording = PathFinding.PathTo(player2, target, geometry, ACCEL, GRAVITY); if (recording != null) { timeInRecording = 0; recordingPointer = new Particle(recording.absolutePosAt(0), Vector2.Zero, Vector2.Zero); playback = true; } } if (!playback) { if (!isBound) { var collision = geometry.FirstCollision(player); if (collision != null) { isBound = true; player2 = collision; } } if (isBound) { bool upsideDown = (((Vector2)player2.boundTo).X < 0) != player2.onCW; if (upsideDown) { isBound = false; player.position = player2.boundTo.p1 + Vector2.Multiply(player2.boundTo, (float)player2.g); player.velocity = Vector2.Multiply(player2.boundTo, (float)player2.gv) + player.gravity; player.position += player.velocity; player.velocity += player.gravity; } else { player2.g += player2.gv; player2.gv += player2.ga; if (keystate.IsKeyDown(Keys.A)) { player2.gv += ACCEL * ((player2.onCW) ? 1 : -1) / ((Vector2)player2.boundTo).Length(); } if (keystate.IsKeyDown(Keys.D)) { player2.gv -= ACCEL * ((player2.onCW) ? 1 : -1) / ((Vector2)player2.boundTo).Length(); } if (player2.g > 1 || player2.g < 0) { var exitingPoint = (player2.g < 0) ? player2.boundTo.p1 : player2.boundTo.p2; var nextList = geometry.LinesAttachedTo(exitingPoint).Where(l => l != player2.boundTo); nextList = nextList.Where(l => (((((Vector2)player2.boundTo).CrossProduct(l) < 0) != player2.onCW) != (player2.boundTo.p1 == exitingPoint)) != ((exitingPoint == l.p1) == (exitingPoint == player2.boundTo.p1))); if (nextList.Count() > 0) { var next = nextList.OrderBy(l => Math.Abs(((Vector2)player2.boundTo).CrossProduct(l)) / ((Vector2)l).Length()).Last(); var multiplier = Vector2.Dot(next, player2.boundTo) / (((Vector2)next).Length() * ((Vector2)player2.boundTo).Length()) * ((Vector2)player2.boundTo).Length() / ((Vector2)next).Length(); if ((exitingPoint == next.p1) == (exitingPoint == player2.boundTo.p1)) { player2.onCW = !player2.onCW; } player2.boundTo = next; player2.g = (next.p1 == exitingPoint) ? 0 : 1; player2.gv *= multiplier; player2.ga = Vector2.Dot(player.gravity, (Vector2)next) / (((Vector2)next).LengthSquared()); } else { isBound = false; player.position = player2.boundTo.p1 + Vector2.Multiply(player2.boundTo, (float)player2.g); player.velocity = Vector2.Multiply(player2.boundTo, (float)player2.gv); } } } } else { // order of this matters player.position += player.velocity; player.velocity += player.gravity; } } }