0
\$\begingroup\$

To start, I'm not working with an engine and am looking for some help fixing the math behind the function I created.

Say we have anchor, obj, speed, dt, and terminationDist ; function anchorPull will theoretically pull obj towards anchor at a rate of speed pixels per second until the distance from anchor to obj is less than terminationDist. My implementation is as follows:

def anchorPull(anchor, obj, speed, dt, termDist = 10): if dist(anchor, obj) > termDist: deltaX1 = obj.x - anchor.x deltaY1 = obj.y - anchor.y theta = degrees(atan(deltaX1/deltaY1)) deltaX2 = sin(theta) * speed * dt deltaY2 = cos(theta) * speed * dt obj.x += deltaX2 obj.y += deltaY2 

Visual Representation: Visual Representation

The problem is, at low framerates (a high dt) obj wont go all the way to anchor: enter image description here

obj will also stochastically move around when anchor isn't stationary.

Any help would be great, thanks!

\$\endgroup\$
1
  • \$\begingroup\$ How about setting the position when stopped? The dt in the real world is infinitely small, and some situations cannot be simulated by the program. \$\endgroup\$ Commented Jun 11, 2022 at 7:51

1 Answer 1

0
\$\begingroup\$

It looks like you're trying to implement a MoveTowards function. Try something more like this:

def moveTowards(mover, target, maxStep): deltaX = target.x - mover.x deltaY = target.y - mover.y mag = deltaX * deltaX + deltaY * deltaY if mag < maxStep * maxStep: mover.x = target.x mover.y = target.y else: scale = maxStep / sqrt(mag) mover.x += deltaX * scale mover.y += deltaY * scale 

Or, to stop at a fixed distance away from the object, modify like so:

def moveTowardsOrbit(mover, target, maxStep, stopDistance): deltaX = target.x - mover.x deltaY = target.y - mover.y distance = sqrt(deltaX * deltaX + deltaY * deltaY) unitScale = 1 / distance deltaX *= unitScale deltaY *= unitScale onCircleX = target.x - deltaX * stopDistance onCircleY = target.y - deltaY * stopDistance fromStop = distance - stopDistance if abs(fromStop) <= maxStep: mover.x = onCircle.x mover.y = onCircle.y else: if fromStop < 0: deltaX *= -1 deltaY *= -1 mover.x += deltaX * maxStep mover.y += deltaY * maxStep 

Call this with moveTowards(obj, anchor, speed * dt, 10).

This version...

  • Picks a point on the circle stopDistance away from the anchor and moves toward that - whether that takes it inward or outward along the line joining obj and anchor.

  • Moves the object at most a distance of maxStep per invocation.

  • When the destination is closer than maxStep, it snaps the object directly to the stopDistance circle, with no under- or over-shooting.

  • Uses no trigonometric functions. It also handles all angles correctly, unlike the sample code (hint: you probably want atan2 when trying to find an angle from two coordinates).

You should also consider using a fixed timestep for your game simulation, so it's not subject to variation depending on the rendering framerate.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks, these work great! One small modification to the moveTowardsOrbit function: if abs(fromStop) <= speed: obj.x = onCircleX obj.y = onCircleY \$\endgroup\$ Commented Jun 11, 2022 at 14:50
  • \$\begingroup\$ No, that is not the correct change to make. \$\endgroup\$ Commented Jun 11, 2022 at 15:52

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.