Skip to main content
Adding version with stopping radius
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

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).

  • 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 toward the targetper invocation.

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

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

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

  • Moves the object at most a distance of maxStep toward the target.

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

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

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).

  • 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).

Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

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

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

This version...

  • Moves the object at most a distance of maxStep toward the target.

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

  • Uses no trigonometric functions, and no transcendentals at all when within one step of the target. 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.